我有一个包含70k行和两列的数据帧。Col1包含物料清单名称和客户,Col2包含零件号(它是BOM的一部分(。
Col1 Col2
0 TUR, Cust1 1001
1 GAR, Cust2 1001
2 FOR, Cust3 1001
3 ERB, Cust1 1002
4 PNR, Cust1 1002
5 DUL, Cust2 1003
6 COC, Cust3 1003
7 ETM, Cust1 1004
8 ROW, Cust3 1005
9 HON, Cust3 1005
在搜索Cust1时,我想在第3列中查看零件号是否是专门为该客户购买的。类似这样的东西:
Col1 Col2 Col3
0 TUR, Cust1 1001 false
1 GAR, Cust2 1001 false
2 FOR, Cust3 1001 false
3 ERB, Cust1 1002 true
4 PNR, Cust1 1002 true
5 DUL, Cust2 1003 false
6 COC, Cust3 1003 false
7 ETM, Cust1 1004 true
8 ROW, Cust3 1005 false
9 HON, Cust3 1005 false
我已经尝试过用df.duplated提取重复项,并用str.contains评估客户名称,但没有得到令人满意的结果。有没有我不知道的聪明的解决方案?我是python的新手,遇到这个问题毫无进展。
从Col1
中提取客户,然后从groupby
中提取零件号,并计算应等于1 的唯一客户数
df['Cust'] = df['Col1'].str.split(', ').str[-1]
df['Col3'] = df.groupby('Col2')['Cust'].transform('nunique').eq(1)
如果只想在一次考虑一个客户的情况下检查重复,这里有一个更简单的版本
m = df['Col1'].str.split(', ').str[-1] == 'Cust1' # is cust1?
df['Col3'] = m.groupby(df['Col2']).transform('all') # are all cust1 per part?
结果
Col1 Col2 Cust Col3
0 TUR, Cust1 1001 Cust1 False
1 GAR, Cust2 1001 Cust2 False
2 FOR, Cust3 1001 Cust3 False
3 ERB, Cust1 1002 Cust1 True
4 PNR, Cust1 1002 Cust1 True
5 DUL, Cust2 1003 Cust2 False
6 COC, Cust3 1003 Cust3 False
7 ETM, Cust1 1004 Cust1 True
一种方法如下:
df['Col3'] = df.Col1.str.extract(r',s(.*)$')[0]
# or: `df['Col1'].str.split(', ', expand=True)[1]`
df['Col3'] = df.Col2.map(df.drop_duplicates(subset=['Col2','Col3'])
['Col2'].value_counts().eq(1))
print(df)
Col1 Col2 Col3
0 TUR, Cust1 1001 False
1 GAR, Cust2 1001 False
2 FOR, Cust3 1001 False
3 ERB, Cust1 1002 True
4 PNR, Cust1 1002 True
5 DUL, Cust2 1003 False
6 COC, Cust3 1003 False
7 ETM, Cust1 1004 True
解释
- 使用
Series.str.extract
从Col1
获取客户名称,并分配给新列Col3
。(或者,使用Series.str.split
。( - 接下来,使用
df.drop_duplicates
,subset
参数设置为['Col2','Col3']
。例如,对于1002, Cust1
这样的副本,我们只保留第一个 - 现在,选择
Col2
并应用Series.value_counts
。df.drop_duplicates(subset=['Col2','Col3'])['Col2'].value_counts()
在此阶段的结果如下:
1001 3
1003 2
1002 1
1004 1
Name: Col2, dtype: int64
- 以
1
为计数的Col2
中的值(即1002, 1004
(将仅出现在一个客户中,因此我们可以将Series.eq
链接为仅针对这些值返回True
,而将False
链接为其他值 - 最后,我们想把这个结果放在
Series.map
中,应用于Col2
以匹配正确的布尔值。用结果重新覆盖Col3