Python 创建查找并返回匹配数据的列
我有一个大数据框150000 x 25的金融交易。此数据框表示金融控股账户的一种类型,因此交易通常通过此分类账进行。例如,下面位置0中的行显示一笔-123.21美元的交易。位置2中的行是+$123.21的对应或耦合事务,与类别、类型和源匹配 我的目标是创建一个新列来标识耦合事务的键。因此,第0行的耦合键是第2行的键,反之亦然 请注意,位置9-14中的行排除了搜索最小值和最大值的解决方案,这些解决方案沿着这些线匹配一个很好的答案。位置9的行显示+10美元的交易。它与位置11中的第一笔-10美元相结合,而不是位置14中的交易。通过这种方式,每个事务与零个或一个其他事务耦合,但不超过一个Python 创建查找并返回匹配数据的列,python,pandas,dataframe,Python,Pandas,Dataframe,我有一个大数据框150000 x 25的金融交易。此数据框表示金融控股账户的一种类型,因此交易通常通过此分类账进行。例如,下面位置0中的行显示一笔-123.21美元的交易。位置2中的行是+$123.21的对应或耦合事务,与类别、类型和源匹配 我的目标是创建一个新列来标识耦合事务的键。因此,第0行的耦合键是第2行的键,反之亦然 请注意,位置9-14中的行排除了搜索最小值和最大值的解决方案,这些解决方案沿着这些线匹配一个很好的答案。位置9的行显示+10美元的交易。它与位置11中的第一笔-10美元相结
import pandas as pd
d_in = {'key' : ['80000001', '80000002', '80000003', '80000004', '80000005', '80000006', '80000007', '80000008', '80000009', '80000010', '80000011', '80000012', '80000013', '80000014', '80000015'],
'date' : ['20200901', '20200901', '20200902', '20200902', '20200902','20200903', '20200904', '20200905', '20200905', '20200906', '20200906', '20200906', '20200906', '20200906', '20200906'],
'category' : ['Z293', 'B993', 'Z293', 'B993', 'W884', 'C123', 'V332', 'C123', 'V332', 'Z213', 'Z213', 'Z213', 'Z213', 'Z213', 'Z213'],
'type' : ['tools', 'supplies', 'tools', 'supplies', 'repairs', 'custom', 'misc', 'custom', 'misc', 'technology', 'technology', 'technology', 'technology', 'technology', 'technology'],
'source' : ['Q112', 'E443', 'Q112', 'E443', 'P443', 'B334', 'E449', 'B334', 'E449', 'QQ32', 'QQ32', 'QQ32', 'QQ32', 'QQ32', 'QQ32'],
'amount' : [-123.21, 3.12, 123.21, -3.12, 9312.00, 312.23, -13.23, -312.23, 13.23, 10, 10, -10, -10, 10, -10]}
df_in = pd.DataFrame(data=d_in)
d_out = {'key' : ['80000001', '80000002', '80000003', '80000004', '80000005', '80000006', '80000007', '80000008', '80000009', '80000010', '80000011', '80000012', '80000013', '80000014', '80000015'],
'date' : ['20200901', '20200901', '20200902', '20200902', '20200902','20200903', '20200904', '20200905', '20200905', '20200906', '20200906', '20200906', '20200906', '20200906', '20200906'],
'category' : ['Z293', 'B993', 'Z293', 'B993', 'W884', 'C123', 'V332', 'C123', 'V332', 'Z213', 'Z213', 'Z213', 'Z213', 'Z213', 'Z213'],
'type' : ['tools', 'supplies', 'tools', 'supplies', 'repairs', 'custom', 'misc', 'custom', 'misc', 'technology', 'technology', 'technology', 'technology', 'technology', 'technology'],
'source' : ['Q112', 'E443', 'Q112', 'E443', 'P443', 'B334', 'E449', 'B334', 'E449', 'QQ32', 'QQ32', 'QQ32', 'QQ32', 'QQ32', 'QQ32'],
'amount' : [-123.21, 3.12, 123.21, -3.12, 9312.00, 312.23, -13.23, -312.23, 13.23, 10, 10, -10, -10, 10, -10],
'coupling_key' : ['80000003', '80000004', '80000001', '80000002', 'none', '80000008', '80000009', '80000006', '80000007', '80000012', '80000013', '80000010', '80000011', '80000015', '80000014']}
df_out = pd.DataFrame(data=d_out)
我所探索的大多数解决方案都涉及到按功能分组。我目前正在考虑groupby…n。。。作用我怀疑解决方案可能还涉及.mask或.duplicated。您可以执行以下操作: 步骤1:设置变换功能:
def coupling(ser):
keys = ser.index
values = ser.values
couples = [None] * len(ser)
free = {*range(len(ser))}
while free:
i = min(free)
j = i + 1
while j < len(ser):
if (values[j] == -values[i]
and j in free):
couples[i], couples[j] = keys[j], keys[i]
free.remove(j)
break
j += 1
free.remove(i)
return couples
结果:
key date category type source amount coupling_key
0 80000001 20200901 Z293 tools Q112 -123.21 80000003
1 80000002 20200901 B993 supplies E443 3.12 80000004
2 80000003 20200902 Z293 tools Q112 123.21 80000001
3 80000004 20200902 B993 supplies E443 -3.12 80000002
4 80000005 20200902 W884 repairs P443 9312.00 None
5 80000006 20200903 C123 custom B334 312.23 80000008
6 80000007 20200904 V332 misc E449 -13.23 80000009
7 80000008 20200905 C123 custom B334 -312.23 80000006
8 80000009 20200905 V332 misc E449 13.23 80000007
9 80000010 20200906 Z213 technology QQ32 10.00 80000012
10 80000011 20200906 Z213 technology QQ32 10.00 80000013
11 80000012 20200906 Z213 technology QQ32 -10.00 80000010
12 80000013 20200906 Z213 technology QQ32 -10.00 80000011
13 80000014 20200906 Z213 technology QQ32 10.00 80000015
14 80000015 20200906 Z213 technology QQ32 -10.00 80000014
我假设日期列的顺序与示例中相同。您可以执行以下操作: 步骤1:设置变换功能:
def coupling(ser):
keys = ser.index
values = ser.values
couples = [None] * len(ser)
free = {*range(len(ser))}
while free:
i = min(free)
j = i + 1
while j < len(ser):
if (values[j] == -values[i]
and j in free):
couples[i], couples[j] = keys[j], keys[i]
free.remove(j)
break
j += 1
free.remove(i)
return couples
结果:
key date category type source amount coupling_key
0 80000001 20200901 Z293 tools Q112 -123.21 80000003
1 80000002 20200901 B993 supplies E443 3.12 80000004
2 80000003 20200902 Z293 tools Q112 123.21 80000001
3 80000004 20200902 B993 supplies E443 -3.12 80000002
4 80000005 20200902 W884 repairs P443 9312.00 None
5 80000006 20200903 C123 custom B334 312.23 80000008
6 80000007 20200904 V332 misc E449 -13.23 80000009
7 80000008 20200905 C123 custom B334 -312.23 80000006
8 80000009 20200905 V332 misc E449 13.23 80000007
9 80000010 20200906 Z213 technology QQ32 10.00 80000012
10 80000011 20200906 Z213 technology QQ32 10.00 80000013
11 80000012 20200906 Z213 technology QQ32 -10.00 80000010
12 80000013 20200906 Z213 technology QQ32 -10.00 80000011
13 80000014 20200906 Z213 technology QQ32 10.00 80000015
14 80000015 20200906 Z213 technology QQ32 -10.00 80000014
我假设日期列的顺序与示例中的相同。另一种解决方案,尝试使用“纯熊猫”函数,不管这意味着什么 要理解以下内容,请执行以下步骤 我们按“类别”、“类型”、“来源”和“金额”进行分组 在每一组中,我们将有相同abs数量但符号不同的行。然后我们按“数量”分组,在正数范围内标记行,从1到n,在负数范围内标记行,从1到n,从而得到累积数 …通过匹配第一个元素的正片与第一个元素的负片、第二个元素的正片与第二个元素的负片等进行分组 组_match将有一个在步骤3中匹配的['key1','key2']列表 剩下的只是把这些列表放在一起,我们还希望每个['key1','key2']都有['key2','key1'],因此这一行颠倒了。。在其中,转换为数据帧,并连接到原始数据帧 第5步可能会做得更优雅,但这是可行的
match = []
for _, df2 in df_in.groupby([df_in['category'], df_in['type'], df_in['source'], df_in['amount'].abs()], as_index=False):
group_match = df2.groupby(df2.groupby(['amount']).cumcount())['key'].apply(list)
match.extend(group_match)
match.extend([list(reversed(m)) for m in group_match])
match_df = pd.DataFrame(data = match, columns = ['key', 'coupling_key']).drop_duplicates()
df_out = df_in.merge(match_df, on='key')
生成所需的df_输出:
key date category type source amount coupling_key
0 80000001 20200901 Z293 tools Q112 -123.21 80000003
1 80000002 20200901 B993 supplies E443 3.12 80000004
2 80000003 20200902 Z293 tools Q112 123.21 80000001
3 80000004 20200902 B993 supplies E443 -3.12 80000002
4 80000005 20200902 W884 repairs P443 9312.00 None
5 80000006 20200903 C123 custom B334 312.23 80000008
6 80000007 20200904 V332 misc E449 -13.23 80000009
7 80000008 20200905 C123 custom B334 -312.23 80000006
8 80000009 20200905 V332 misc E449 13.23 80000007
9 80000010 20200906 Z213 technology QQ32 10.00 80000012
10 80000011 20200906 Z213 technology QQ32 10.00 80000013
11 80000012 20200906 Z213 technology QQ32 -10.00 80000010
12 80000013 20200906 Z213 technology QQ32 -10.00 80000011
13 80000014 20200906 Z213 technology QQ32 10.00 80000015
14 80000015 20200906 Z213 technology QQ32 -10.00 80000014
如果amount列中有零,并且它们应该根据下面的注释进行匹配,那么我们可以如下修改循环
for _, df2 in df_in.groupby([df_in['category'], df_in['type'], df_in['source'], df_in['amount'].abs()], as_index=False):
if (df2['amount'].iloc[0] == 0):
group_match = df2.groupby([i//2 for i in range(len(df2))])['key'].apply(list)
else:
group_match = df2.groupby(df2.groupby(['amount']).cumcount())['key'].apply(list)
match.extend(group_match)
match.extend([list(reversed(m)) for m in group_match])
在df_扩展为这样的情况下,请注意末尾的三行0:
d_in = {'key' : ['80000001', '80000002', '80000003', '80000004', '80000005', '80000006', '80000007', '80000008', '80000009', '80000010', '80000011', '80000012', '80000013', '80000014', '80000015', '1', '2', '3'],
'date' : ['20200901', '20200901', '20200902', '20200902', '20200902','20200903', '20200904', '20200905', '20200905', '20200906', '20200906', '20200906', '20200906', '20200906', '20200906', '20200906', '20200906', '20200906'],
'category' : ['Z293', 'B993', 'Z293', 'B993', 'W884', 'C123', 'V332', 'C123', 'V332', 'Z213', 'Z213', 'Z213', 'Z213', 'Z213', 'Z213', 'Z213', 'Z213', 'Z213'],
'type' : ['tools', 'supplies', 'tools', 'supplies', 'repairs', 'custom', 'misc', 'custom', 'misc', 'technology', 'technology', 'technology', 'technology', 'technology', 'technology','technology', 'technology', 'technology'],
'source' : ['Q112', 'E443', 'Q112', 'E443', 'P443', 'B334', 'E449', 'B334', 'E449', 'QQ32', 'QQ32', 'QQ32', 'QQ32', 'QQ32', 'QQ32', 'QQ32', 'QQ32', 'QQ32'],
'amount' : [-123.21, 3.12, 123.21, -3.12, 9312.00, 312.23, -13.23, -312.23, 13.23, 10, 10, -10, -10, 10, -10,0,0,0]}
我们将忽略与以前相同的行
key date category type source amount coupling_key
15 1 20200906 Z213 technology QQ32 0.00 2
16 2 20200906 Z213 technology QQ32 0.00 1
17 3 20200906 Z213 technology QQ32 0.00 None
另一个解决方案是,尝试使用“纯熊猫”功能,不管这意味着什么 要理解以下内容,请执行以下步骤 我们按“类别”、“类型”、“来源”和“金额”进行分组 在每一组中,我们将有相同abs数量但符号不同的行。然后我们按“数量”分组,在正数范围内标记行,从1到n,在负数范围内标记行,从1到n,从而得到累积数 …通过匹配第一个元素的正片与第一个元素的负片、第二个元素的正片与第二个元素的负片等进行分组 组_match将有一个在步骤3中匹配的['key1','key2']列表 剩下的只是把这些列表放在一起,我们还希望每个['key1','key2']都有['key2','key1'],因此这一行颠倒了。。在其中,转换为数据帧,并连接到原始数据帧 第5步可能会做得更优雅,但这是可行的
match = []
for _, df2 in df_in.groupby([df_in['category'], df_in['type'], df_in['source'], df_in['amount'].abs()], as_index=False):
group_match = df2.groupby(df2.groupby(['amount']).cumcount())['key'].apply(list)
match.extend(group_match)
match.extend([list(reversed(m)) for m in group_match])
match_df = pd.DataFrame(data = match, columns = ['key', 'coupling_key']).drop_duplicates()
df_out = df_in.merge(match_df, on='key')
生成所需的df_输出:
key date category type source amount coupling_key
0 80000001 20200901 Z293 tools Q112 -123.21 80000003
1 80000002 20200901 B993 supplies E443 3.12 80000004
2 80000003 20200902 Z293 tools Q112 123.21 80000001
3 80000004 20200902 B993 supplies E443 -3.12 80000002
4 80000005 20200902 W884 repairs P443 9312.00 None
5 80000006 20200903 C123 custom B334 312.23 80000008
6 80000007 20200904 V332 misc E449 -13.23 80000009
7 80000008 20200905 C123 custom B334 -312.23 80000006
8 80000009 20200905 V332 misc E449 13.23 80000007
9 80000010 20200906 Z213 technology QQ32 10.00 80000012
10 80000011 20200906 Z213 technology QQ32 10.00 80000013
11 80000012 20200906 Z213 technology QQ32 -10.00 80000010
12 80000013 20200906 Z213 technology QQ32 -10.00 80000011
13 80000014 20200906 Z213 technology QQ32 10.00 80000015
14 80000015 20200906 Z213 technology QQ32 -10.00 80000014
如果amount列中有零,并且它们应该根据下面的注释进行匹配,那么我们可以如下修改循环
for _, df2 in df_in.groupby([df_in['category'], df_in['type'], df_in['source'], df_in['amount'].abs()], as_index=False):
if (df2['amount'].iloc[0] == 0):
group_match = df2.groupby([i//2 for i in range(len(df2))])['key'].apply(list)
else:
group_match = df2.groupby(df2.groupby(['amount']).cumcount())['key'].apply(list)
match.extend(group_match)
match.extend([list(reversed(m)) for m in group_match])
在df_扩展为这样的情况下,请注意末尾的三行0:
d_in = {'key' : ['80000001', '80000002', '80000003', '80000004', '80000005', '80000006', '80000007', '80000008', '80000009', '80000010', '80000011', '80000012', '80000013', '80000014', '80000015', '1', '2', '3'],
'date' : ['20200901', '20200901', '20200902', '20200902', '20200902','20200903', '20200904', '20200905', '20200905', '20200906', '20200906', '20200906', '20200906', '20200906', '20200906', '20200906', '20200906', '20200906'],
'category' : ['Z293', 'B993', 'Z293', 'B993', 'W884', 'C123', 'V332', 'C123', 'V332', 'Z213', 'Z213', 'Z213', 'Z213', 'Z213', 'Z213', 'Z213', 'Z213', 'Z213'],
'type' : ['tools', 'supplies', 'tools', 'supplies', 'repairs', 'custom', 'misc', 'custom', 'misc', 'technology', 'technology', 'technology', 'technology', 'technology', 'technology','technology', 'technology', 'technology'],
'source' : ['Q112', 'E443', 'Q112', 'E443', 'P443', 'B334', 'E449', 'B334', 'E449', 'QQ32', 'QQ32', 'QQ32', 'QQ32', 'QQ32', 'QQ32', 'QQ32', 'QQ32', 'QQ32'],
'amount' : [-123.21, 3.12, 123.21, -3.12, 9312.00, 312.23, -13.23, -312.23, 13.23, 10, 10, -10, -10, 10, -10,0,0,0]}
我们将忽略与以前相同的行
key date category type source amount coupling_key
15 1 20200906 Z213 technology QQ32 0.00 2
16 2 20200906 Z213 technology QQ32 0.00 1
17 3 20200906 Z213 technology QQ32 0.00 None
请粘贴代码,你已经尝试到目前为止,并在那里你是Stucked张贴点。谢谢请粘贴代码,你已经尝试到目前为止,并在那里你是Stucked张贴点。谢谢这篇文章是按照我考虑的思路写的,谢谢你的回复!我发现这个解决方案不是零量控制的。遗憾的是,我没有在我原来的帖子中要求这个条件。修改此代码以控制零金额有多困难?零金额的规则是什么?你可以先把它们过滤掉谢谢你的邀请。规则是零金额应按照与非零金额相同的规则耦合。换句话说,在给定的条件下,第一个零应该耦合到第二个零,第三个零应该耦合到第四个零,依此类推。同一类别etc的所有零都将在同一组中结束,在循环中是相同的df2,所以看起来我们需要循环中的ifdf2['amount']==0条件来单独处理这种情况。我会更新答案这篇文章是按照我考虑的思路写的,谢谢你的回复!我发现这个解决方案不是可控的
他被判零罚款。遗憾的是,我没有在我原来的帖子中要求这个条件。修改此代码以控制零金额有多困难?零金额的规则是什么?你可以先把它们过滤掉谢谢你的邀请。规则是零金额应按照与非零金额相同的规则耦合。换句话说,在给定的条件下,第一个零应该耦合到第二个零,第三个零应该耦合到第四个零,依此类推。同一类别etc的所有零都将在同一组中结束,在循环中是相同的df2,所以看起来我们需要循环中的ifdf2['amount']==0条件来单独处理这种情况。我会更新答案