Actualizar los valores de las filas donde se cumplen ciertas condiciones en pandas

96

Digamos que tengo el siguiente marco de datos:

mesa

¿Cuál es la forma más eficiente de actualizar los valores de las columnas feat y another_feat donde el flujo es el número 2 ?

Es esto?

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

ACTUALIZACIÓN: ¿Qué hacer si tengo más de 100 columnas? No quiero nombrar explícitamente las columnas que quiero actualizar. Quiero dividir el valor de cada columna por 2 (excepto la columna de flujo).

Entonces, para tener claro cuál es mi objetivo:

Dividir todos los valores por 2 de todas las filas que tienen el flujo 2, pero sin cambiar la columna del flujo

Stanko
fuente

Respuestas:

199

Creo que puede usar locsi necesita actualizar dos columnas al mismo 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

Si necesita una actualización por separado, use una opción:

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

Otra opción común es 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: Si necesita dividir todas las columnas sin streamdónde está la condición 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
fuente
Actualicé mi pregunta, tengo más de 100 columnas, ¿cómo puedo hacer esto?
Stanko
1
@Stanko: creo que es otra pregunta: debes seleccionar estas 100columnas de alguna manera. por ejemplo, si necesita las 100primeras columnas, use df.columns[:100]y luego pase a loc.
jezrael
No necesariamente quiero las primeras 100 columnas, solo quiero dividir todos los valores de las columnas (excepto la columna de flujo) por 2 donde el flujo es fe 2
Stanko
entonces, la diferencia entre loc y np.¿Dónde está loc cambia las filas que solo satisfacen la condición pero np.¿Dónde tiene la declaración if y else, por lo tanto, cambiará todas las filas?
Ambleu
1
@Ambleu - exactamente.
jezrael
3

Puedes hacer lo mismo con .ix, así:

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

Después de la información adicional, lo siguiente devolverá todas las columnas, donde se cumple alguna condición, con valores reducidos a la mitad:

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

¡Espero que esto ayude!

Thanos
fuente
Esto es factible si no tengo muchas columnas, debería haber dicho que tengo más de 100 columnas.
Stanko
Probé su última edición condition = (df.a == -1.001287)esperando que los valores se dividieran de la fila donde a == -1.001287obtuve un marco de datos vacío.
Stanko
Sí, esto se debe a que esto es sólo la pantalla, no el valor real, obtener el valor real de la siguiente manera: df.iloc[1,0]. O mejor aún, establezca el valor usted mismo y vuelva a intentarlo:df.iloc[1,0] = 1.2345; condition = df.a == 1.2345
Thanos
No estoy siguiendo, ¿por qué exactamente condition = (df.a == -1.001287)no funciona?
Stanko
8
ixahora está en desuso.
dbliss