【问题标题】:How to filter the rows of a dataframe based on the presence of the column values in a separate dataframe and append columns from the second dataframe如何根据单独数据框中的列值的存在来过滤数据框的行并从第二个数据框中附加列
【发布时间】:2021-06-28 20:43:47
【问题描述】:

我有以下数据框:

数据框 1:

Fruit Vegetable
Mango Spinach
Apple Kale
Watermelon Squash
Peach Zucchini

数据框 2:

Item Price/lb
Mango 2
Spinach 1
Apple 4
Peach 2
Zucchini 1

当两列都不存在于数据框 2 的“项目”系列中时,我想丢弃数据框 1 中的行,并且我想根据数据框 1 和 2 创建以下数据框 3:

Fruit Vegetable Combination Price
Mango Spinach 3
Peach Zucchini 3

数据框 3 中的第三列是数据框 2 中商品价格的总和。

【问题讨论】:

    标签: python pandas dataframe


    【解决方案1】:

    您可以分两步完成:

    1. 屏蔽您的 dataframe1,使其仅包含在 dataframe2.Item 中同时存在水果和蔬菜的行

    2. 使用Series.map获取与剩余行关联的值,并将它们相加得到组合价格。

    # Make our df2 information easier to work with. 
    #  It is now a Series whose index is the Item and values are the prices. 
    #  This allows us to work with it like a dictionary
    >>> item_pricing = df2.set_index("Item")["Price/lb"]
    >>> items = item_pricing.index
    
    # get rows where BOTH fruit is in items & Vegetable is in items
    >>> mask = df1["Fruit"].isin(items) & df1["Vegetable"].isin(items)
    >>> subset = df1.loc[mask].copy()  # .copy() tells pandas we want this subset to be independent of the larger dataframe
    >>> print(subset)
       Fruit Vegetable
    0  Mango   Spinach
    3  Peach  Zucchini
    
    # On each column (fruit and vegetable) use .map to obtain the price of those items
    #  then sum those columns together into a single price
    >>> subset["combo_price"] = subset.apply(lambda s: s.map(item_pricing)).sum(axis=1)
    >>> print(subset)
       Fruit Vegetable  combo_price
    0  Mango   Spinach            3
    3  Peach  Zucchini            3
    

    全部加在一起,没有 cmets:

    item_pricing = df2.set_index("Item")["Price/lb"]
    items = item_pricing.index
    
    mask = df1["Fruit"].isin(items) & df1["Vegetable"].isin(items)
    subset = df1.loc[mask].copy()
    subset["combo_price"] = subset.apply(lambda s: s.map(item_pricing)).sum(axis=1)
    

    【讨论】:

    • 如此优雅的解决方案!它涵盖了大部分。但是,如果 'Price/lb' 列中有 NaN 值,则代码的最后一行不起作用。
    • 我试过 nansum(),但不是解决方案。
    • 嗯,这取决于您要如何计算包含NaN 的组合的价格。此处的代码将导致将具有NaN 的任何内容组合为保持NaN,我认为这是合适的。你想到了什么?
    • 我正在考虑用 0 替换 NaN 值。
    • 用这个item_pricing = df2.set_index("Item")["Price/lb"].fillna(0)替换第一行item_pricing = df2.set_index("Item")["Price/lb"],它应该可以工作。
    【解决方案2】:

    您可以将stack()-map()unstack()-sum() 结合使用:

    df3 = (df1.join(df1
        .stack().map(df2.set_index('Item')['Price/lb'])
        .unstack().sum(axis=1, min_count=2).rename('Combination Price')
    ).dropna())
    
    #    Fruit Vegetable  Combination Price
    # 0  Mango   Spinach                3.0
    # 3  Peach  Zucchini                3.0
    

    分步说明

    堆栈df1,这样我们就可以一次绘制所有价格:

    stacked = df1.stack().map(df2.set_index('Item')['Price/lb'])
    
    # 0  Fruit        2.0
    #    Vegetable    1.0
    # 1  Fruit        4.0
    #    Vegetable    NaN
    # 2  Fruit        NaN
    #    Vegetable    NaN
    # 3  Fruit        2.0
    #    Vegetable    1.0
    # dtype: float64
    

    取消堆叠恢复原始形状:

    unstacked = stacked.unstack()
    
    #    Fruit  Vegetable
    # 0    2.0        1.0
    # 1    4.0        NaN
    # 2    NaN        NaN
    # 3    2.0        1.0
    

    min_count=2 相加,这意味着总和将为 nan,除非存在 2 个值(水果和蔬菜)

    combo = unstacked.sum(axis=1, min_count=2)
    
    # 0    3.0
    # 1    NaN
    # 2    NaN
    # 3    3.0
    # dtype: float64
    

    使用df1 重新加入并删除nan 行:

    df3 = df1.join(combo.rename('Combination Price')).dropna()
    
    #    Fruit Vegetable  Combination Price
    # 0  Mango   Spinach                3.0
    # 3  Peach  Zucchini                3.0
    

    【讨论】:

      【解决方案3】:

      meltmergeunstack 的组合:

      (df1[(df1['Fruit'].isin(df2['Item'])) & (df1['Vegetable'].isin(df2['Item']))]
          .reset_index()
          .melt(id_vars = 'index',value_vars = ['Fruit','Vegetable'])
          .merge(df2,left_on='value',right_on = 'Item')
          .drop(columns = 'Item')
          .set_index(['index','variable']).unstack(level = 1)
          .transform(lambda g: g.assign(Combination_Price=g.xs('Price/lb',axis=1,level=0).sum(axis=1)))
      )
      

      按成分生成组合价格和细分,以防万一

                  value               Price/lb           Combination_Price
      variable    Fruit   Vegetable   Fruit   Vegetable   
      index                   
      0           Mango   Spinach     2       1         3
      3           Peach   Zucchini    2       1         3
      

      【讨论】:

        【解决方案4】:

        您可以使用两个内部连接来执行此操作,如下所示。最终结果包含在df3中。

        df_temp = pd.merge(df1, df2, left_on='Fruit', right_on='Item', how='inner')
        df3 = pd.merge(df_temp, df2, left_on='Vegetable', right_on='Item', how='inner')
        df3['Combined price'] = df3['Price/lb_x'] + df3['Price/lb_y']
        df3.drop(columns = ['Item_x','Price/lb_x','Item_y','Price/lb_y'], inplace = True)
        

        【讨论】:

          猜你喜欢
          • 2020-04-22
          • 1970-01-01
          • 2021-06-06
          • 2019-12-19
          • 2018-11-12
          • 1970-01-01
          • 2021-08-16
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多