【问题标题】:I want to multiply two columns in a pandas DataFrame and add the result into a new column我想将 pandas DataFrame 中的两列相乘并将结果添加到新列中
【发布时间】:2012-12-13 02:29:47
【问题描述】:

我正在尝试将 pandas 数据框 (orders_df) 中的两个现有列相乘 - 价格(股票收盘价)和金额(股票数量),并将计算结果添加到名为“价值”的新列中。出于某种原因,当我运行此代码时,“值”列下的所有行都是正数,而某些行应该是负数。在 DataFrame 的 Action 列下,有 7 行带有“Sell”字符串,7 行带有“Buy”字符串。

for i in orders_df.Action:
 if i  == 'Sell':
  orders_df['Value'] = orders_df.Prices*orders_df.Amount
 elif i == 'Buy':
  orders_df['Value'] = -orders_df.Prices*orders_df.Amount)

请让我知道我做错了什么!

【问题讨论】:

    标签: python python-2.7 pandas


    【解决方案1】:

    我认为一个优雅的解决方案是使用where 方法(另见API docs):

    In [37]: values = df.Prices * df.Amount
    
    In [38]: df['Values'] = values.where(df.Action == 'Sell', other=-values)
    
    In [39]: df
    Out[39]: 
       Prices  Amount Action  Values
    0       3      57   Sell     171
    1      89      42   Sell    3738
    2      45      70    Buy   -3150
    3       6      43   Sell     258
    4      60      47   Sell    2820
    5      19      16    Buy    -304
    6      56      89   Sell    4984
    7       3      28    Buy     -84
    8      56      69   Sell    3864
    9      90      49    Buy   -4410
    

    此外,这应该是最快的解决方案。

    【讨论】:

    • 你能指出这回答了你的问题吗?
    • 将此标记为您的答案,@OAK
    • 从性能分析的角度来看,执行此操作的内存高效方法是什么?
    【解决方案2】:

    可以使用DataFrameapply方法:

    order_df['Value'] = order_df.apply(lambda row: (row['Prices']*row['Amount']
                                                   if row['Action']=='Sell'
                                                   else -row['Prices']*row['Amount']),
                                       axis=1)
    

    使用这些方法通常比使用 for 循环更快。

    【讨论】:

      【解决方案3】:

      如果我们愿意牺牲海登解决方案的简洁性,也可以这样做:

      In [22]: orders_df['C'] = orders_df.Action.apply(
                     lambda x: (1 if x == 'Sell' else -1))
      
      In [23]: orders_df   # New column C represents the sign of the transaction
      Out[23]:
         Prices  Amount Action  C
      0       3      57   Sell  1
      1      89      42   Sell  1
      2      45      70    Buy -1
      3       6      43   Sell  1
      4      60      47   Sell  1
      5      19      16    Buy -1
      6      56      89   Sell  1
      7       3      28    Buy -1
      8      56      69   Sell  1
      9      90      49    Buy -1
      

      现在我们不再需要if 语句。使用DataFrame.apply(),我们还取消了for 循环。正如 Hayden 所指出的,矢量化操作总是更快。

      In [24]: orders_df['Value'] = orders_df.Prices * orders_df.Amount * orders_df.C
      
      In [25]: orders_df   # The resulting dataframe
      Out[25]:
         Prices  Amount Action  C  Value
      0       3      57   Sell  1    171
      1      89      42   Sell  1   3738
      2      45      70    Buy -1  -3150
      3       6      43   Sell  1    258
      4      60      47   Sell  1   2820
      5      19      16    Buy -1   -304
      6      56      89   Sell  1   4984
      7       3      28    Buy -1    -84
      8      56      69   Sell  1   3864
      9      90      49    Buy -1  -4410
      

      这个解决方案需要两行代码而不是一行,但更容易阅读。我怀疑计算成本也相似。

      【讨论】:

      • 只是为了挑剔一个应该与符号一致,即如果你在左侧使用df['column_name'],你应该在右侧也这样做,而不是df.column_name。跨度>
      【解决方案4】:

      既然这个问题再次出现,我认为一个很好的干净方法是使用assign

      代码非常富有表现力和自我描述:

      df = df.assign(Value = lambda x: x.Prices * x.Amount * x.Action.replace({'Buy' : 1, 'Sell' : -1}))
      

      【讨论】:

      • 优雅的代码。但是您能否向我解释一下为什么在这种情况下我将使用lambda x 而不是df?从未在熊猫中使用过 lambda。在这种情况下,lambda x 函数的输入是什么?谢谢。
      • 你是对的,在这种情况下,我们可以轻松地使用 df 并摆脱 lambda。老实说,当数据框的名称很长并且表达式变得过于冗长时,我通常使用 lambda。在这种情况下,'df' 足够短!如果 lambda 正好是 df,则输入 'x'
      • 非常感谢!我以前从未在 pandas 中使用过 lambda,所以我不确定。现在我明白了。感谢您澄清它。我会做同样的事情,因为我发现只用 df, df1, df2 等命名数据框不够清楚
      • 在实践中使用 lambda 的另一个优点(这个特殊问题太简单了,无法产生影响)是您可以将转换链接到您的数据框。如果没有 lambda,您必须为每个步骤声明变量,以便您可以引用新的数据框,以便后续调用 assign 或 loc 或许多其他 pandas 函数。
      【解决方案5】:

      为了使事情变得整洁,我采用了 Hayden 的解决方案,但从中制作了一个小功能。

      def create_value(row):
          if row['Action'] == 'Sell':
              return row['Prices'] * row['Amount']
          else:
              return -row['Prices']*row['Amount']
      

      所以当我们想将函数应用到我们的数据框时,我们可以这样做..

      df['Value'] = df.apply(lambda row: create_value(row), axis=1)
      

      ...任何修改只需要在小函数本身中进行。

      简洁、易读、整洁!

      【讨论】:

        【解决方案6】:

        对我来说,这是最清晰、最直观的:

        values = []
        for action in ['Sell','Buy']:
            amounts = orders_df['Amounts'][orders_df['Action'==action]].values
            if action == 'Sell':
                prices = orders_df['Prices'][orders_df['Action'==action]].values
            else:
                prices = -1*orders_df['Prices'][orders_df['Action'==action]].values
            values += list(amounts*prices)  
        orders_df['Values'] = values
        

        .values 方法返回一个numpy array,让您可以轻松地将元素相乘,然后您可以通过“添加”来累积生成一个列表。

        【讨论】:

          【解决方案7】:

          来自 bmu 的好解决方案。我认为将值放在括号内而不是放在括号外更具可读性。

              df['Values'] = np.where(df.Action == 'Sell', 
                                      df.Prices*df.Amount, 
                                     -df.Prices*df.Amount)
          

          使用一些 pandas 的内置函数。

              df['Values'] = np.where(df.Action.eq('Sell'), 
                                      df.Prices.mul(df.Amount), 
                                     -df.Prices.mul(df.Amount))
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2018-07-27
            • 2020-12-31
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2022-01-01
            相关资源
            最近更新 更多