Заменить значения в одном датафрейме на значения из другого по услови

Есть два датафрейма, необходимо заменить значения в первом датафрейме на айдишники из второго датафрейма, если значениясовпадают по колонкам

df1 = pd.DataFrame(
    {
        "col1": ["string1", "string2"],
        "col2": [np.NaN, "string1"],
        "col3": ["string2", np.NaN ],
        "col1_name": [np.NaN, np.NaN],
        "col2_name": ["first_name", np.NaN],
        "col3_name": [np.NaN, "last_name"]
    }
)

df2 = pd.DataFrame(
    {
        "string": ["string1", "string2"],
        "name": ["first_name", "last_name"],
        "desc": ["description 102", "description 103"],
        "id_": [101, 202]
    }
)

Пробовал сделать так (к каждой колонке):

df1.col1 = df1.col1.apply(lambda x: df2[df2["string"] == x].id_)

Но работает не так, как я этого ожидаю (не очень понимаю печему оно так...) Хотелось бы увидеть в этом (df1.col1) случае:

col1 |
101  |
202  |

Поясните , пожалуйста, почему ответ другой и как можно поправить?

PS: я понимаю что при вызове df1.col1.apply(lambda x: df2[df2["string"] == x].id_) возвращается датафрейм 2х2, но не понимаю почему.


Ответы (2 шт):

Автор решения: Nobody

Решил эту задачу путем создания мапперов

string_mapper = dict(zip(df2.string, df2.id_))
name_mapper = dict(zip(df2.name, df2.id_))

df1.col1 = df1.col1.map(string_mapper)
df1.col1_name = df1.col1_name.map(name_mapper)
→ Ссылка
Автор решения: strawdog

Если я правильно понял вопрос, а я в этом сомневаюсь, то можно еще такое сделать:

res = df1.applymap(lambda x: df2.loc[df2.eq(x).any(1), "id_"]
                   .values).applymap(lambda x:x.flat[0] if x.size>0 else np.nan)

тогда при ваших исходных, res будет:

   col1   col2   col3  col1_name  col2_name  col3_name
0   101    NaN  202.0        NaN      101.0        NaN
1   202  101.0    NaN        NaN        NaN      202.0​

разумеется, тип float появился из-за np.nan. Вы можете заменить это по своему усмотрению.

→ Ссылка