
本教程旨在解决如何在pandas dataframe中为每笔交易查找并记录同一客户之前一笔不同类型交易的金额。文章将详细介绍一种优化的迭代分组方法,避免了传统`apply`函数带来的性能瓶颈,并提供了清晰的python代码示例,帮助读者高效处理此类复杂的时序数据分析任务,确保结果的准确性和代码的健壮性。
在处理客户交易数据时,我们经常需要分析客户行为序列。一个常见的需求是,对于每一笔交易,我们希望知道该客户之前最近一次不同类型的交易金额是多少。例如,如果客户购买了“工具”类商品,我们可能想知道他之前最近一次购买“电机”类商品的金额。
假设我们有一个名为df的Pandas DataFrame,包含以下列:
我们的目标是添加一个新列PREV_AMOUNT,其中包含每个交易对应客户的上一笔不同类型交易的金额。如果不存在这样的交易,则应为NaN。
直接使用DataFrame的apply方法结合自定义函数来查找历史记录,在数据量较大时会面临严重的性能问题,甚至可能导致内核崩溃,因为它涉及到对DataFrame的重复子集查询。而简单的shift()操作只能获取同一分组内的上一条记录,无法满足“不同类型”的条件。因此,我们需要一种更高效、更具扩展性的解决方案。
为了高效地解决这个问题,我们将采用一种结合了Pandas分组操作和Python迭代逻辑的方法。核心思想是:
为了更好地说明,我们使用以下示例数据:
| KEY_ID | TYPE | AMOUNT | DATE |
|---|---|---|---|
| 1 | Motor | 5000 | 2020-01-01 |
| 1 | Tool | 3000 | 2020-02-01 |
| 1 | Tool | 7000 | 2020-03-01 |
| 2 | Tool | 2000 | 2020-01-15 |
| 2 | Motor | 6000 | 2020-02-15 |
| 2 | Tool | 4000 | 2020-03-15 |
首先,确保导入必要的库并准备数据。
import pandas as pd
import numpy as np
# 示例数据
data = {
'KEY_ID': [1, 1, 1, 2, 2, 2],
'TYPE': ['Motor', 'Tool', 'Tool', 'Tool', 'Motor', 'Tool'],
'AMOUNT': [5000, 3000, 7000, 2000, 6000, 4000],
'DATE': pd.to_datetime(['2020-01-01', '2020-02-01', '2020-03-01', '2020-01-15', '2020-02-15', '2020-03-15'])
}
df = pd.DataFrame(data)
# 步骤1: 预排序DataFrame
# 这一步至关重要,确保在处理每个客户的交易时,是按时间顺序进行的。
df = df.sort_values(by=['KEY_ID', 'DATE']).reset_index(drop=True)
# 初始化PREV_AMOUNT列
df['PREV_AMOUNT'] = np.nan接下来,实现分组迭代逻辑:
# 步骤2 & 3 & 4: 按客户分组并迭代处理
grouped = df.groupby(['KEY_ID'])
for key_id, group in grouped:
last_motor_amount = np.nan # 记录该客户最近一次Motor交易金额
last_tool_amount = np.nan # 记录该客户最近一次Tool交易金额
# 在每个客户组内,再次按日期排序(虽然整体已排序,但确保分组迭代的顺序)
# 使用iterrows()迭代,同时获取索引和行数据
for ind, row in group.iterrows():
current_type = row['TYPE']
current_amount = row['AMOUNT']
if current_type == 'Motor':
# 如果当前交易是Motor类型,则查找之前最近的Tool交易金额
df.loc[ind, 'PREV_AMOUNT'] = last_tool_amount
# 更新最近一次Motor交易金额
last_motor_amount = current_amount
elif current_type == 'Tool':
# 如果当前交易是Tool类型,则查找之前最近的Motor交易金额
df.loc[ind, 'PREV_AMOUNT'] = last_motor_amount
# 更新最近一次Tool交易金额
last_tool_amount = current_amount
# 如果有其他交易类型,可以扩展此处的elif分支
print(df)运行上述代码后,df将包含PREV_AMOUNT列,结果如下:
| KEY_ID | TYPE | AMOUNT | DATE | PREV_AMOUNT |
|---|---|---|---|---|
| 1 | Motor | 5000 | 2020-01-01 | NaN |
| 1 | Tool | 3000 | 2020-02-01 | 5000.0 |
| 1 | Tool | 7000 | 2020-03-01 | 5000.0 |
| 2 | Tool | 2000 | 2020-01-15 | NaN |
| 2 | Motor | 6000 | 2020-02-15 | 2000.0 |
| 2 | Tool | 4000 | 2020-03-15 | 6000.0 |
# 扩展到多种交易类型
# last_amounts = {type_name: np.nan for type_name in df['TYPE'].unique()}
# ...
# if current_type in last_amounts:
# other_types = [t for t in last_amounts if t != current_type]
# # 简单地取第一个其他类型作为PREV_AMOUNT,或者根据业务逻辑选择
# df.loc[ind, 'PREV_AMOUNT'] = last_amounts[other_types[0]] if other_types else np.nan
# last_amounts[current_type] = current_amount然而,如果“不同类型”指的是任何其他类型,且只需最近的一笔,那么上述双变量方法可以推广为维护一个last_any_other_type_amount变量,但这样就无法区分是哪种“其他”类型了。本教程的原始需求是针对特定两种类型互查,所以双变量是合适的。
本教程提供了一种在Pandas DataFrame中计算每个交易的上一笔不同类型交易金额的有效方法。通过结合DataFrame的分组功能和Python的迭代逻辑,我们能够高效地处理复杂的时序依赖关系,同时避免了性能瓶颈。这种方法不仅适用于本例中的两种交易类型场景,稍加修改也可扩展到更复杂的业务需求。理解这种分组迭代模式对于处理各类时序和分组相关的数据分析任务具有重要意义。
以上就是高效计算DataFrame中不同类型前一笔交易金额的教程的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号