Les Pandas conditionnelle création d'une série/dataframe colonne
J'ai un dataframe le long des lignes de:
Type Set
1 A Z
2 B Z
3 B X
4 C Y
Je veux ajouter une autre colonne sur le dataframe (ou générer une série) de la même longueur que le dataframe (égal (=nombre d'enregistrements/lignes) qui définit une couleur verte si la valeur = 'Z' et 'rouge' si la valeur = sinon.
Quelle est la meilleure façon de le faire?
Vous devez vous connecter pour publier un commentaire.
Si vous n'avez que deux choix pour sélectionner à partir de:
Par exemple,
rendements
Si vous avez plus de deux conditions, alors, utiliser
np.sélectionnez
. Par exemple, si vous voulezcolor
êtreyellow
quand(df['Set'] == 'Z') & (df['Type'] == 'A')
blue
quand(df['Set'] == 'Z') & (df['Type'] == 'B')
purple
quand(df['Type'] == 'B')
black
,ensuite utiliser
qui donne
&
au lieu deand
. Voir stackoverflow.com/q/13589390/190597df['foo'] = np.where(df['Set']=='Z', df['Set'], df['Type'].shift(1))
df.color = np.where(...)
pour créer une nouvelle colonne? Si vous n'avez, aucune nouvelle colonne a été créé. Au lieu de cela,df
obtient un attribut nommécolor
qui est attribué à un tableau NumPy. En revanche,df['color'] = np.where(...)
créer un nouveau DataFrame de la colonne. Puisdf.color
serait le retour de la Sériedf['color']
. Cette asymétrie dans le comportement dedf['color']
vsdf.color
est (je crois) une raison de ne jamais utiliser la syntaxe à point pour accéder à des colonnes. L'enregistrement d'un clavier n'est pas la peine de cette confusion mentale.np.where
retourne toujours un tableau NumPy. Lorsque vous affectez des valeurs d'un DataFrame colonne à l'aide dedf['color'] = ...
, et, plus tard, le récupérer à l'aide dedf['color']
que vous obtenez en retour une Série à la place.last
oumean
(pour n'en nommer que quelques-uns) le même quefoo
parce quelast
etmean
sont des noms de méthode.df.last
à juste titre renvoie à la méthode. Donc, si vous utilisez la syntaxe à point, vous devez avoir une mémoire parfaite hors tension tous les DataFrame noms d'attribut, sinon vous allez être constamment l'écriture du code bogué, pouvant écraser les méthodes avec les valeurs de la colonne....</rant> 🙂df.Set.map(lambda x: ...)
comme proposé dans la réponse par @cheekybastard ci-dessous?df['Set'].map(lambda x: ...)
est "pure Pandas" je ne vois pas vraiment l'attraction en remplacement denp.where
avec une fonction lambda. (Sous le capot,map
a appeler lelambda
fonction dans une boucle. Plusieurs appels à une fonction lambda ont tendance à être plus lent que 1 appel ànp.where
.) Pour moi, la partie vraiment intéressante de cheekbastard réponse est un pure Python compréhension de liste beatsnp.where
pour une large gamme d'entrées.Series.str.contains
.np.select(conditions, choices, default="foo")
. Pourquoi est-PyCharm avertissement sistr
est validenp.ScalarType
?np.select
sera de retour, mais fait une erreur dans ce cas. Je n'utilise pas PyCharm donc je ne peux pas tester, mais vous voudrez peut-être regarder ici pour des moyens pour supprimer cette alerte.conditions = [(mydata['column'] in someList), (mydata['column'] in someOtherList)]
Cependant, alors j'obtiens l'erreur suivante:The truth value of a Series is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all().
Pourquoi ma solution ne fonctionne pas pour moi?in
opérateur renvoie une seule valeur True/False. Je suppose que vous voulez(mydata['column'] in someList)
pour retourner un tableau ressemblant à de Vraies/Fausses valeurs, une valeur booléenne pour chaque valeur demydata['column']
. Pour cela, utilisez leSeries.isin
méthode:conditions = [(mydata['column'].isin(someList)), (mydata['column'].isin(someOtherList))]
ValueError: The truth value of an array is ambiguous
voir ce post.Compréhension de liste est une autre façon de créer une autre colonne conditionnelle. Si vous travaillez avec un objet dtypes dans les colonnes, comme dans votre exemple, les interprétations de la liste typiquement surpasser la plupart des autres méthodes.
Exemple de liste de la compréhension: l'
%timeit tests:
pd.DataFrame({'Type':list('ABBC')*100000, 'Set':list('ZZXY')*100000})
-taille),numpy.where
dépassemap
, mais la compréhension de liste est roi (environ 50% plus rapide quenumpy.where
).df['color'] = ['red' if (x['Set'] == 'Z') & (x['Type'] == 'B') else 'green' for x in df]
df['color_type'] = np.where(df['Set']=='Z', 'green', df['Type'])
Voici encore une autre façon de la peau, ce chat, à l'aide d'un dictionnaire à la carte, de nouvelles valeurs sur les touches dans la liste:
À quoi il ressemble:
Cette approche peut être très puissant lorsque vous avez de nombreux
ifelse
-type de déclarations à faire (c'est à dire de nombreuses valeurs uniques à remplacer).Et bien sûr, vous pourriez faire ceci:
Mais cette approche est plus de trois fois plus lent que le
apply
approche à partir de ci-dessus, sur ma machine.Et vous pourriez aussi le faire, à l'aide de
dict.get
:Une autre façon dont cela pourrait être réalisé est
La suite est plus lent que les approches chronométré ici, mais nous pouvons calculer la colonne supplémentaire basé sur le contenu de plus d'une colonne, et plus de deux valeurs peuvent être calculées pour la colonne supplémentaire.
Exemple Simple en utilisant simplement le "Set" de la colonne:
Exemple avec plus de couleurs et plus de colonnes pris en compte:
Modifier (21/06/2019): à l'Aide de plydata
Il est également possible d'utiliser plydata pour faire ce genre de choses (ce qui semble encore plus lent que d'utiliser
assign
etapply
, tout de même).Simple
if_else
:Imbriquée
if_else
:Peut-être que cela a été possible avec les nouvelles mises à jour de Panda, mais je pense que ce qui suit est le plus court et peut-être la meilleure réponse pour la question, jusqu'à présent. Vous pouvez utiliser une condition ou plusieurs en fonction de votre besoin.
df.loc[(df['Set']=="Z") & (df['Type']=="A"), 'Color'] = "green"
Un liner avec
.apply()
méthode est la suivante:Après,
df
bloc de données ressemble à ceci: