Pandas数学运算,基于列值的条件。

4
我需要进行一个数学运算,该运算取决于第二列中的值。以下是设置。
给定一个简单的数据框(`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循环中使用一个变量来表示col1的值。因此,我无法按照这里这里描述的那样使.group_by()起作用。我想我需要像这样的东西...
df['math'] = 10 + df.loc[[df['col1'] == my_var], 'col3']

我从上面第二个示例的评论中得到了这个代码,但我无法使其工作。它会抛出一个“ValueError”,因为有太多的值——也就是说,我正在尝试同时传递过滤器和操作列,但它只期望过滤器。这个 Stack Overflow 帖子也使用类似于我上面的表达式的“loc”——但是使用静态的“col1”。

1
你的表达几乎正确。你的意思是 df.loc[:,'math'] = 10 + df.loc[df['col1'] == "B", 'col3'] - rafaelc
@RafaelC,事实上,这正是我想做的。至少在右侧是这样的。df['math']df.loc[:, 'math']之间有什么区别? - Bill Armstrong
5个回答

5

where

我执行数学运算,然后使用 pandas.Series.where 进行掩码处理,通过传递布尔系列 df.col1.eq('B')

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

5
使用 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

2
或者 df.loc[df.col1=="B", "math"] = df.col3+10 - rafaelc
哦,我不知道你可以这样创建列,谢谢你的提示! - user3483203

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。不要混合使用索引器。 - cs95
@coldspeed,是的,我知道你的意思,现在怎么样?:-) - BENY
2
问题出在 df.col3[df.col1=='B'] 语句上,实际上可以用 df.loc[df.col1=='B', 'col3'] 来代替。尽管这里并不会产生影响(只是提示SettingWithCopyWarnings),但在其他地方可能就有影响了。你的代码比必要的复杂了 :) - cs95
@coldspeed 是的,没错。当 df 是其他 dfs 的子集时,我们肯定会收到警告消息。 - BENY

0

由于您没有正确使用 loc,因此它会抛出 ValueError。以下是使用 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

0

我也能做到以下的事情...

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

这是对@user3483203答案的变化。最终,我的'B'是一个变量,所以我根据@RafaelC的评论进行了修改。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接