提问人:Fazli 提问时间:10/21/2021 最后编辑:Fazli 更新时间:10/22/2021 访问量:798
使用嵌套字典根据条件映射数据帧中的值
Map values in dataframe based on condition using a nested dictionary
问:
我有以下词典
dict_map = {
'Anti' : {'Drug':('A','B','C')},
'Undef': {'Drug':'D','Name':'Type X'},
'Vit ' : {'Name': 'Vitamin C'},
'Placebo Effect' : {'Name':'Placebo', 'Batch':'XYZ'},
}
和数据帧
df = pd.DataFrame(
{
'ID': ['AB01', 'AB02', 'AB03', 'AB04', 'AB05','AB06'],
'Drug': ["A","B","A",np.nan,"D","D"],
'Name': ['Placebo', 'Vitamin C', np.nan, 'Placebo', '', 'Type X'],
'Batch' : ['ABC',np.nan,np.nan,'XYZ',np.nan,np.nan],
}
我必须创建一个新列,该列将使用列表中指定的列的数据来填充
cols_to_map = ["Drug", "Name", "Batch"]
最终结果应如下所示
请注意,尽管有“维生素 C”,但“结果”列的前 3 行填充了“反”,而“安慰剂”是“名称”列,这是因为“反”在字典中排在第一位。如何使用 python 实现这一点?无论如何,dict_map都可以进行重组以满足此结果。我不是python专业人士,我真的很感激一些帮助。
答:
1赞
jezrael
10/21/2021
#1
首先,为嵌套字典中元组的单独值重塑嵌套字典:
from collections import defaultdict
d = defaultdict(dict)
for k, v in dict_map.items():
for k1, v1 in v.items():
if isinstance(v1, tuple):
for x in v1:
d[k1][x] = k
else:
d[k1][v1] = k
print (d)
defaultdict(<class 'dict'>, {'Drug': {'A': 'Anti', 'B': 'Anti',
'C': 'Anti', 'D': 'Undef'},
'Name': {'Type X': 'Undef', 'Vitamin C': 'Vit ',
'Placebo': 'PPL'}})
df = pd.DataFrame(
{
'ID': ['AB01', 'AB02', 'AB03', 'AB04', 'AB05','AB06'],
'Drug': ["A","B","A",np.nan,
"D","D"],
'Name': ['Placebo', 'Vitamin C', np.nan, 'Placebo', '', 'Type X']
}
)
然后按字典映射,优先级是按列表中列的顺序排列的:cols_to_map
cols_to_map = ["Drug", "Name"]
df['Result'] = np.nan
for col in cols_to_map:
df['Result'] = df['Result'].combine_first(df[col].map(d[col]))
print (df)
ID Drug Name Result
0 AB01 A Placebo Anti
1 AB02 B Vitamin C Anti
2 AB03 A NaN Anti
3 AB04 NaN Placebo PPL
4 AB05 D Undef
5 AB06 D Type X Undef
cols_to_map = [ "Name","Drug"]
df['Result'] = np.nan
for col in cols_to_map:
df['Result'] = df['Result'].combine_first(df[col].map(d[col]))
print (df)
ID Drug Name Result
0 AB01 A Placebo PPL
1 AB02 B Vitamin C Vit
2 AB03 A NaN Anti
3 AB04 NaN Placebo PPL
4 AB05 D Undef
5 AB06 D Type X Undef
编辑:
df['Result1'] = df['Drug'].map(d['Drug'])
df['Result2'] = df['Name'].map(d['Name'])
print (df)
ID Drug Name Result1 Result2
0 AB01 A Placebo Anti PPL
1 AB02 B Vitamin C Anti Vit
2 AB03 A NaN Anti NaN
3 AB04 NaN Placebo NaN PPL
4 AB05 D Undef NaN
5 AB06 D Type X Undef Undef
评论
0赞
Fazli
10/21/2021
谢谢,但是“Undef”应该只在第 5 行,因为只有该行在“药物”列中具有“D”,在列名称中具有“X”,而“Anti”必须位于第 0、1、2 行中,因为它满足字典中指定的第一个条件
0赞
jezrael
10/21/2021
@Fazli - 很遗憾不明白为什么。
0赞
jezrael
10/21/2021
@Fazli - 第一、第二和最后一行匹配两个条件(药物、名称)、第三、第五马赫、第四匹配。为什么会有?Name
Drug
NaN
0赞
Fazli
10/21/2021
因此,如果它满足第一个条件并被映射,则无需检查其他条件(这可以通过使用 nans 创建新列并在 for 循环中使用 fillna 来完成),并且第 4 行有 NaN,因为如果 Drug 是 D 且 Name 是 “”,则没有应该映射它的情况
0赞
jezrael
10/21/2021
@Fazli 选中 EDIT。在 Result1 中被映射,所以只有 NaN,如果映射得到 NaN。那么为什么在最后一列中替换了 index=4 呢?Drug
index=3
Name
Result2
2,4
NaN
0赞
Tranbi
10/21/2021
#2
由于 dict 和预期结果之间的关系非常复杂,我将使用一个函数来应用于您的 DataFrame。这使我们免于操纵字典:
def get_result(row):
result = np.nan
for k,v in dict_map.items():
if row['Name'] in v.values():
result = k
if row['Name'] and type(row['Drug']) == str and 'Drug' in v.keys() and row['Drug'] in v['Drug']:
return k
return result
df['Result'] = df.apply(lambda row: get_result(row), axis=1)
print(df)
输出:
ID Drug Name Result
0 AB01 A Placebo Anti
1 AB02 B Vitamin C Anti
2 AB03 A NaN Anti
3 AB04 NaN Placebo PPL
4 AB05 D NaN
5 AB06 D Type X Undef
在更新您的问题后,我将函数更改为通用函数。不过,我不太确定它是否会涵盖您的所有情况,因为您的输出不会随着新列而发生太大变化:
col_to_maps = ["Drug", "Name", "Batch"]
def get_result(row, dict_map):
result = np.nan
for k,v in dict_map.items():
for i,col in enumerate(col_to_maps[:-1]):
if type(v)==dict:
if str(row[col]) and \
all(str(row[other_col])
and (not(str(other_col) in v.keys()) and str(col) in v.keys() and str(row[col]) in v[col]
or str(other_col) in v.keys() and str(row[other_col]) in v[other_col]
)
for other_col in col_to_maps[i+1:]
):
return k
elif str(row[col]) in v:
result = k
return result
df['Result'] = df.apply(lambda row: get_result(row, dict_map), axis=1)
print(df)
输出:
ID Drug Name Batch Result
0 AB01 A Placebo ABC Anti
1 AB02 B Vitamin C NaN Anti
2 AB03 A NaN NaN Anti
3 AB04 NaN Placebo XYZ Placebo Effect
4 AB05 D NaN NaN
5 AB06 D Type X NaN Undef
评论
0赞
Fazli
10/21/2021
如果有的话,我可以在不对列名进行硬编码的情况下做到这一点,而是从列表中获取感兴趣的列cols_to_map?因为可能存在涉及 2 个以上变量的情况
0赞
Tranbi
10/21/2021
你能举一个第三列的例子吗?包括对字典和预期输出的更改?
0赞
Fazli
10/21/2021
我已经更新了上面的问题
0赞
Tranbi
10/22/2021
好的,我不确定我是否完全掌握了您的要求,但我更新了我的答案。一探究竟!
上一个:根据字符串中定义的条件填充新列
下一个:从字符串创建字典
评论