Map column using two dictionaries

If it needs to be done for many groups use a dict of dicts to map each group separately. Ideally you can find some functional way to create d:

d = {1: d1, 2: d2}
df['ColB'] = pd.concat([gp.ColB.map(d[idx]) for idx, gp in df.groupby('ColA')])

Output:

   ColA ColB
0     1    a
1     2    f
2     2    e
3     1    b
4     1    c
5     2    d

You can use a new dictionary in which the keys are tuples and map it against the zipped columns.

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

Or we can get cute with a lambda to map.
NOTE: I aligned the dictionaries to switch between based on their relative position in the list [0, d1, d2]. In this case it doesn't matter what is in the first position. I put 0 arbitrarily.

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

For robustness I'd stay away from cute and map a lambda that had some default value capability

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

I am using concat with reindex

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

One way is using np.where to map the values in ColB using one dictionary or the other depending on the values of ColA:

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

Which gives:

    ColA ColB
0     1    a
1     2    f
2     2    e
3     1    b
4     1    c
5     2    d

For a more general solution, you could use np.select, which works for multiple conditions. Let's add another value in ColA and a dictionary, to see how this could be done with three different mappings:

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)

Resulting in:

    ColA ColB
0     1    a
1     2    f
2     2    e
3     1    b
4     3    i
5     3    g

Tags:

Python

Pandas