【发布时间】:2020-06-07 15:40:27
【问题描述】:
我有一个代表帐户持有人之间交换组的数据框。数据显示了交互的帐户和交换的项目。有时有明确的匹配,但有时交换的物品总数匹配,但您无法准确判断个人之间交换的金额。
想要的输入输出如下:
id group rx tx
0 A x 50 0
1 B x 0 50
2 A y 210 0
3 B y 0 50
4 C y 0 350
5 D y 190 0
group exchanges
0 x [(B, A, 50)]
1 y [(unk, A, 210), (B, unk, 50), (C, unk, 350), (unk, D, 190)]
目前我正在像这样使用“groupby”和“apply”:
def sort_out(x):
# create the row to be returned
y = pd.Series(index=['group','exchanges'])
y['group'] = x.group.iloc[0]
y['exchanges'] = []
# Find all rx and make tuples list
# determine source and destinations
sink = [tuple(i) for i in x.loc[x['rx'] != 0][[
'id', 'rx'
]].to_records(index=True)]
source = [tuple(i) for i in x.loc[x['tx'] != 0][[
'id', 'tx'
]].to_records(index=True)]
# find match
match = []
for item in source:
match = [o for o in sink if o[2] == item[2]]
if len(match):
y['exchanges'].append((item[1], match[0][1], match[0][2]))
sink.remove(match[0])
continue
# handle the unmatched elements
tx_el = x.loc[~x['tx'].isin(x['rx'])][[
'id', 'tx']].to_records(index=True)
rx_el = x.loc[~x['rx'].isin(x['tx'])][[
'id', 'rx']].to_records(index=True)
[y['exchanges'].append((item[1], 'unk', item[2])) for item in tx_el]
[y['exchanges'].append(('unk', item[1], item[2])) for item in rx_el]
return y
b = a.groupby('group').apply(lambda x: sort_out(x))
这种方法在大约 2000 万行上最多需要 7 个小时。我认为最大的障碍是'groupby'-'apply'。我最近被介绍给“爆炸”。从那里我看着“融化”,但它似乎不是我想要的。有什么改进建议吗?
[另一个尝试]
根据 YOBEN_S 的建议,我尝试了以下方法。部分挑战是匹配,部分是跟踪哪些正在发送(tx)和哪些正在接收(rx)。所以我通过显式添加标签来作弊,即方向['dir']。我也使用嵌套三元,但我不确定这是否非常高效:
a['dir'] = a.apply(lambda x: 't' if x['tx'] !=0 else 'r', axis=1)
a[['rx','tx']]=np.sort(a[['rx','tx']].values,axis=1)
out = a.drop(['group','rx'],1).apply(tuple,1).groupby([a['group'],a.tx]).agg('sum') \
.apply(lambda x: (x[3],x[0],x[1]) if len(x)==6 else
((x[0],'unk',x[1]) if x[2]=='t' else ('unk',x[0],x[1]))
).groupby(level=0).agg(list)
【问题讨论】:
标签: python-3.x pandas dataframe