将一个Pandas数据框的特定列与另一个数据框的数据按条件合并

huangapple go评论96阅读模式
英文:

Merge certain columns of a pandas dataframe with data from another dataframe by condition

问题

我明白你的需求。你想要在DataFrame df1 中使用DataFrame df2 中的数据填充空白的'Region'和'Country'列,但同时保留df1 中的信息。下面是一个代码示例,可以实现这一目标:

  1. import pandas as pd
  2. import numpy as np
  3. # 数据示例
  4. data1 = {
  5. 'Substance': ['Substance1', 'Substance2', 'Substance1', 'Substance3', 'Substance2', 'Substance1', 'Substance3', 'Substance2', 'Substance4', 'Product A'],
  6. 'Name': ['Bayer', 'Sanofi', 'Pfizer', 'AstraZeneca', 'BionTech', 'Sanofi', 'Sanofi', 'Bayer', 'Pfizer', 'Braun'],
  7. 'Region': ['Europe', 'Europe', 'Asia', 'Asia', 'North America', np.nan, np.nan, 'Europe', 'Asia', 'Asia'],
  8. 'Country': ['France', np.nan, np.nan, 'P.R. China', 'United States', np.nan, np.nan, np.nan, 'India', 'Indonesia'],
  9. 'Misc': [910, 200, 898, 910, 910, 12, 34, 700, 800, 10000],
  10. }
  11. data2 = {
  12. 'Substance': ['Substance1', 'Substance1', 'Substance1', 'Substance3', 'Substance2', 'Substance3'],
  13. 'Name': ['Bayer', 'Sanofi', 'Pfizer', 'AstraZeneca', 'BionTech', 'Sanofi'],
  14. 'Region': ['Europe', 'Europe', 'Asia', 'Asia', 'North America', np.nan],
  15. 'Country': ['France', 'Germany', 'India', 'P.R. China', 'United States', 'Poland'],
  16. 'Misc': [910, 200, 898, 910, 910, 40],
  17. }
  18. df1 = pd.DataFrame(data1)
  19. df2 = pd.DataFrame(data2)
  20. # 合并数据,保留df1中的非空值
  21. df3 = df1.copy() # 复制df1以保留原始数据
  22. df3[['Region', 'Country']] = df1[['Region', 'Country']].fillna(df2[['Region', 'Country'])
  23. # 输出结果
  24. print(df3)

这段代码将保留df1 中的非空值,并使用df2 中的数据填充空白的'Region'和'Country'列。如果df1 中的某一行在这两列中有值,将不会被df2 中的值替代。

英文:

I have the following challenge: I have two Pandas Dataframes with information about eg. chemical substances and related to some additional information. E.g. production region or country.
For example, like this:

  1. data1 = {
  2. 'Substance' : ['Substance1', 'Substance2', 'Substance1', 'Substance3', 'Substance2', 'Substance1', 'Substance3', 'Substance2', 'Substance4'],
  3. 'Name' : ['Bayer', 'Sanofi', 'Pfizer', 'AstraZeneca', 'BionTech', 'Sanofi', 'Sanofi', 'Bayer', 'Pfizer'],
  4. 'Region' : ['Europe', 'Europe', 'Asia', 'Asia', 'North America', np.nan, np.nan, 'Europe', 'Asia'],
  5. 'Country' : ['France', np.nan, np.nan, 'P.R. China', 'United States', np.nan, np.nan, np.nan, 'India'],
  6. 'Misc' : [910, 200, 898, 910, 910, 12, 34, 700, 800],
  7. }
  8. df1 = pd.DataFrame(data1)
  9. #print(df1)

and

  1. data2 = {
  2. 'Substance' : ['Substance1', 'Substance2', 'Substance1', 'Substance3', 'Substance2'],
  3. 'Name' : ['Bayer', 'Sanofi', 'Pfizer', 'AstraZeneca', 'BionTech'],
  4. 'Region' : ['Europe', 'Europe', 'Asia', 'Asia', 'North America'],
  5. 'Country' : ['France', 'Germany', 'India', 'P.R. China', 'United States'],
  6. 'Misc' : [910, 200, 898, 910, 910],
  7. }
  8. df2 = pd.DataFrame(data2)
  9. #print(df2)

In the first data frame all orders from one year are listed. It happens that a substance is also supplied by several manufacturers and that the row appears more than once (== number of orders).
I would like to supplement the dataframe (df1) with information from certain columns of another dataframe (df2). The goal is, if in df1 for a substance and a manufacturer the value in the column 'Region' or 'Country' is empty, then please insert the value from the corresponding column from df2.

  1. df3 = df1.loc[df1.Substance.isin(df2.Substance), ['Substance', 'Region', 'Country']] = df2[['Substance', 'Region', 'Country']]
  2. #print(df3)

However, I then lose many rows (e.g. if substances are repeated). But I would keep all rows in df, just supplemented with information from df2.

I would expect the following result for df3:

  1. | | Substance | Name | Region | Country | Misc |
  2. -------------------------------------------------------------------
  3. | 0 | Substance1 | Bayer | Europe | France | 910 |
  4. | 1 | Substance2 | Sanofi | Europe | Germany | 200 |
  5. | 2 | Substance1 | Pfizer | Asia | India | 898 |
  6. | 3 | Substance3 | AstraZeneca | Asia | P.R. China | 910 |
  7. | 4 | Substance2 | BionTech |North America | United States | 910 |
  8. | 5 | Substance1 | Sanofi | Europe | France | 12 |
  9. | 6 | Substance3 | Sanfoi | np.nan | np.nan | 34 |
  10. | 7 | Substance2 | Bayer | Europe | Germany | 700 |
  11. | 8 | Substance4 | Pfizer | Asia | India | 800 |

Any suggestions would be appreciated. Many thanks in advance!

EDIT:

I'm not sure if this is a new question or an edit of my old question - that's why I'm posting this as a comment and want to ask for your help again, especially @mozway.

  1. data1 = {
  2. 'Substance' : ['Substance1', 'Substance2', 'Substance1', 'Substance3', 'Substance2', 'Substance1', 'Substance3', 'Substance2', 'Substance4', 'Product A'],
  3. 'Name' : ['Bayer', 'Sanofi', 'Pfizer', 'AstraZeneca', 'BionTech', 'Sanofi', 'Sanofi', 'Bayer', 'Pfizer', 'Braun'],
  4. 'Region' : ['Europe', 'Europe', 'Asia', 'Asia', 'North America', np.nan, np.nan, 'Europe', 'Asia', 'Asia'],
  5. 'Country' : ['France', np.nan, np.nan, 'P.R. China', 'United States', np.nan, np.nan, np.nan, 'India', 'Indonesia'],
  6. 'Misc' : [910, 200, 898, 910, 910, 12, 34, 700, 800, 10000],
  7. }
  8. df1 = pd.DataFrame(data1)
  9. #print('line ', lineno(), '\n ', df1)
  1. data2 = {
  2. 'Substance' : ['Substance1', 'Substance1', 'Substance1', 'Substance3', 'Substance2', 'Substance3'],
  3. 'Name' : ['Bayer', 'Sanofi', 'Pfizer', 'AstraZeneca', 'BionTech', 'Sanofi'],
  4. 'Region' : ['Europe', 'Europe', 'Asia', 'Asia', 'North America', np.nan],
  5. 'Country' : ['France', 'Germany', 'India', 'P.R. China', 'United States', 'Poland'],
  6. 'Misc' : [910, 200, 898, 910, 910,40],
  7. }
  8. df2 = pd.DataFrame(data2)
  9. #print('line ', lineno(), '\n ', df2)

Using 'merge' as suggested by @mozway:

  1. out = (df1[['Substance',
  2. 'Name',
  3. # 'Region',
  4. #'Country',
  5. ]]
  6. .merge(df2#.drop(columns='Substance')
  7. .groupby(['Substance',
  8. 'Name'
  9. ], as_index=False).first(),
  10. how='left')
  11. )
  12. #print('line ', lineno(), '\n ',out)

It results in

  1. Substance Name Region Country Misc
  2. 0 Substance1 Bayer Europe France 910.0
  3. 1 Substance2 Sanofi NaN NaN NaN
  4. 2 Substance1 Pfizer Asia India 898.0
  5. 3 Substance3 AstraZeneca Asia P.R. China 910.0
  6. 4 Substance2 BionTech North America United States 910.0
  7. 5 Substance1 Sanofi Europe Germany 200.0
  8. 6 Substance3 Sanofi NaN NaN NaN
  9. 7 Substance2 Bayer NaN NaN NaN
  10. 8 Substance4 Pfizer NaN NaN NaN

But I want the columns 'Region' and 'Country' to be completed by the values of the columns 'Region' and 'Country'. In the example of line 5 in the out-dataframe the value of Substance 1, distributed by Sanofi supplemented from line 1 in df2. That's great. But, the information from df1 in this certain columns is not considered. See, for instance, the line for Product A, where the values of column 'Region' and 'Country' are NaNs. Or line 2 of the out-dataframe where Substance 2 by Sanofihas NaNs in the Columns 'Region' and 'Country', even if the information for 'Region' is given in df1 (line 1).

I am looking for an approach, which keeps the information from df1 (if any exists --> not NaN). If not, I would like to add the information from df2. I really appreciate your support, many thanks in advance!

答案1

得分: 3

你可以使用自定义的 merge

  1. out = (df1[['Substance', 'Name']]
  2. .merge(df2.drop(columns='Substance')
  3. .groupby('Name', as_index=False).first(),
  4. how='left')
  5. )

输出:

  1. Substance Name Region Country Misc
  2. 0 Substance1 Bayer Europe France 910
  3. 1 Substance2 Sanofi Europe Germany 200
  4. 2 Substance1 Pfizer Asia India 898
  5. 3 Substance3 AstraZeneca Asia P.R. China 910
  6. 4 Substance2 BionTech North America United States 910
  7. 5 Substance1 Sanofi Europe Germany 200
  8. 6 Substance3 Sanofi Europe Germany 200
  9. 7 Substance2 Bayer Europe France 910
  10. 8 Substance4 Pfizer Asia India 898
英文:

You can use a custom merge:

  1. out = (df1[['Substance', 'Name']]
  2. .merge(df2.drop(columns='Substance')
  3. .groupby('Name', as_index=False).first(),
  4. how='left')
  5. )

Output:

  1. Substance Name Region Country Misc
  2. 0 Substance1 Bayer Europe France 910
  3. 1 Substance2 Sanofi Europe Germany 200
  4. 2 Substance1 Pfizer Asia India 898
  5. 3 Substance3 AstraZeneca Asia P.R. China 910
  6. 4 Substance2 BionTech North America United States 910
  7. 5 Substance1 Sanofi Europe Germany 200
  8. 6 Substance3 Sanofi Europe Germany 200
  9. 7 Substance2 Bayer Europe France 910
  10. 8 Substance4 Pfizer Asia India 898

huangapple
  • 本文由 发表于 2023年3月3日 21:00:12
  • 转载请务必保留本文链接:https://go.coder-hub.com/75627401.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定