我想根据熊猫中的布尔OR准则生成一组组。组由在A列或B列上匹配的成员组成。
例如,在此数据框中:
df = pd.DataFrame([[1,1],[2,2],[2,3],[2,4],[3,3],[4,5]], columns = ['A','B'])
A B
0 1 1
1 2 2
2 2 3
3 2 4
4 3 3
5 4 5
由于第1行,第2行和第3行在A列上匹配,第2行和第4行在B列上匹配,我希望id值为:
A B id
0 1 1 0
1 2 2 1
2 2 3 1
3 2 4 1
4 3 3 1
5 4 5 2
除了使用连接创建NxN scipy图并使用scipy.sparse.csgraph.connected_components
之外,我找不到任何解决方案。还有其他更简单的选择吗?
答案 0 :(得分:1)
请注意,我认为这是网络问题,因此我们使用networkx
import networkx as nx
G=nx.from_pandas_edgelist(df, 'A', 'B')
l=list(nx.connected_components(G))
l
[{1}, {2, 3}]
from itertools import chain
l=[dict.fromkeys(y,x)for x,y in enumerate(l)]#create the list of dict for later map
d=dict(chain(*map(dict.items,l)))# flatten the list of dict to one dict
df['ID']=df.B.map(d)
df
A B ID
0 1 1 0
1 2 2 1
2 2 3 1
3 3 3 1
更新
s1=df.A.astype('category').cat.codes.sort_values()
s2=df.B.astype('category').cat.codes.sort_values()
s=((s1==s1.shift())|(s2==s2.shift())).eq(False).cumsum()
s
#df['new']=s
Out[25]:
0 1
1 2
2 2
3 2
4 2
5 3
dtype: int32+
答案 1 :(得分:0)
我们可以使用Counter
类来做到这一点。我们计算该列中每个元素的出现次数,并使用这些值创建一个临时列。如果该临时列中某行的值大于1(这意味着该数字多次出现,我们将更改id
列。
import pandas as pd
from collections import Counter as ctr
df = pd.DataFrame([[1,1],[2,2],[2,3],[2,4],[3,3],[4,5]], columns = ['A','B'])
df['id'] = 0
for i in range(len(df.columns)):
if list(df.columns)[i] != 'id':
c = dict(ctr(df[list(df.columns)[i]]))
df[list(df.columns)[i] + '_1'] = df[list(df.columns)[i]].apply(lambda x: c[x])
df.loc[df[list(df.columns)[i] + '_1'] > 1, 'id'] = 1
df = df.drop(columns=[list(df.columns)[i] + '_1'])
df
A B id
0 1 1 0
1 2 2 1
2 2 3 1
3 2 4 1
4 3 3 1
5 4 5 0
此列应可扩展为> 2列。
答案 2 :(得分:0)
感谢@ W-B将我放在正确的位置。这是一个更通用的答案,适用于> 2列,并且各列之间的值不相关。
import pandas as pd
import networkx as nx
from itertools import chain, combinations
columns = ['A','B','C']
df = pd.DataFrame([[1,1,1],[2,2,2],[2,3,3],[2,4,4],[3,3,4],[4,5,5]], columns = columns)
# make columns unique, so that values in any column are not treated as equivalent to values in another
# if you don't want to overwrite values, create new columns instead
for col in df.columns:
df[col] = str(col)+df[col].astype(str)
colPairs = list(combinations(columns, 2)) # we could match on a subset of column pairs instead
G = nx.compose_all([nx.from_pandas_edgelist(df, colPair[0], colPair[1]) for colPair in colPairs])
l=list(nx.connected_components(G))
l=[dict.fromkeys(y,x)for x,y in enumerate(l)]
d=dict(chain(*map(dict.items,l)))
df['ID']=df.B.map(d)
print(df)
A B C ID
0 A1 B1 C1 0
1 A2 B2 C2 1
2 A2 B3 C3 1
3 A2 B4 C4 1
4 A3 B3 C4 1
5 A4 B5 C5 2