web-dev-qa-db-fra.com

Utilisation de conditionnel pour générer une nouvelle colonne dans le cadre de données pandas

J'ai un cadre de données de pandas qui ressemble à ceci: 

   portion  used
0        1   1.0
1        2   0.3
2        3   0.0
3        4   0.8

J'aimerais créer une nouvelle colonne basée sur la colonne used, de sorte que la df ressemble à ceci: 

   portion  used    alert
0        1   1.0     Full
1        2   0.3  Partial
2        3   0.0    Empty
3        4   0.8  Partial
  • Créez une nouvelle colonne alert basée sur
  • Si used est 1.0, alert devrait être Full.
  • Si used est 0.0, alert devrait être Empty.
  • Sinon, alert devrait être Partial.

Quelle est la meilleure façon de faire ça?

13
user3786999

Vous pouvez définir une fonction qui renvoie vos différents états "Complet", "Partiel", "Vide", etc., puis utilisez df.apply pour appliquer la fonction à chaque ligne. Notez que vous devez passer le mot clé argument axis=1 pour vous assurer qu'il applique la fonction aux lignes.

import pandas as pd

def alert(c):
  if c['used'] == 1.0:
    return 'Full'
  Elif c['used'] == 0.0:
    return 'Empty'
  Elif 0.0 < c['used'] < 1.0:
    return 'Partial'
  else:
    return 'Undefined'

df = pd.DataFrame(data={'portion':[1, 2, 3, 4], 'used':[1.0, 0.3, 0.0, 0.8]})

df['alert'] = df.apply(alert, axis=1)

#    portion  used    alert
# 0        1   1.0     Full
# 1        2   0.3  Partial
# 2        3   0.0    Empty
# 3        4   0.8  Partial
29
Ffisegydd

Sinon, vous pouvez faire:

import pandas as pd
import numpy as np
df = pd.DataFrame(data={'portion':np.arange(10000), 'used':np.random.Rand(10000)})

%%timeit
df.loc[df['used'] == 1.0, 'alert'] = 'Full'
df.loc[df['used'] == 0.0, 'alert'] = 'Empty'
df.loc[(df['used'] >0.0) & (df['used'] < 1.0), 'alert'] = 'Partial'

Ce qui donne la même sortie mais est environ 100 fois plus rapide sur 10 000 lignes:

100 loops, best of 3: 2.91 ms per loop

Puis en appliquant:

%timeit df['alert'] = df.apply(alert, axis=1)

1 loops, best of 3: 287 ms per loop

Je suppose que le choix dépend de la taille de votre base de données.

22
Primer

Utilisez np.where, est généralement rapide

In [845]: df['alert'] = np.where(df.used == 1, 'Full', 
                                 np.where(df.used == 0, 'Empty', 'Partial'))

In [846]: df
Out[846]:
   portion  used    alert
0        1   1.0     Full
1        2   0.3  Partial
2        3   0.0    Empty
3        4   0.8  Partial

Les horaires

In [848]: df.shape
Out[848]: (100000, 3)

In [849]: %timeit df['alert'] = np.where(df.used == 1, 'Full', np.where(df.used == 0, 'Empty', 'Partial'))
100 loops, best of 3: 6.17 ms per loop

In [850]: %%timeit
     ...: df.loc[df['used'] == 1.0, 'alert'] = 'Full'
     ...: df.loc[df['used'] == 0.0, 'alert'] = 'Empty'
     ...: df.loc[(df['used'] >0.0) & (df['used'] < 1.0), 'alert'] = 'Partial'
     ...:
10 loops, best of 3: 21.9 ms per loop

In [851]: %timeit df['alert'] = df.apply(alert, axis=1)
1 loop, best of 3: 2.79 s per loop
5
Zero

df ['TaxStatus'] = np.where (df.Public == 1, True, np.where (df.Public == 2, False))

Cela semblerait fonctionner, sauf pour ValueError: les deux ou aucun des x et y devraient être donnés

0
user1857373

Je ne peux pas commenter, donc en formulant une nouvelle réponse: En améliorant l'approche de Ffisegydd, vous pouvez utiliser un dictionnaire et la méthode dict.get() pour rendre la fonction à transmettre à .apply() plus facile à gérer:

import pandas as pd

def alert(c):
    mapping = {1.0: 'Full', 0.0: 'Empty'}
    return mapping.get(c['used'], 'Partial')

df = pd.DataFrame(data={'portion':[1, 2, 3, 4], 'used':[1.0, 0.3, 0.0, 0.8]})

df['alert'] = df.apply(alert, axis=1)

Selon le cas d'utilisation, vous souhaiterez peut-être également définir le dict en dehors de la définition de la fonction.

0
Spcogg the second