【问题标题】:Pandas mathematical operation, conditional on column valuePandas 数学运算,以列值为条件
【发布时间】:2018-12-04 16:02:54
【问题描述】:

我需要根据第二列中的值进行数学运算。这是设置。

给定一个简单的数据框 (df):

df = pd.DataFrame({
    'col1' : ['A', 'A', 'B', np.nan, 'D', 'C'],
    'col2' : [2, 1, 9, 8, 7, 4],
    'col3': [0, 1, 9, 4, 2, 3],
    })

In [11]: df
Out[11]: 
  col1  col2  col3
0    A     2     0
1    A     1     1
2    B     9     9
3  NaN     8     4
4    D     7     2
5    C     4     3

我可以添加一个新列 (math),然后用基于 10 和 col3 之和的数学表达式填充它。

df['math'] = 10 + df['col3']

In [14]: df
Out[14]: 
  col1  col2  col3  math
0    A     2     0    10
1    A     1     1    11
2    B     9     9    19
3  NaN     8     4    14
4    D     7     2    12
5    C     4     3    13

但我不知道如何使表达式以另一列中的值为条件(例如,仅当 col1 == B 时)。期望的输出是:

In [14]: df
Out[14]: 
  col1  col2  col3  math
0    A     2     0   NaN
1    A     1     1   NaN
2    B     9     9    19
3  NaN     8     4   NaN
4    D     7     2   NaN
5    C     4     3   NaN

为了进一步说明,我将在for loop 中使用col1 值的变量。结果,我无法让.group_by()herehere 所描述的那样工作。我想我正在寻找这样的东西......

df['math'] = 10 + df.loc[[df['col1'] == my_var], 'col3']

我从上面第二个示例中的评论中得到 - 但我无法让它工作。它会为太多值抛出ValueError - 也就是说,我试图同时传递过滤器和操作列,但它只期待过滤器。 This SO 帖子也使用类似于我上面的表达式的.loc - 但使用静态col1

【问题讨论】:

  • 你的表达几乎是对的。你的意思是df.loc[:,'math'] = 10 + df.loc[df['col1'] == "B", 'col3']
  • @RafaelC,事实上,这就是我想要做的。至少在右手边。 df['math']df.loc[:, 'math'] 有什么区别?

标签: python pandas


【解决方案1】:

使用 loc

df['math'] = df.loc[df.col1.eq('B'), 'col3'].add(10)

  col1  col2  col3  math
0    A     2     0   NaN
1    A     1     1   NaN
2    B     9     9  19.0
3  NaN     8     4   NaN
4    D     7     2   NaN
5    C     4     3   NaN

【讨论】:

  • df.loc[df.col1=="B", "math"] = df.col3+10
  • 嗯,不知道你可以创建这样的列,谢谢你的提示!
【解决方案2】:

where

我执行数学运算,然后通过传递布尔系列 df.col1.eq('B') 使用 pandas.Series.where 将其屏蔽

df.assign(math=df.col3.add(10).where(df.col1.eq('B')))

  col1  col2  col3  math
0    A     2     0   NaN
1    A     1     1   NaN
2    B     9     9  19.0
3  NaN     8     4   NaN
4    D     7     2   NaN
5    C     4     3   NaN

【讨论】:

    【解决方案3】:

    使用:(不是一种安全的实现方式,请参阅下面的评论)

    df['New']=df.col3[df.col1=='B']+10
    df
    Out[11]: 
      col1  col2  col3   New
    0    A     2     0   NaN
    1    A     1     1   NaN
    2    B     9     9  19.0
    3  NaN     8     4   NaN
    4    D     7     2   NaN
    5    C     4     3   NaN
    

    更新

    pd.concat([df,(df.col3[df.col1=='B']+10).to_frame('New')],1)
    Out[51]: 
      col1  col2  col3   New
    0    A     2     0   NaN
    1    A     1     1   NaN
    2    B     9     9  19.0
    3  NaN     8     4   NaN
    4    D     7     2   NaN
    5    C     4     3   NaN
    

    【讨论】:

    • 这不是一个好的索引方法。仅使用 loc 或 iloc。不要像这样混合索引器。
    • @coldspeed 是的,我知道你的意思,现在怎么样 :-)
    • 问题是df.col3[df.col1=='B'] 可以用df.loc[df.col1=='B', 'col3'] 完成。虽然在这里无关紧要,但在其他地方可能很重要(产生 SettingWithCopyWarnings),而且你已经比你需要的更复杂了:)
    • @coldspeed 是的,没错,当 df 是其他 dfs 的子集时,我们肯定会收到警告消息
    【解决方案4】:

    我还能够做到以下几点......

    df['math'] = 10 + df.loc[df['col1'] == 'B']['col3']  
    

    这是上面@user3483203 答案的变体。最终,我的'B' 是一个变量,所以我为@RafaelC 的cmets 进行了修改。

    【讨论】:

      【解决方案5】:

      它正在抛出 ValueError,因为您没有正确使用 loc。这是使用 loc 的解决方案:

      df.loc[:,'math'] = 10 + df.loc[df['col1'] == "B", 'col3']
      

      输出:

       col1 col2 col3 math
      0    A   2   0    NaN
      1    A   1   1    NaN
      2    B   9   9    19.0
      3    NaN 8   4    NaN
      4    D   7   2    NaN
      5    C   4   3    NaN
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-10-14
        • 2017-08-20
        • 1970-01-01
        • 2010-10-19
        • 2015-09-19
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多