解决这个问题的一种方法是,
df['series'] = df[['withdraw','deposit']].ne(0).sum(axis=1)
m = df['series']>=1
正如@Chris A所评论的那样,
m = df[['withdraw','deposit']].gt(0).any(axis=1) #replacement for above snippet,
df['num_months_since_last_txn'] = df.groupby(m.cumsum()).cumcount()
df.loc[df['num_months_since_last_txn']==0,'num_months_since_last_txn']=(df['num_months_since_last_txn']+1).shift(1).fillna(0)
print df
输出:
txn_year txn_month custid withdraw deposit
0 2011 4 123 0.0 100.0
1 2011 5 123 0.0 0.0
2 2011 6 123 0.0 0.0
3 2011 7 123 50.1 0.0
4 2011 8 123 0.0 0.0
txn_year txn_month custid withdraw deposit num_months_since_last_txn
0 2011 4 123 0.0 100.0 0.0
1 2011 5 123 0.0 0.0 1.0
2 2011 6 123 0.0 0.0 2.0
3 2011 7 123 50.1 0.0 3.0
4 2011 8 123 0.0 0.0 1.0
解释:
- 使用
ne
来获取是否发生了交易,并使用求和得到二进制值。
- 当交易为 1 时,使用
groupby
、cumsum
和 cumcount
创建从 0,1,2...n 的系列。
- 使用
.loc
对值为 0
进行重新排序。
注意:我可能增加了更多复杂性来解决这个问题。但是它会给你解决这个问题的思路和方法。
考虑客户 ID 的解决方案:
df=df.sort_values(by=['custid','txn_month'])
mask=~df.duplicated(subset=['custid'],keep='first')
m = df[['withdraw','deposit']].gt(0).any(axis=1)
df['num_months_since_last_txn'] = df.groupby(m.cumsum()).cumcount()
df.loc[df['num_months_since_last_txn']==0,'num_months_since_last_txn']=(df['num_months_since_last_txn']+1).shift(1)
df.loc[mask,'num_months_since_last_txn']=0
样例输入:
txn_year txn_month custid withdraw deposit
0 2011 4 123 0.0 100.0
1 2011 5 123 0.0 0.0
2 2011 4 1245 0.0 100.0
3 2011 5 1245 0.0 0.0
4 2011 6 123 0.0 0.0
5 2011 7 1245 50.1 0.0
6 2011 7 123 50.1 0.0
7 2011 8 123 0.0 0.0
8 2011 6 1245 0.0 0.0
9 2011 8 1245 0.0 0.0
示例输出:
txn_year txn_month custid withdraw deposit num_months_since_last_txn
0 2011 4 123 0.0 100.0 0.0
1 2011 5 123 0.0 0.0 1.0
4 2011 6 123 0.0 0.0 2.0
6 2011 7 123 50.1 0.0 3.0
7 2011 8 123 0.0 0.0 1.0
2 2011 4 1245 0.0 100.0 0.0
3 2011 5 1245 0.0 0.0 1.0
8 2011 6 1245 0.0 0.0 2.0
5 2011 7 1245 50.1 0.0 3.0
9 2011 8 1245 0.0 0.0 1.0
考虑客户ID的解释:
- 以上代码基于[1,1]之间的时间间隔而运作。为了使格式保持一致,请按照cust_id和txn_month对df进行排序,并在未来加入txn_year。
- fillna(0)在这里不起作用,因为shift不会为下一个客户创建NaN。要将其重置为0,找到客户ID的重复项并将第一个值替换为0。
df ['series']
将是2
,因此不会被您的布尔掩码m
的逻辑所捕获。您可以潜在地通过以下方式压缩第1行和第2行:m = df [['withdraw','deposit']]。gt(0).any(axis = 1)
。 - Chris Adamscustid
分组? - oikonomiyaki