根据 Pandas 中的列内容连接两个 csv 文件

Posted

技术标签:

【中文标题】根据 Pandas 中的列内容连接两个 csv 文件【英文标题】:Concatenate two csv files based on column content in Pandas 【发布时间】:2022-01-17 06:06:57 【问题描述】:

我有两个带有示例数据的大型 CSV 文件,如下所示:

df1 = 
Index    Fruit   Vegetable    
    0    Mango   Spinach
    1    Berry   Carrot
    2    Banana  Cabbage   
df2 = 
Index   Unit        Price
   0    Mango       30
   1    Artichoke   45
   2    Banana      12
   3    Berry       10
   4    Cabbage     25
   5    Rice        40
   6    Spinach     34
   7    Carrot      08
   8    Lentil      12
   9    Pot         32

我想创建以下数据框:

df3 = 
Index    Fruit   Price      Vegetable    Price   
    0    Mango   30         Spinach      34
    1    Berry   10         Carrot       08   
    2    Banana  12         Cabbage      25

我希望在 df1 中逐行比较每个单位的价格。如果价格在 5 美元以内,我想将它们输出到单独的数据框中,如下所示:

df4 = 
Index    Fruit   Price      Vegetable    Price   
    0    Mango   30         Spinach      34
    1    Berry   10         Carrot       08 

实现这一目标的通用方法是什么?提前谢谢你。

【问题讨论】:

我建议在这里使用两个joins 将来自 df2 的价格信息与 df1 结合起来。 【参考方案1】:

您可以使用replace 基于df2 创建价格数据框,然后使用join 与原始数据连接。

请注意,不鼓励重复的列名:

# print to see what it does
item_prices = dict(zip(df2.Unit, df2.Price))

out = df1.join(df1.replace(item_prices).add_suffix('_Price')).sort_index(axis=1)

输出:

        Fruit  Fruit_Price Vegetable  Vegetable_Price
Index                                                
0       Mango           30   Spinach               34
1       Berry           10    Carrot                8
2      Banana           12   Cabbage               25

对于下一个问题,您需要一个布尔 loc 访问权限:

out[abs(out['Fruit_Price'] - out['Vegetable_Price']) < 5]

query:

out.query('abs(Fruit_Price-Vegetable_Price)<5')

输出:

       Fruit  Fruit_Price Vegetable  Vegetable_Price
Index                                               
0      Mango           30   Spinach               34
1      Berry           10    Carrot                8

【讨论】:

如果 df2 中的单位名称是 Mango_123、Spinach_435 等,对代码的修改是什么。我相信在加入之前应该与 df1 进行字符串匹配,但不知道该怎么做。 【参考方案2】:

您可以使用双重合并:

fruit = df1[['Fruit']].merge(df2.rename(columns='Unit': 'Fruit'), on='Fruit')
veggie = df1[['Vegetable']].merge(df2.rename(columns='Unit': 'Vegetable'), on='Vegetable')

df3 = pd.concat([fruit, veggie], axis=1)
print(df3)

# Output:
    Fruit  Price Vegetable  Price
0   Mango     30   Spinach     34
1   Berry     10    Carrot      8
2  Banana     12   Cabbage     25

然后

df4 = df3[np.abs(np.subtract(*out['Price'].values.T)) <= 5]
print(df4)

# Output:
   Fruit  Price Vegetable  Price
0  Mango     30   Spinach     34
1  Berry     10    Carrot      8

【讨论】:

谢谢,这也有效。但是,我在上面的答案中也发布了一个问题-如果 df2 中的单位名称是 Mango_123、Spinach_435 等,对代码的修改是什么。我相信在加入之前应该与 df1 进行字符串匹配但不确定怎么做。【参考方案3】:

一种通用的替代方法(可以处理任意数量的类别)是在之前(使用melt)和之后(使用pivot)重塑。这样做的好处是可以创建一个非常方便明确识别价格类别的 MultiIndex:

out = (df1.melt(id_vars='Index', value_name='Unit')
          .merge(df2.drop(columns='Index'), on='Unit')
          .pivot(index='Index', columns='variable', values=['Unit', 'Price'])
       )

输出:

            Unit           Price          
variable   Fruit Vegetable Fruit Vegetable
Index                                     
0          Mango   Spinach    30        34
1          Berry    Carrot    10         8
2         Banana   Cabbage    12        25
对 diff ≤ 5 的行进行子集化:
out[out['Price'].diff(axis=1).abs().le(5).any(1)]

输出:

           Unit           Price          
variable  Fruit Vegetable Fruit Vegetable
Index                                    
0         Mango   Spinach    30        34
1         Berry    Carrot    10         8

【讨论】:

以上是关于根据 Pandas 中的列内容连接两个 csv 文件的主要内容,如果未能解决你的问题,请参考以下文章

使用 Pandas [with key column] 将 CSV 与不同的列组合

Pandas:连接多个 .csv 文件并返回聚合了同名列的 Dataframe

使用 pandas 连接两个数据框中的不同列(并附加相似的列)

从两个熊猫系列(csv的列作为DataFrame)创建元素字典

在 read_csv 之后选择 pandas 数据框中的列时出现关键错误

将两个 csv 文件与 python pandas 进行比较