【发布时间】:2017-05-29 06:44:00
【问题描述】:
在给定分组和日期范围的情况下,我正在尝试找到一种有效的方法来在 pandas 中生成滚动计数或总和。最终,我希望能够添加条件,即。评估“类型”字段,但我还没有。我已经写了一些东西来完成这项工作,但我觉得可能有更直接的方法可以达到预期的结果。
我的 pandas 数据框目前看起来像这样,所需的输出放在最后一列“rolling_sales_180”中。
name date amount rolling_sales_180
0 David 2015-01-01 100 100.0
1 David 2015-01-05 500 600.0
2 David 2015-05-30 50 650.0
3 David 2015-07-25 50 100.0
4 Ryan 2014-01-04 100 100.0
5 Ryan 2015-01-19 500 500.0
6 Ryan 2016-03-31 50 50.0
7 Joe 2015-07-01 100 100.0
8 Joe 2015-09-09 500 600.0
9 Joe 2015-10-15 50 650.0
我目前的解决方案和环境可以从下面获得。我一直在从这个 R Q&A 在 stackoverflow 中对我的解决方案进行建模。 Efficient way to perform running total in the last 365 day window
import pandas as pd
import numpy as np
def trans_date_to_dist_matrix(date_col): # used to create a distance matrix
x = date_col.tolist()
y = date_col.tolist()
data = []
for i in x:
tmp = []
for j in y:
tmp.append(abs((i - j).days))
data.append(tmp)
del tmp
return pd.DataFrame(data=data, index=date_col.values, columns=date_col.values)
def lower_tri(x_col, date_col, win): # x_col = column user wants a rolling sum of ,date_col = dates, win = time window
dm = trans_date_to_dist_matrix(date_col=date_col) # dm = distance matrix
dm = dm.where(dm <= win) # find all elements of the distance matrix that are less than window(time)
lt = dm.where(np.tril(np.ones(dm.shape)).astype(np.bool)) # lt = lower tri of distance matrix so we get only future dates
lt[lt >= 0.0] = 1.0 # cleans up our lower tri so that we can sum events that happen on the day we are evaluating
lt = lt.fillna(0) # replaces NaN with 0's for multiplication
return pd.DataFrame(x_col.values * lt.values).sum(axis=1).tolist()
def flatten(x):
try:
n = [v for sl in x for v in sl]
return [v for sl in n for v in sl]
except:
return [v for sl in x for v in sl]
data = [
['David', '1/1/2015', 100], ['David', '1/5/2015', 500], ['David', '5/30/2015', 50], ['David', '7/25/2015', 50],
['Ryan', '1/4/2014', 100], ['Ryan', '1/19/2015', 500], ['Ryan', '3/31/2016', 50],
['Joe', '7/1/2015', 100], ['Joe', '9/9/2015', 500], ['Joe', '10/15/2015', 50]
]
list_of_vals = []
dates_df = pd.DataFrame(data=data, columns=['name', 'date', 'amount'], index=None)
dates_df['date'] = pd.to_datetime(dates_df['date'])
list_of_vals.append(dates_df.groupby('name', as_index=False).apply(
lambda x: lower_tri(x_col=x.amount, date_col=x.date, win=180)))
new_data = flatten(list_of_vals)
dates_df['rolling_sales_180'] = new_data
print dates_df
感谢您的时间和反馈。
【问题讨论】:
-
您确定“rolling_sales_180”的示例输出正确吗?该列应该是 180 的滚动总和,对吧? Ryan 的所有日期都相隔一年多,但仍在求和?乔的所有日期都在 180 天内,并且没有被相加?您是否以某种方式切换了两者?
-
@root - 我可能转错了 - 抱歉。
-
不用担心,只要确保我对问题的理解是正确的。
-
@JohnE - 我做过一些与 groupby 和 rolling 相关的研究,但一切似乎都与偶数序列的时间序列数据有关。我没有看到类似下面建议的解决方案。
-
Ryan 的 Rollins_sales_180 值应该是 100、500 和 50。