pandas - python - 使用两个字典映射列

我有一个 df:


ColA ColB


1 1


2 3


2 2


1 2


1 3


2 1



我想使用两个不同的字典来更改ColB中的值。 如果ColA中的值为 1和 d2,则使用 d1,如果ColB中的值为 2,则为,


d1 = {1:'a',2:'b',3:'c'}


d2 = {1:'d',2:'e',3:'f'}



结果:


ColA ColB


1 a


2 f


2 e


1 b


1 c


2 d



怎样才能达到最好的效果?

时间:

一种方法是使用np.where,使用一个字典或另一个字典根据ColA的值对ColB中的值进行map处理:


import numpy as np


df['ColB'] = np.where(df.ColA.eq(1), df.ColB.map(d1), df.ColB.map(d2))



这给出了:


 ColA ColB


0 1 a


1 2 f


2 2 e


3 1 b


4 1 c


5 2 d



对于更一般的解决方案,你可以使用np.select,它适用于多个条件,让我们在ColA和字典中添加另一个值,以便了解如何使用三个不同的映射来完成它:


print(df)


 ColA ColB


0 1 1


1 2 3


2 2 2


3 1 2


4 3 3


5 3 1



values_to_map = [1,2,3]


d1 = {1:'a',2:'b',3:'c'}


d2 = {1:'d',2:'e',3:'f'}


d3 = {1:'g',2:'h',3:'i'}



#create a list of boolean Series as conditions


conds = [df.ColA.eq(i) for i in values_to_map]


# List of Series to choose from depending on conds


choices = [df.ColB.map(d) for d in [d1,d2,d3]]


# use np.select to select form the choice list based on conds


df['ColB'] = np.select(conds, choices)



结果:


 ColA ColB


0 1 a


1 2 f


2 2 e


3 1 b


4 3 i


5 3 g



你可以使用一个新字典,其中键是tuple的,并将它映射到压缩的列。


d = {**{(1, k): v for k, v in d1.items()}, **{(2, k): v for k, v in d2.items()}}


df.assign(ColB=[*map(d.get, zip(df.ColA, df.ColB))])



 ColA ColB


0 1 a


1 2 f


2 2 e


3 1 b


4 1 c


5 2 d



或者我们可以用一个lambda ,
注意:我对字典进行了对齐,以基于列表[0, d1, d2]中的相对位置切换,在这种情况下,第一个位置是什么并不重要,我把0放在了。


df.assign(ColB=[*map(lambda x, y: [0, d1, d2][x][y], df.ColA, df.ColB)])



 ColA ColB


0 1 a


1 2 f


2 2 e


3 1 b


4 1 c


5 2 d



为了健壮,我远离可爱,映射具有一些默认值能力的lambda,


df.assign(ColB=[*map(lambda x, y: {1: d1, 2: d2}.get(x, {}).get(y), df.ColA, df.ColB)])



 ColA ColB


0 1 a


1 2 f


2 2 e


3 1 b


4 1 c


5 2 d



如果需要对多个组执行这个操作,就使用dictdict来分别映射每个组,理想情况下,你可以找到一些创建 d的功能方法:


d = {1: d1, 2: d2}


df['ColB'] = pd.concat([gp.ColB.map(d[idx]) for idx, gp in df.groupby('ColA')])



输出:


 ColA ColB


0 1 a


1 2 f


2 2 e


3 1 b


4 1 c


5 2 d



我正在使用concatreindex


idx=pd.MultiIndex.from_arrays([df.ColA, df.ColB])


df.ColB=pd.concat([pd.Series(x) for x in [d1,d2]],keys=[1,2]).reindex(idx).values


df


Out[683]: 


 ColA ColB


0 1 a


1 2 f


2 2 e


3 1 b


4 1 c


5 2 d



可以为一个元素创建一个函数,然后在dataframe中使用lambda 。


def your_func(row):


 if row["ColA"] == 1:


 return d1[row["ColB"]]


 elif row["ColB"] == 2:


 return d2[row["ColB"]]


 else:


 return None



df["ColB"] = df.apply(lambda row: your_func(row), axis=1)



你可以使用两种替换方式:


df.loc[df['ColA'] == 1,'ColB'] = df['ColB'].replace(d1, regex=True)


df.loc[df['ColA'] == 2,'ColB'] = df['ColB'].replace(d2, regex=True)



我希望这对你有帮助

...