Atualize os valores das linhas onde certas condições são atendidas nos pandas

98

Digamos que eu tenha o seguinte dataframe:

mesa

Qual é a maneira mais eficiente de atualizar os valores das colunas feat e another_feat onde o stream é o número 2 ?

É isso?

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

ATUALIZAÇÃO: O que fazer se eu tiver mais de 100 colunas? Não quero nomear explicitamente as colunas que desejo atualizar. Quero dividir o valor de cada coluna por 2 (exceto para a coluna do fluxo).

Portanto, para deixar claro qual é o meu objetivo:

Dividindo todos os valores por 2 de todas as linhas que têm o fluxo 2, mas não alterando a coluna do fluxo

Stanko
fonte

Respostas:

204

Acho que você pode usar locse precisar atualizar duas colunas com o mesmo valor:

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

Se você precisar de atualização separada, uma opção é usar:

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

Outra opção comum é usar 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

EDITAR: Se você precisar dividir todas as colunas sem streamonde está a condição True, use:

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
jezrael
fonte
Atualizei minha pergunta, tenho mais de 100 colunas, como posso fazer isso?
Stanko
1
@Stanko - Acho que é outra questão - você precisa selecionar essas 100colunas de alguma forma. por exemplo, se precisar das 100primeiras colunas, use df.columns[:100]e depois passe para loc.
jezrael
Não quero necessariamente as primeiras 100 colunas, só quero dividir todos os valores das colunas (exceto a coluna do fluxo) por 2, onde o fluxo é fe 2
Stanko
então a diferença entre loc e np. onde é que loc muda as linhas que apenas satisfazem a condição, mas np. onde tem a instrução if e else, portanto, ele mudará todas as linhas?
Ambleu
1
@Ambleu - exatamente.
jezrael
3

Você pode fazer o mesmo com .ixeste:

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

EDITAR

Após as informações extras, o seguinte retornará todas as colunas - onde alguma condição for atendida - com valores reduzidos à metade:

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

Eu espero que isso ajude!

Thanos
fonte
Isso é possível se eu não tiver muitas colunas, devo dizer que tenho mais de 100 colunas.
Stanko
Testei sua última edição condition = (df.a == -1.001287)esperando que os valores fossem divididos da linha onde, a == -1.001287mas obtive um dataframe vazio.
Stanko
Sim, isso é porque este é apenas o monitor, não o valor real, obter o valor real como este: df.iloc[1,0]. Ou melhor ainda, defina o valor você mesmo e tente novamente:df.iloc[1,0] = 1.2345; condition = df.a == 1.2345
Thanos
Não estou entendendo, por que exatamente condition = (df.a == -1.001287)não funciona?
Stanko
8
ixagora está obsoleto.
dbliss