Python 对数据帧中的事务链求和,由列值链接的行
我试图从一个数据帧链接多个行,以便通过连接接收方ID和发送方ID获得所有可能的路径 以下是我的数据帧示例:Python 对数据帧中的事务链求和,由列值链接的行,python,pandas,Python,Pandas,我试图从一个数据帧链接多个行,以便通过连接接收方ID和发送方ID获得所有可能的路径 以下是我的数据帧示例: transaction_id sender_id receiver_id amount 0 213234 002 125 10 1 223322 017 354 90 2 343443 125 689 70 3
transaction_id sender_id receiver_id amount
0 213234 002 125 10
1 223322 017 354 90
2 343443 125 689 70
3 324433 689 233 5
4 328909 354 456 10
创建时使用:
df = pd.DataFrame(
{'transaction_id': {0: '213234', 1: '223322', 2: '343443', 3: '324433', 4: '328909'},
'sender_id': {0: '002', 1: '017', 2: '125', 3: '689', 4: '354'},
'receiver_id': {0: '125', 1: '354', 2: '689', 3: '233', 4: '456'},
'amount': {0: 10, 1: 90, 2: 70, 3: 5, 4: 10}}
)
我的代码的结果应该是链式ID列表和交易链的总金额。对于上面示例中的前两行,类似于:
[('002', '125', '689', '233'), 85]
[('017', '354', '456'), 100]
我已经尝试遍历这些行,并将每一行转换为节点
类的实例,然后使用方法遍历链表,但我不知道下一步是什么:
class Node:
def __init__(self,transaction_id,sender,receiver,amount):
self.transac = transaction_id
self.val = sender_id
self.next = receiver_id
self.amount = amount
def traverse(self):
node = self # start from the head node
while node != None:
print (node.val) # access the node value
node = node.next # move on to the next node
for index, row in customerTransactionSqlDf3.iterrows():
index = Node(
row["transaction_id"],
row["sender_id"],
row["receiver_id"],
row["amount"]
)
其他信息:
- 发件人id值是唯一的,对于每个发件人id,只有一个可能的交易链
- 没有循环,也不存在接收方id指向同一路径中的发送方id的链
- 您有一个有向图,其边由
id->id
连接构成。您正在尝试枚举此图中的所有路径。如果不使用链表,这实际上要容易得多
请注意,链表实现实际上并不链接节点;您的next
值必须引用其他节点
实例,而不是id
因为路径不能有循环,所以该图被称为非循环图。您的路径也非常简单,正如您所说的,每个发送者id都不会超过一个接收方id
在数据框中创建一个新视图,将发送者id作为索引,并将接收者id和金额列一起创建;这将使查找下一个路径元素变得非常容易。然后,您可以迭代这些列,遍历它们的路径,并对它们的数量求和,非常简单。以下代码使用已找到的路径,以避免再次遍历这些路径:
# receiver and amount rows, indexed by sender
edges = df[['sender_id', 'receiver_id', 'amount']].set_index('sender_id')
paths = {} # sender -> [sender, receiver, receiver, receiver, ...]
totals = {} # sender -> total amount
for sender, next_, amount in edges.itertuples():
path = paths[sender] = [sender, next_]
totals[sender] = amount
while True:
if next_ in paths:
# re-use already found path
path += paths[next_]
totals[sender] += totals[next_]
break
try:
next_, amount = edges.loc[next_]
except KeyError:
break # path complete
path.append(next_)
totals[sender] += amount
通过更新遇到的每个子路径,代码仍然可以变得更有效,因此,当您为发送者id125
处理第三行时,您已经处理了该路径,因为您必须为第一行从002
开始的路径遍历该路径:
for sender, next_, amount in edges.itertuples():
if sender in paths:
# already handled as part of a longer path
continue
paths[sender], totals[sender] = [sender, next_], amount
senders = [sender] # all sender ids along the path
while True:
if next_ in paths:
# re-use already found path
for sender in senders:
paths[sender] += paths[next_]
totals[sender] += totals[next_]
break
if next_ not in edges.index:
break # path complete
# start a new path from this sender id
paths[next_], totals[next_] = [next_], 0
senders.append(next_)
next_, amount = edges.loc[next_]
for sender in senders:
paths[sender].append(next_)
totals[sender] += amount
无论哪种方式,您现在都已计算出所有事务的完整路径和总数。您可以将这些列转换回其他列:
df['path'], df['total'] = df.sender_id.map(paths), df.sender_id.map(totals)
对于您的输入数据帧,它将生成:
交易\u id发送方\u id接收方\u id金额路径合计
0 213234 002 125 10 [002, 125, 689, 233] 85
1 223322 017 354 90 [017, 354, 456] 100
2 343443 125 689 70 [125, 689, 233] 75
3 324433 689 233 5 [689, 233] 5
4 328909 354 456 10 [354, 456] 10
或者,您可以通过在任一字典上循环,将路径与总计配对:
for id, path in paths.items():
print(id, path, totals[id])
对于您的具体示例,这同样会产生:
002['002',125',689',233']85
125 ['125', '689', '233'] 75
689 ['689', '233'] 5
017 ['017', '354', '456'] 100
354 ['354', '456'] 10
我不知道下一步是什么
通过使用当前实现,可以通过迭代每个节点来连接两个节点
对象。您还可以在节点
类中添加已访问
属性,以便在遍历树时识别唯一的链,即没有一条链是另一条链的子链。但是,如果您想知道每个发送者\u id
的链,这可能不是必需的
编辑:我注意到您提到的预期结果示例是前两行。这意味着每个sender\u id
都应该有自己的链。修改遍历
方法,以便在节点全部连接后使用
编辑:重新实现已访问的属性以获取唯一链
df=pd.DataFrame(
{'transaction_id':{0:'213234',1:'223322',2:'34343443',3:'324433',4:'328909'},
“发件人id:{0:'002',1:'017',2:'125',3:'689',4:'354'},
'接收者id':{0:'125',1:'354',2:'689',3:'233',4:'456'},
‘金额’:{0:10,1:90,2:70,3:5,4:10}
)
类节点:
定义初始(自身、交易id、发送方id、接收方id、金额):
self.transac=事务\u id
self.sender=sender\u id
self.receiver=receiver\u id
self.next=无
self.amount=金额
自我访问=错误
def遍历(自身,链=无,总计=0):
if(自访问):#撤消访问的节点
返回
自我访问=真实
如果链为无:#这是遍历的开始
链=[self.sender]
链+=[自我接收器]
合计+=自付金额
如果self.next不是None:
返回self.next.travel(链,总计)
返回链,总计
transc=[节点(
行[“事务处理id”],
行[“发送方id”],
行[“接收方id”],
行[“金额”]
)对于i,df.iterrows()中的行
#连接节点
对于枚举(transc)中的i、v:
对于枚举(transc)中的j,k:
#如果接收器v与来自j的发送器相同
如果v.receiver==k.sender:
v、 next=k
summary=[i.TRAVENSE()表示transc中的i]
summary=[如果i不是None,则i代表summary中的i]#删除None
打印(摘要)
输出:
[
(['002', '125', '689', '233'], 85),
(['017', '354', '456'], 100)
]
我认为它可以完成这项工作,但预期的结果应该是:[(['002',125',689',233',85),(['017',354',456',100),]
我不需要所有的事务链id,我只需要所有可能的链将我的解决方案用于获得唯一的链。这将是非常有帮助的,如果这被标记为答案,如果这解决了你的问题。太好了!这解决了我的问题