我在尝试使用人行横道将数据集中的代码A与代码B进行匹配时遇到了一个问题。例如,这些代码可以是1990和1991年的行业代码,人口普查改变了他们对行业进行编码的方式。如果我可以创建一个协调的代码,我就可以使用这个代码随着时间的推移跟踪相同的行业(或新的行业组,如果需要的话)。它们提供了一个类似于以下内容的交叉通道:
import pandas as pd
import numpy as np
df = pd.DataFrame([
[0,0],
[1,2],
[1,3],
[2,4],
[3,4],
[4,5],
[4,6],
[5,5],
[10,11],
[10,13],
[11,11]
], columns=list('AB'))
df
A B
0 0 0
1 1 2
2 1 3
3 2 4
4 3 4
5 4 5
6 4 6
7 5 5
8 10 11
9 10 13
10 11 11因此,我想要的输出将是一个新列,它定义了A和B中的非重叠代码。例如,考虑下面所需的结果:
A B C
0 0 0 0.0
1 1 2 1.0
2 1 3 1.0
3 2 4 2.0
4 3 4 2.0
5 4 5 3.0
6 4 6 3.0
7 5 5 3.0
8 10 11 4.0
9 10 13 4.0
10 11 11 4.0我已经开始通过先完成简单的部分来回答这个问题。这些是(一对多) 1:m和(多对一) m:1匹配,我可以简单地分配一个公共值。
sizesA = df.groupby('A').size()
sizesB = df.groupby('B').size()
df['sizeA'] = df['A'].map(sizesA)
df['sizeB'] = df['B'].map(sizesB)
df['C'] = np.nan
next_v = 0
# 1:m matching
for a in df[df.sizeA>=1].A.unique():
if df[df.A==a]['sizeB'].max()==1:
df['C'] = np.where(df['A']==a, next_v, df['C'])
next_v += 1
# m:1 matching
for b in df[df.sizeB>1].B.unique():
if df[df.B==b]['sizeA'].max()==1:
df['C'] = np.where(df['B']==b, next_v, df['C'])
next_v += 1
df
A B sizeA sizeB C
0 0 0 1 1 0.0
1 1 2 2 1 1.0
2 1 3 2 1 1.0
3 2 4 1 2 2.0
4 3 4 1 2 2.0
5 4 5 2 2 NaN
6 4 6 2 1 NaN
7 5 5 1 2 NaN
8 10 11 2 2 NaN
9 10 13 2 1 NaN
10 11 11 1 2 NaN问题在于(多对多) m:m匹配。我似乎想不出一个好的方法来解决这个问题,我猜这是一个很难解决的计算问题。请注意,我可以将剩余的值分配到单个代码之上,但这会忽略这样一个事实,即我可以将它们划分为两个不同的代码,同时仍然保持一致性。
另外,如果你对这个标题有任何建议,请告诉我。
发布于 2020-01-31 06:36:14
C需要从0开始吗?还是可以从1开始?我只是简单地减去1,所以你可以从0开始。您可以根据需要对其进行调整。
使用cumcount和cumsum应该会更容易。
df['C'] = ((df.groupby('A').cumcount()==0) & (df.groupby('B').cumcount()==0)).cumsum()-1
print(df)
print(df)
A B C
0 0 0 0
1 1 2 1
2 1 3 1
3 2 4 2
4 3 4 2
5 4 5 3
6 4 6 3
7 5 5 3
8 10 11 4
9 10 13 4
10 11 11 4发布于 2020-01-31 07:34:25
我真的想出了一个解决方案。也许不是那么优雅。
ungrouped = df['A'].unique().tolist()
Anew = pd.Series(index=sorted(df['A'].unique()))
Bnew = pd.Series(index=sorted(df['B'].unique()))
g = 0
Avals = [ungrouped[0]]
while True:
Bvals = df[df['A'].isin(Avals)].B.unique().tolist()
Acheck = df[df['B'].isin(Bvals)].A.unique().tolist()
if set(Acheck) == set(Avals):
Anew.loc[Avals] = g
Bnew.loc[Bvals] = g
g += 1
ungrouped = [a for a in ungrouped if a not in Avals]
if len(ungrouped) == 0:
break
Avals = [ungrouped[0]]
else:
Avals = Acheck
df['C'] = df['A'].map(Anew)
df
A B C
0 0 0 0.0
1 1 2 1.0
2 1 3 1.0
3 2 4 2.0
4 3 4 2.0
5 4 5 3.0
6 4 6 3.0
7 5 5 3.0
8 10 11 4.0
9 10 13 4.0
10 11 11 4.0https://stackoverflow.com/questions/59994991
复制相似问题