如果任何单个属性匹配,则将Pandas的列值替换为另一个(确定两列是否具有公共属性)

问题描述 投票:1回答:2

假设有一个示例数据帧:

   Chemical   Compound     Name
0   Alcohol    Ethanol   Liquor
1     Hooch        NaN   Liquor
2   Cerveza    Ethanol      NaN
3   Bauxite  Aluminium Gibbsite
4  Feldspar  Aluminium      NaN

更换或识别两行是否相同的有效方法是什么? (如果任何属性(列)匹配,则假设两行相同,并且不一定全部匹配)

结果可能是:

   Chemical   Compound     Name
0   Alcohol    Ethanol   Liquor
1   Alcohol        NaN   Liquor
2   Alcohol    Ethanol      NaN
3   Bauxite  Aluminium Gibbsite
4   Bauxite  Aluminium      NaN

要么:

   Chemical   Compound     Name Identifier
0   Alcohol    Ethanol   Liquor    Alcohol
1     Hooch        NaN   Liquor    Alcohol
2   Cerveza    Ethanol      NaN    Alcohol
3   Bauxite  Aluminium Gibbsite    Bauxite
4  Feldspar  Aluminium      NaN    Bauxite
python pandas
2个回答
3
投票

这是伪装的集合/连接组件/联合查找问题。

如果我们任意决定将其视为连接组件问题,我们可以将帧中的每个单词都想象为一个节点。一行基本上表示那里的元素是等价的,换句话说,是可达的:节点之间有边。要确定同义词集,我们需要找到图的连接组件。

import networkx as nx
G = nx.from_pandas_dataframe(df.stack().reset_index(), source='level_0', target=0)
codes = {v: i for i, vv in enumerate(nx.connected_components(G)) for v in vv}
df["Identifier"] = df["Chemical"].groupby(df["Chemical"].replace(codes)).transform("first")

给我

In [229]: df
Out[229]: 
   Chemical   Compound    Name Identifier
0   Alcohol    Ethanol  Liquor    Alcohol
1     Hooch        NaN  Liquor    Alcohol
2   Cerveza    Ethanol     NaN    Alcohol
3   Bauxite  Aluminium     NaN    Bauxite
4  Feldspar  Aluminium     NaN    Bauxite

因为一旦我们用边创建图(等价)

In [233]: G.edges()
Out[233]: 
[(0, 'Alcohol'),
 (0, 'Ethanol'),
 (0, 'Liquor'),
 ('Ethanol', 2),
 ('Liquor', 1),
 (1, 'Hooch'),
 (2, 'Cerveza'),
 (3, 'Bauxite'),
 (3, 'Aluminium'),
 ('Aluminium', 4),
 (4, 'Feldspar')]

我们可以要求networkx找到这些组:

In [234]: list(nx.connected_components(G))
Out[234]: 
[{0, 1, 2, 'Alcohol', 'Cerveza', 'Ethanol', 'Hooch', 'Liquor'},
 {3, 4, 'Aluminium', 'Bauxite', 'Feldspar'}]

然后剩下的就是把它们变成数字并随意选择使用第一个化学品条目作为每个组的名称。

我们可以通过使用scipy的scipy.sparse.csgraph.connected_components函数完成相同的操作,稍微多一点设置,或者只是使用现成的集合合算法来查找组。例如,使用集合合并算法here,我们可以做到

In [240]: consolidate([set(row.dropna()) for _, row in df.iterrows()])
Out[240]: 
[{'Alcohol', 'Cerveza', 'Ethanol', 'Hooch', 'Liquor'},
 {'Aluminium', 'Bauxite', 'Feldspar'}]

我们再一次拥有我们需要的团体。


1
投票

要标识至少包含一个匹配列的行:

>>> df.apply(lambda x: x.dropna().duplicated()).any(axis=1)
0    False
1     True
2     True
3    False
4     True
dtype: bool

在上文中,行1,2和4是“重复的”。第1行:白酒,第2行:乙醇,第4行:铝。

但是,我不清楚你的填充逻辑。

© www.soinside.com 2019 - 2024. All rights reserved.