Je souhaite ajouter une balise de texte à une nouvelle colonne dans une trame de données Pandas. L'exemple suivant fonctionne mais j'obtiens l'avertissement de copie et je ne comprends pas très bien si je dois l'ignorer dans ce cas.

Le DataFrame a simplement un caractère ou est une chaîne vide:

In [1]: import pandas as pd

In [2]: df=pd.DataFrame({('A'):['x','','x',''], ('B'):['x','x','','']})

In [3]: df
Out[3]:
   A  B
0  x  x
1     x
2  x
3

Créez une nouvelle colonne appelée «msg»

In [4]: df['msg'] = ''

In [5]: df
Out[5]:
   A  B msg
0  x  x
1     x
2  x
3

Définissez la colonne 'msg' sur 'rouge' si 'A' n'est pas une chaîne vide

In [6]: df['msg'][df['A'] != ''] = 'red;'

In [7]: df
Out[7]:
   A  B  msg
0  x  x  red;
1     x
2  x     red;
3

Concaténer «bleu» en fonction des valeurs de la colonne «B»

In [8]: df['msg'][df['B'] != ''] += 'blue;'

In [9]: df
Out[9]:
   A  B       msg
0  x  x  red;blue;
1     x     blue;
2  x         red;
3

Alternativement, j'ai trouvé que l'utilisation de numpy.where a produit le résultat souhaité. Quelle est la bonne façon de procéder dans Pandas?

import numpy as np

df['msg'] += np.where(df['A'] != '','green;', '')

Mise à jour: 15/04/2018

Après mûre réflexion, il serait utile de conserver les données du DataFrame d'origine dans certains cas, tout en attachant une étiquette («couleur» dans cet exemple). La réponse de @COLDSPEED m'a conduit à ce qui suit (changer 'bleu;' en 'bleu:' et conserver les données de la colonne 'B' à inclure dans la balise dans ce cas):

df['msg'] = (v.where(df.applymap(len) > 0, '') + 
             df.where(df[['B']].applymap(len)>0,'')).agg(''.join, axis=1)


   A  B         msg
0  x  x  red;blue:x
1     x      blue:x
2  x           red;
3
4
Robert 15 avril 2018 à 03:23

3 réponses

Meilleure réponse

Si vous connaissez vos couleurs à l'avance, vous pouvez utiliser le masquage avec DataFrame.where et str.join pour y parvenir.

v = pd.DataFrame(
     np.repeat([['red;', 'blue;']], len(df), axis=0), 
     columns=df.columns, 
     index=df.index
) 
df['msg'] = v.where(df.applymap(len) > 0, '').agg(''.join, axis=1)
df
   A  B        msg
0  x  x  red;blue;
1     x      blue;
2  x          red;
3              
4
cs95 15 avril 2018 à 00:38

Utilisation de pandas.DataFrame.dot
Remarque spéciale que j'ai défini le dtype du tableau sur object. Sinon, le dot ne fonctionnera pas.

a = np.array(['red', 'blue;'], object)

df.assign(msg=df.astype(bool).dot(a))

   A  B        msg
0  x  x  red;blue;
1     x      blue;
2  x          red;
3                 
4
piRSquared 15 avril 2018 à 02:02

Vous pouvez utiliser dot et replace

(df!='').dot(df.columns).replace({'A':'red;','B':'blue;'},regex=True)
Out[379]: 
0    red;blue;
1        blue;
2         red;
3             
dtype: object

#df['msg']=(df!='').dot(df.columns).replace({'A':'red;','B':'blue;'},regex=True)
4
YOBEN_S 15 avril 2018 à 02:14