ajouter un préfixe de chaîne à chaque valeur dans une colonne de chaîne à l'aide de Pandas

119

Je voudrais ajouter une chaîne au début de chaque valeur dans une dite colonne d'un dataframe pandas (élégamment). J'ai déjà compris comment faire cela et j'utilise actuellement:

df.ix[(df['col'] != False), 'col'] = 'str'+df[(df['col'] != False), 'col']

Cela semble une sacrée chose inélégante à faire - connaissez-vous une autre façon (qui ajoute peut-être également le caractère aux lignes où cette colonne est 0 ou NaN)?

Au cas où cela ne serait pas encore clair, je voudrais tourner:

    col 
1     a
2     0

dans:

       col 
1     stra
2     str0
TheChymera
la source
Que demandez-vous exactement? s'il vous plaît écrivez une explication sur ce que votre code fait / souhaite qu'il fasse
Ryan Saxe
1
Je pensais que ce que faisait l'exemple de code était très clair pour l'utilisateur moyen des pandas. J'ai ajouté des exemples de cas d'utilisation pour votre commodité.
TheChymera
3
Votre description est quelque peu en contradiction avec votre code. Qu'est-ce qui se passe avec l' != Falseentreprise? Voulez-vous ajouter strà chaque valeur ou seulement une partie?
BrenBarn
à chaque valeur, comme indiqué dans mes exemples de dataframes.
TheChymera
1
votre exemple est encore un peu flou, voulez-vous quelque chose comme df['col'] = 'str' + df['col'].astype(str)?
Roman Pekar

Réponses:

223
df['col'] = 'str' + df['col'].astype(str)

Exemple:

>>> df = pd.DataFrame({'col':['a',0]})
>>> df
  col
0   a
1   0
>>> df['col'] = 'str' + df['col'].astype(str)
>>> df
    col
0  stra
1  str0
Roman Pekar
la source
1
Merci. s'ils présentent un intérêt, les index dataframe prennent également en charge de telles manipulations de chaînes.
tagoma
2
Comment faire cela si les conditions doivent être remplies avant la concaténation?
acecabana
1
@tagoma, après 4 ans, Oui: il supporte également les index dataframe. Vous pouvez créer une nouvelle colonne et l'ajouter à la valeur d'index comme suit: df ['col'] = 'str' + df.index.astype (str)
MEdwin
"astype (str)" peut ruiner l'encodage si vous essayez d'enregistrer dans un fichier à la fin.
Raein Hashemi
2
Lorsque j'essaye cela ainsi que toute autre approche, j'obtiens un SettingWithCopyWarning. Y a-t-il un moyen de l'éviter?
Madan Ivan
13

Comme alternative, vous pouvez également utiliser un applycombiné avec format(ou mieux avec des f-strings) que je trouve légèrement plus lisible si, par exemple, on veut également ajouter un suffixe ou manipuler l'élément lui-même:

df = pd.DataFrame({'col':['a', 0]})

df['col'] = df['col'].apply(lambda x: "{}{}".format('str', x))

qui donne également la sortie souhaitée:

    col
0  stra
1  str0

Si vous utilisez Python 3.6+, vous pouvez également utiliser des chaînes f:

df['col'] = df['col'].apply(lambda x: f"str{x}")

produisant le même résultat.

La version f-string est presque aussi rapide que la solution de @ RomanPekar (python 3.6.4):

df = pd.DataFrame({'col':['a', 0]*200000})

%timeit df['col'].apply(lambda x: f"str{x}")
117 ms ± 451 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)

%timeit 'str' + df['col'].astype(str)
112 ms ± 1.04 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

L'utilisation format, cependant, est en effet beaucoup plus lente:

%timeit df['col'].apply(lambda x: "{}{}".format('str', x))
185 ms ± 1.07 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
Cleb
la source
même résultat, mais beaucoup plus lent ;-)
Philipp_Kats
1
@Philipp_Kats: J'ai ajouté quelques horaires, merci pour la suggestion! Il semble que les f-strings soient presque aussi rapides; formatfonctionne en effet pire. Comment avez-vous comparé?
Cleb
Oh sympa! dans ma compréhension .applyest toujours soit aussi rapide ou plus lent que les opérations vectorisées «directes»; même s'ils ne sont pas plus lents, je préfère les éviter dans la mesure du possible.
Philipp_Kats
@Philipp_Kats: Je suis d'accord, cependant, dans ce cas particulier, je le trouve plus lisible lorsque j'ajoute aussi un suffixe, que je fais quelque chose avec xlui-même etc., mais c'est juste une question de goût ... :)
Cleb
4

Vous pouvez utiliser pandas.Series.map:

df['col'].map('str{}'.format)

Il appliquera le mot «str» avant toutes vos valeurs.

Boxtell
la source
3

Si vous chargez votre fichier de table avec dtype=str
ou convertissez le type de colonne en chaîne, df['a'] = df['a'].astype(str)
vous pouvez utiliser une telle approche:

df['a']= 'col' + df['a'].str[:]

Cette approche permet d'ajouter une chaîne de préfixe, d'ajout et de sous-ensemble de df.
Fonctionne sur Pandas v0.23.4, v0.24.1. Je ne connais pas les versions antérieures.

Vasyl Vaskivskyi
la source
0

Une autre solution avec .loc:

df = pd.DataFrame({'col': ['a', 0]})
df.loc[df.index, 'col'] = 'string' + df['col'].astype(str)

Ce n'est pas aussi rapide que les solutions ci-dessus (> 1 ms par boucle plus lent) mais peut être utile au cas où vous auriez besoin d'un changement conditionnel, comme:

mask = (df['col'] == 0)
df.loc[mask, 'col'] = 'string' + df['col'].astype(str)
Lukas
la source
Pourquoi le .indexdans df[mask].index?
AMC le
@AMC car pour .loc vous avez besoin d'index de la dataframe. Cela signifie - df [masque] renvoie la trame de données correspondant à la condition et df [masque] .index renvoie les indices de la trame de données. Mais c'est vrai que vous pouvez faire la même chose avec df.loc [(df ['col'] == 'a'), 'col'] ou df.loc [mask, 'col'] aussi.
Lukas le
1
car pour .loc vous avez besoin d'index de la dataframe. Si df.loc[mask]ça marche, et ça marche, alors .indexc'est superflu, non?
AMC
@AMC exactement :). J'ai édité la solution. Je vous remercie.
Lukas le