我有两个数据框,如下面的例子:
import pandas as pd
import numpy as np
df = pd.DataFrame({'a': ['20', '50', '100'], 'b': [1, np.nan, 1],
'c': [np.nan, 1, 1]})
df_id = pd.DataFrame({'b': ['50', '4954', '93920', '20'],
'c': ['123', '100', '6', np.nan]})
print(df)
a b c
0 20 1.0 NaN
1 50 NaN 1.0
2 100 1.0 1.0
print(df_id)
b c
0 50 123
1 4954 100
2 93920 6
3 20 NaN
对于df['a']
中的每个标识符,如果df['b']
中的任何行中没有匹配的标识符,我想要使df_id['b']
中的值为空。我想对列df['c']
做同样的事情。
我想要的结果如下:
result = pd.DataFrame({'a': ['20', '50', '100'], 'b': [1, np.nan, np.nan],
'c': [np.nan, np.nan, 1]})
print(result)
a b c
0 20 1.0 NaN
1 50 NaN NaN # df_id['c'] did not contain '50'
2 100 NaN 1.0 # df_id['b'] did not contain '100'
我尝试这样做的地方是:
for i, letter in enumerate(['b','c']):
df[letter] = (df.apply(lambda x: x[letter] if x['a']
.isin(df_id[letter].tolist()) else np.nan, axis = 1))
我得到的错误:
AttributeError: ("'str' object has no attribute 'isin'", 'occurred at index 0')
这是在Python 3.5.2,Pandas版本20.1
中答案 0 :(得分:0)
您可以使用此解决问题:
for letter in ['b','c']: # took off enumerate cuz i didn't need it here, maybe you do for the rest of your code
df[letter] = df.apply(lambda row: row[letter] if row['a'] in (df_id[letter].tolist()) else np.nan,axis=1)
只需将isin
替换为in
。
问题是,当您在df
上使用apply时,x代表df rows
,因此当您选择x['a']
时,您实际上选择了一个元素。
但是,isin适用于引发错误的系列或类似列表的结构,因此我们只需使用in
来检查该元素是否在列表中。
希望这很有帮助。如果您有任何疑问,请询问。
答案 1 :(得分:0)
从Pandas New Column Calculation Based on Existing Columns Values调整难以找到的答案:
for i, letter in enumerate(['b','c']):
mask = df['a'].isin(df_id[letter])
name = letter + '_new'
# for some reason, df[letter] = df.loc[mask, letter] does not work
df.loc[mask, name] = df.loc[mask, letter]
df[letter] = df[name]
del df[name]
这不是很好,但似乎有效。
答案 2 :(得分:0)
如果您拥有更大的Dataframe并且性能对您很重要,您可以先构建一个掩码df,然后将其应用于您的数据帧。 首先创建掩码:
mask = df_id.apply(lambda x: df['a'].isin(x))
b c
0 True False
1 True False
2 False True
这可以应用于原始数据框:
df.iloc[:,1:] = df.iloc[:,1:].mask(~mask, np.nan)
a b c
0 20 1.0 NaN
1 50 NaN NaN
2 100 NaN 1.0