在pandas中,当满足特定条件时更新行值

194

假设我有以下数据框:

table

对于流编号为2的行,更新 featanother_feat 列的值,最有效的方法是什么?

就是这样吗?

for index, row in df.iterrows():
    if df1.loc[index,'stream'] == 2:
       # do something

如果有超过100列,我该如何操作呢?我不想明确命名要更新的列。我想将每个列的值除以2(流列除外)。

所以说,我的目标是:

将所有stream为2的行的所有值除以2,但不更改流列。

3个回答

339

如果你需要将两列更新为相同的值,我认为你可以使用loc

df1.loc[df1['stream'] == 2, ['feat','another_feat']] = 'aaaa'
print df1
   stream        feat another_feat
a       1  some_value   some_value
b       2        aaaa         aaaa
c       2        aaaa         aaaa
d       3  some_value   some_value

如果您需要单独更新,一个选项是使用:

df1.loc[df1['stream'] == 2, 'feat'] = 10
print df1
   stream        feat another_feat
a       1  some_value   some_value
b       2          10   some_value
c       2          10   some_value
d       3  some_value   some_value

另一个常见的选项是使用numpy.where

df1['feat'] = np.where(df1['stream'] == 2, 10,20)
print df1
   stream  feat another_feat
a       1    20   some_value
b       2    10   some_value
c       2    10   some_value
d       3    20   some_value

编辑:如果您需要在条件为True的情况下分割所有没有stream的列,请使用以下方法:

print df1
   stream  feat  another_feat
a       1     4             5
b       2     4             5
c       2     2             9
d       3     1             7

#filter columns all without stream
cols = [col for col in df1.columns if col != 'stream']
print cols
['feat', 'another_feat']

df1.loc[df1['stream'] == 2, cols ] = df1 / 2
print df1
   stream  feat  another_feat
a       1   4.0           5.0
b       2   2.0           2.5
c       2   1.0           4.5
d       3   1.0           7.0

如果需要使用多个条件,请使用多个numpy.wherenumpy.select

df0 = pd.DataFrame({'Col':[5,0,-6]})

df0['New Col1'] = np.where((df0['Col'] > 0), 'Increasing', 
                          np.where((df0['Col'] < 0), 'Decreasing', 'No Change'))

df0['New Col2'] = np.select([df0['Col'] > 0, df0['Col'] < 0],
                            ['Increasing',  'Decreasing'], 
                            default='No Change')

print (df0)
   Col    New Col1    New Col2
0    5  Increasing  Increasing
1    0   No Change   No Change
2   -6  Decreasing  Decreasing

5
您可以使用.ix执行相同的操作,如下所示:
In [1]: df = pd.DataFrame(np.random.randn(5,4), columns=list('abcd'))

In [2]: df
Out[2]: 
          a         b         c         d
0 -0.323772  0.839542  0.173414 -1.341793
1 -1.001287  0.676910  0.465536  0.229544
2  0.963484 -0.905302 -0.435821  1.934512
3  0.266113 -0.034305 -0.110272 -0.720599
4 -0.522134 -0.913792  1.862832  0.314315

In [3]: df.ix[df.a>0, ['b','c']] = 0

In [4]: df
Out[4]: 
          a         b         c         d
0 -0.323772  0.839542  0.173414 -1.341793
1 -1.001287  0.676910  0.465536  0.229544
2  0.963484  0.000000  0.000000  1.934512
3  0.266113  0.000000  0.000000 -0.720599
4 -0.522134 -0.913792  1.862832  0.314315

编辑

在附加信息后,以下内容将返回满足某些条件的所有列 - 值减半:

>> condition = df.a > 0
>> df[condition][[i for i in df.columns.values if i not in ['a']]].apply(lambda x: x/2)

15
ix现已弃用。 - abcd
将 .ix 改为 .loc,这样它应该可以正常工作。 - wal

0
另一个向量化解决方案是使用mask()方法将对应于stream=2的行减半,并将这些列与仅包含stream列的数据框连接起来:
cols = ['feat', 'another_feat']
df[['stream']].join(df[cols].mask(df['stream'] == 2, lambda x: x/2))

或者你也可以使用 update() 函数更新原始数据框:

df.update(df[cols].mask(df['stream'] == 2, lambda x: x/2))

以上两个代码都执行以下操作:

case1


如果要替换的值是常量(而不是通过函数导出),使用mask()更加简单;例如,下面的代码将所有stream等于1或3的feat值替换为100。1
df[['stream']].join(df.filter(like='feat').mask(df['stream'].isin([1,3]), 100))

case2

1: feat列也可以使用filter()方法进行选择。


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