我有一个包含两列的数据框 - date和id。我想为每个日期计算该日期的id的数量,该日期在7天之后的某个日期重新出现。如果我在postgres中这样做,它看起来像是:
SELECT df1.date, COUNT(DISTINCT df1.id)
FROM df df1 INNER JOIN df df2
ON df1.id = df2.id AND
df2.date BETWEEN df1.date + 1 AND df1.date + 7
GROUP BY df1.date;
对我来说有什么问题是如何以快速和惯用等方式将此语句翻译成大熊猫。
我已经尝试过一天保留,只需创建一个滞后列并将原始数据与滞后数据帧合并。这当然有效。但是,为了保留七天,我需要创建7个数据帧并将它们合并在一起。就我而言,那是不合理的。 (特别是因为我也想知道30天的数字。)
(我还应该指出,我的研究导致我https://github.com/pydata/pandas/issues/2996,这表明我的安装(pandas 0.14.0)上的无效的合并行为因错误而失败消息TypeError: Argument 'values' has incorrect type (expected numpy.ndarray, got Series)
。所以似乎有某种高级合并/加入行为,我显然不知道如何激活。)
答案 0 :(得分:1)
如果我理解正确,我认为你可以用groupby/apply
来做。这有点棘手。所以我认为你有以下数据:
>>> df
date id y
0 2012-01-01 1 0.1
1 2012-01-03 1 0.3
2 2012-01-09 1 0.4
3 2012-01-12 1 0.0
4 2012-01-14 1 0.2
5 2012-01-16 1 0.4
6 2012-01-01 2 0.2
7 2012-01-02 2 0.1
8 2012-01-03 2 0.4
9 2012-01-04 2 0.6
10 2012-01-09 2 0.7
11 2012-01-10 2 0.4
我要在一个' id'内创建滚动前进计数。 ID包括当天在后7天内显示的次数组:
def count_forward7(g):
# Add column to the datframe so I can set date as the index
g['foo'] = 1
# New dataframe with daily frequency, so 7 rows = 7 days
# If there are no gaps in the dates you don't need to do this
x = g.set_index('date').resample('D')
# Do Andy Hayden Method for a forward looking rolling windows
# reverses the series and then reverses back the answer
fsum = pd.rolling_sum(x[::-1],window=7,min_periods=0)[::-1]
return pd.DataFrame(fsum[fsum.index.isin(g.date)].values,index=g.index)
>>> df['f7'] = df.groupby('id')[['date']].apply(count_forward7)
>>> df
date id y f7
0 2012-01-01 1 0.1 2
1 2012-01-03 1 0.3 2
2 2012-01-09 1 0.4 3
3 2012-01-12 1 0.0 3
4 2012-01-14 1 0.2 2
5 2012-01-16 1 0.4 1
6 2012-01-01 2 0.2 4
7 2012-01-02 2 0.1 3
8 2012-01-03 2 0.4 3
9 2012-01-04 2 0.6 3
10 2012-01-09 2 0.7 2
11 2012-01-10 2 0.4 1
现在,如果您现在想要计算每个日期,该日期的ID数量会在7天后的某个日期重新出现"只计算每个日期,其中f7> 1:
>>> df['bool_f77'] = df['f7'] > 1
>>> df.groupby('date')['bool_f77'].sum()
2012-01-01 2
2012-01-02 1
2012-01-03 2
2012-01-04 1
2012-01-09 2
2012-01-10 0
2012-01-12 1
2012-01-14 1
2012-01-16 0
或类似以下内容:
>>> df.query('f7 > 1').groupby('date')['date'].count()
date
2012-01-01 2
2012-01-02 1
2012-01-03 2
2012-01-04 1
2012-01-09 2
2012-01-12 1
2012-01-14 1