Fügen Sie jedem Wert in einer Zeichenfolgenspalte mit Pandas ein Zeichenfolgenpräfix hinzu

118

Ich möchte eine Zeichenfolge an den Anfang jedes Werts in einer der Spalten eines Pandas-Datenrahmens anhängen (elegant). Ich habe bereits herausgefunden, wie das geht und verwende derzeit:

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

Dies scheint eine verdammt unelegante Sache zu sein - kennen Sie einen anderen Weg (der den Charakter vielleicht auch zu Zeilen hinzufügt, in denen diese Spalte 0 oder NaN ist)?

Falls dies noch unklar ist, möchte ich mich wenden:

    col 
1     a
2     0

in:

       col 
1     stra
2     str0
TheChymera
quelle
Was genau fragst du? Bitte schreiben Sie eine Erklärung darüber, was Ihr Code tut / wünscht
Ryan Saxe
1
Ich dachte, was der Beispielcode macht, war für den durchschnittlichen Pandas-Benutzer sehr klar. Ich habe Anwendungsbeispiele für Ihre Bequemlichkeit hinzugefügt.
TheChymera
3
Ihre Beschreibung steht in gewissem Widerspruch zu Ihrem Code. Was ist != Falselos mit dem Geschäft? Möchten Sie strjeden Wert oder nur einige hinzufügen ?
BrenBarn
auf jeden Wert, wie in meinen Beispieldatenrahmen gezeigt.
TheChymera
1
Ihr Beispiel ist noch etwas unklar. Wollen Sie so etwas df['col'] = 'str' + df['col'].astype(str)?
Roman Pekar

Antworten:

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

Beispiel:

>>> 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
quelle
1
Danke. Bei Interesse unterstützen Datenrahmenindizes auch solche Zeichenfolgenmanipulationen.
Tagoma
2
Wie mache ich das, wenn vor der Verkettung Bedingungen erfüllt sein müssen?
Acecabana
1
@tagoma, nach 4 Jahren Ja: Es werden auch die Datenrahmenindizes unterstützt. Sie können eine neue Spalte erstellen und an den Indexwert anhängen als: df ['col'] = 'str' + df.index.astype (str)
MEdwin
"astype (str)" kann die Codierung ruinieren, wenn Sie am Ende versuchen, in einer Datei zu speichern.
Raein Hashemi
1
Wenn ich dies und einen anderen Ansatz versuche, erhalte ich eine SettingWithCopyWarning. Gibt es eine Möglichkeit, dies zu vermeiden?
Madan Ivan
13

Alternativ können Sie auch eine applyKombination mit format(oder besser mit F-Strings) verwenden, die ich etwas besser lesbar finde, wenn man zB auch ein Suffix hinzufügen oder das Element selbst manipulieren möchte:

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

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

was auch die gewünschte Ausgabe ergibt:

    col
0  stra
1  str0

Wenn Sie Python 3.6+ verwenden, können Sie auch F-Strings verwenden:

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

die gleiche Ausgabe ergeben.

Die F-String-Version ist fast so schnell wie die Lösung von @ 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)

Die Verwendung formatist jedoch in der Tat viel langsamer:

%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
quelle
gleiches Ergebnis, aber viel langsamer ;-)
Philipp_Kats
1
@Philipp_Kats: Ich habe einige Timings hinzugefügt, danke für den Vorschlag! Es scheint, dass F-Saiten fast genauso schnell sind; formatin der Tat schlechter abschneidet. Wie hast du verglichen?
Cleb
Oh schön! nach meinem Verständnis .applyist es immer entweder so schnell oder langsamer als "direkte" vektorisierte Operationen; Auch wenn sie nicht langsamer sind, ziehe ich es vor, sie nach Möglichkeit zu meiden.
Philipp_Kats
@Philipp_Kats: Ich stimme jedoch zu, in diesem speziellen Fall finde ich es besser lesbar, wenn ich auch ein Suffix hinzufüge, etwas mit sich xselbst mache usw., aber das ist nur eine Frage des Geschmacks ... :)
Cleb
4

Sie können pandas.Series.map verwenden:

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

Es wird das Wort "str" ​​vor allen Ihren Werten anwenden.

Boxtell
quelle
3

Wenn Sie Ihre Tabellendatei mit einem dtype=str
Spaltentyp laden oder in einen String konvertieren, können Sie folgende df['a'] = df['a'].astype(str)
Vorgehensweise verwenden:

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

Dieser Ansatz ermöglicht das Voranstellen, Anhängen und Teilmengenzeichenfolgen von df.
Funktioniert mit Pandas v0.23.4, v0.24.1. Ich weiß nichts über frühere Versionen.

Vasyl Vaskivskyi
quelle
0

Eine andere Lösung mit .loc:

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

Dies ist nicht so schnell wie die oben genannten Lösungen (> 1 ms pro Schleife langsamer), kann jedoch nützlich sein, wenn Sie eine bedingte Änderung benötigen, wie z.

mask = (df['col'] == 0)
df.loc[mask, 'col'] = 'string' + df['col'].astype(str)
Lukas
quelle
Warum das .indexin df[mask].index?
AMC
@AMC, weil Sie für .loc Indizes des Datenrahmens benötigen. Dies bedeutet, dass - df [Maske] einen Datenrahmen zurückgibt, der der Bedingung entspricht, und der Index df [Maske]. Indizes des Datenrahmens zurückgibt. Aber es ist wahr, dass Sie dasselbe auch mit df.loc [(df ['col'] == 'a'), 'col'] oder df.loc [mask, 'col'] tun können.
Lukas
1
denn für .loc benötigen Sie Indizes des Datenrahmens. Wenn es df.loc[mask]funktioniert und es funktioniert, dann .indexist das überflüssig, oder?
AMC
@ AMC genau :). Ich habe die Lösung bearbeitet. Danke dir.
Lukas