Replace values in a pandas column using another pandas df which has the corresponding replacements

人盡茶涼 提交于 2021-02-08 06:32:12

问题


I have a pandas df named inventory, which has a column containing Part Numbers (AlphaNumeric). Some of those part numbers have been superseded and I have another df named replace_with containing two columns, 'old part numbers' and 'new part numbers'. For example:

Inventory has values like:

* 123AAA
* 123BBB
* 123CCC
......

and replace-with has values like

**oldPartnumbers**   .....        **newPartnumbers**  

* 123AAA        ............            123ABC
* 123CCC          ...........          123DEF

SO, i need to replace corresponding values in inventory with the new numbers. After replacement inventory will look like as follows:

* 123ABC
* 123BBB
* 123DEF

Is there a simple way to do that in python? Thanks!


回答1:


Let say you have 2 df as follows:

import pandas as pd
df1 = pd.DataFrame([[1,3],[5,4],[6,7]], columns = ['PN','name'])
df2 = pd.DataFrame([[2,22],[3,33],[4,44],[5,55]], columns = ['oldname','newname'])

df1:

    PN  oldname
0   1   3
1   5   4
2   6   7

df2:

    oldname  newname
0   2        22
1   3        33
2   4        44
3   5        55

run left join between them:

temp = df1.merge(df2,'left',left_on='name',right_on='oldname')

temp:

    PN      name     oldname    newname
0   1        3         3.0      33.0
1   5        4         4.0      44.0
2   6        7         NaN      NaN

then calculate the new name column and replace it:

df1['name'] = temp.apply(lambda row: row['newname'] if pd.notnull(row['newname']) else row['name'], axis=1)

df1:

    PN  name
0   1   33.0
1   5   44.0
2   6   7.0

or, as one liner:

df1['name'] = df1.merge(df2,'left',left_on='name',right_on='oldname').apply(lambda row: row['newname'] if pd.notnull(row['newname']) else row['name'], axis=1)



回答2:


Setup

Consider the dataframes inventory and replace_with

inventory = pd.DataFrame(dict(Partnumbers=['123AAA', '123BBB', '123CCC']))

replace_with = pd.DataFrame(dict(
        oldPartnumbers=['123AAA', '123BBB', '123CCC'],
        newPartnumbers=['123ABC', '123DEF', '123GHI']
    ))

Option 1
map

d = replace_with.set_index('oldPartnumbers').newPartnumbers
inventory['Partnumbers'] = inventory['Partnumbers'].map(d)

inventory

  Partnumbers
0      123ABC
1      123DEF
2      123GHI

Option 2
replace

d = replace_with.set_index('oldPartnumbers').newPartnumbers
inventory['Partnumbers'].replace(d, inplace=True)

inventory

  Partnumbers
0      123ABC
1      123DEF
2      123GHI



回答3:


This solution is relatively fast - it uses pandas data alignment and the numpy "copyto" function.

import pandas as pd
import numpy as np

df1 = pd.DataFrame({'partNumbers': ['123AAA', '123BBB', '123CCC', '123DDD']})
df2 = pd.DataFrame({'oldPartnumbers': ['123AAA', '123BBB', '123CCC'],
                    'newPartnumbers': ['123ABC', '123DEF', '123GHI']})

# assign index in each dataframe to original part number columns
# (faster than set_index method, but use set_index if original index must be preserved)
df1.index = df1.partNumbers
df2.index = df2.oldPartnumbers
# use pandas index data alignment
df1['updatedPartNumbers'] = df2.newPartnumbers
# use numpy to copy in old part num when a new part num is not found
np.copyto(df1.updatedPartNumbers.values,
          df1.partNumbers.values,
          where=pd.isnull(df1.updatedPartNumbers))
# reset index
df1.reset_index(drop=True, inplace=True)

df1:

  partNumbers updatedPartNumbers
0      123AAA             123ABC
1      123BBB             123DEF
2      123CCC             123GHI
3      123DDD             123DDD


来源:https://stackoverflow.com/questions/44879044/replace-values-in-a-pandas-column-using-another-pandas-df-which-has-the-correspo

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!