J'ai un dataframe le long des lignes ci-dessous:
Type Set
1 A Z
2 B Z
3 B X
4 C Y
Je souhaite ajouter une autre colonne à la structure de données (ou générer une série) de la même longueur que la structure de données (= nombre égal d'enregistrements/lignes), qui définit une couleur verte si Set = 'Z' et 'rouge' si Set = sinon .
Quelle est la meilleure façon de faire cela?
Si vous ne pouvez choisir que parmi deux choix:
_df['color'] = np.where(df['Set']=='Z', 'green', 'red')
_
Par exemple,
_import pandas as pd
import numpy as np
df = pd.DataFrame({'Type':list('ABBC'), 'Set':list('ZZXY')})
df['color'] = np.where(df['Set']=='Z', 'green', 'red')
print(df)
_
les rendements
_ Set Type color
0 Z A green
1 Z B green
2 X B red
3 Y C red
_
Si vous avez plus de deux conditions, utilisez np.select
. Par exemple, si vous voulez que color
soit
yellow
quand _(df['Set'] == 'Z') & (df['Type'] == 'A')
_blue
quand _(df['Set'] == 'Z') & (df['Type'] == 'B')
_purple
quand _(df['Type'] == 'B')
_black
,puis utiliser
_df = pd.DataFrame({'Type':list('ABBC'), 'Set':list('ZZXY')})
conditions = [
(df['Set'] == 'Z') & (df['Type'] == 'A'),
(df['Set'] == 'Z') & (df['Type'] == 'B'),
(df['Type'] == 'B')]
choices = ['yellow', 'blue', 'purple']
df['color'] = np.select(conditions, choices, default='black')
print(df)
_
qui donne
_ Set Type color
0 Z A yellow
1 Z B blue
2 X B purple
3 Y C black
_
La compréhension de liste est un autre moyen de créer une autre colonne de manière conditionnelle. Si vous utilisez des types d'objet dans les colonnes, comme dans votre exemple, les compréhensions de liste sont généralement plus performantes que la plupart des autres méthodes.
Exemple de compréhension de liste:
df['color'] = ['red' if x == 'Z' else 'green' for x in df['Set']]
% timeit tests:
import pandas as pd
import numpy as np
df = pd.DataFrame({'Type':list('ABBC'), 'Set':list('ZZXY')})
%timeit df['color'] = ['red' if x == 'Z' else 'green' for x in df['Set']]
%timeit df['color'] = np.where(df['Set']=='Z', 'green', 'red')
%timeit df['color'] = df.Set.map( lambda x: 'red' if x == 'Z' else 'green')
1000 loops, best of 3: 239 µs per loop
1000 loops, best of 3: 523 µs per loop
1000 loops, best of 3: 263 µs per loop
Voici encore un autre moyen d'adapter ce chat, en utilisant un dictionnaire pour mapper de nouvelles valeurs sur les clés de la liste:
def map_values(row, values_dict):
return values_dict[row]
values_dict = {'A': 1, 'B': 2, 'C': 3, 'D': 4}
df = pd.DataFrame({'INDICATOR': ['A', 'B', 'C', 'D'], 'VALUE': [10, 9, 8, 7]})
df['NEW_VALUE'] = df['INDICATOR'].apply(map_values, args = (values_dict,))
A quoi ça ressemble:
df
Out[2]:
INDICATOR VALUE NEW_VALUE
0 A 10 1
1 B 9 2
2 C 8 3
3 D 7 4
Cette approche peut être très puissante lorsque vous avez plusieurs déclarations de type ifelse
- à effectuer (c’est-à-dire de nombreuses valeurs uniques à remplacer).
Et bien sûr, vous pouvez toujours faire ceci:
df['NEW_VALUE'] = df['INDICATOR'].map(values_dict)
Mais cette approche est plus de trois fois plus lente que la apply
approche d’en haut, sur ma machine.
Et vous pouvez aussi le faire en utilisant dict.get
:
df['NEW_VALUE'] = [values_dict.get(v, None) for v in df['INDICATOR']]
Une autre manière d’y parvenir est de
df['color'] = df.Set.map( lambda x: 'red' if x == 'Z' else 'green')
Ce qui suit est plus lent que les approches temporisées ici , mais nous pouvons calculer la colonne supplémentaire en fonction du contenu de plus d'une colonne, et plus de deux valeurs peuvent être calculées pour la colonne supplémentaire.
Exemple simple utilisant uniquement la colonne "Set":
def set_color(row):
if row["Set"] == "Z":
return "red"
else:
return "green"
df = df.assign(color=df.apply(set_color, axis=1))
print(df)
Set Type color
0 Z A red
1 Z B red
2 X B green
3 Y C green
Exemple avec plus de couleurs et plus de colonnes prises en compte:
def set_color(row):
if row["Set"] == "Z":
return "red"
Elif row["Type"] == "C":
return "blue"
else:
return "green"
df = df.assign(color=df.apply(set_color, axis=1))
print(df)
Set Type color
0 Z A red
1 Z B red
2 X B green
3 Y C blue
Il est également possible d'utiliser plydata pour faire ce genre de choses (cela semble encore plus lent que d'utiliser assign
et apply
, cependant).
from plydata import define, if_else
Simple if_else
:
df = define(df, color=if_else('Set=="Z"', '"red"', '"green"'))
print(df)
Set Type color
0 Z A red
1 Z B red
2 X B green
3 Y C green
Nested if_else
:
df = define(df, color=if_else(
'Set=="Z"',
'"red"',
if_else('Type=="C"', '"green"', '"blue"')))
print(df)
Set Type color
0 Z A red
1 Z B red
2 X B blue
3 Y C green
Cela a peut-être été possible avec les nouvelles mises à jour de Pandas, mais je pense que ce qui suit est la réponse la plus courte et peut-être la meilleure pour la question, jusqu'à présent. Vous pouvez utiliser une ou plusieurs conditions selon vos besoins.
df=pd.DataFrame(dict(Type='A B B C'.split(), Set='Z Z X Y'.split()))
df['Color'] = "red"
df.loc[(df['Set']=="Z"), 'Color'] = "green"
print(df)
# result:
Type Set Color
0 A Z green
1 B Z green
2 B X red
3 C Y red