Diese Frage wurde bereits beantwortet, aber ich glaube, es wäre gut, einige nützliche Methoden, die zuvor nicht erörtert wurden, in den Mix aufzunehmen und alle bisher vorgeschlagenen Methoden hinsichtlich der Leistung zu vergleichen.
Hier sind einige nützliche Lösungen für dieses Problem in aufsteigender Reihenfolge der Leistung.
Dies ist ein einfacher str.format
Ansatz.
df['baz'] = df.agg('{0[bar]} is {0[foo]}'.format, axis=1)
df
foo bar baz
0 a 1 1 is a
1 b 2 2 is b
2 c 3 3 is c
Sie können hier auch die F-String-Formatierung verwenden:
df['baz'] = df.agg(lambda x: f"{x['bar']} is {x['foo']}", axis=1)
df
foo bar baz
0 a 1 1 is a
1 b 2 2 is b
2 c 3 3 is c
Konvertieren Sie die Spalten so chararrays
, dass sie verkettet werden , und fügen Sie sie dann zusammen.
a = np.char.array(df['bar'].values)
b = np.char.array(df['foo'].values)
df['baz'] = (a + b' is ' + b).astype(str)
df
foo bar baz
0 a 1 1 is a
1 b 2 2 is b
2 c 3 3 is c
Ich kann nicht übertreiben, wie unterschätzt das Listenverständnis bei Pandas ist.
df['baz'] = [str(x) + ' is ' + y for x, y in zip(df['bar'], df['foo'])]
Alternativ mit str.join
concat (wird auch besser skaliert):
df['baz'] = [
' '.join([str(x), 'is', y]) for x, y in zip(df['bar'], df['foo'])]
df
foo bar baz
0 a 1 1 is a
1 b 2 2 is b
2 c 3 3 is c
Listenverständnisse zeichnen sich durch die Manipulation von Zeichenfolgen aus, da Zeichenfolgenoperationen von Natur aus schwer zu vektorisieren sind und die meisten "vektorisierten" Pandas-Funktionen im Grunde genommen Wrapper um Schleifen sind. Ich habe ausführlich über dieses Thema in For-Schleifen mit Pandas geschrieben - Wann sollte es mich interessieren? . Wenn Sie sich keine Gedanken über die Indexausrichtung machen müssen, verwenden Sie im Allgemeinen ein Listenverständnis, wenn Sie mit Zeichenfolgen- und Regex-Operationen arbeiten.
Die obige Liste enthält standardmäßig keine NaNs. Sie können jedoch jederzeit eine Funktion schreiben, die einen Versuch umschließt, es sei denn, Sie müssen damit umgehen.
def try_concat(x, y):
try:
return str(x) + ' is ' + y
except (ValueError, TypeError):
return np.nan
df['baz'] = [try_concat(x, y) for x, y in zip(df['bar'], df['foo'])]
perfplot
Leistungsmessungen
Grafik erstellt mit Perfplot . Hier ist die vollständige Codeliste .
Funktionen
def brenbarn(df):
return df.assign(baz=df.bar.map(str) + " is " + df.foo)
def danielvelkov(df):
return df.assign(baz=df.apply(
lambda x:'%s is %s' % (x['bar'],x['foo']),axis=1))
def chrimuelle(df):
return df.assign(
baz=df['bar'].astype(str).str.cat(df['foo'].values, sep=' is '))
def vladimiryashin(df):
return df.assign(baz=df.astype(str).apply(lambda x: ' is '.join(x), axis=1))
def erickfis(df):
return df.assign(
baz=df.apply(lambda x: f"{x['bar']} is {x['foo']}", axis=1))
def cs1_format(df):
return df.assign(baz=df.agg('{0[bar]} is {0[foo]}'.format, axis=1))
def cs1_fstrings(df):
return df.assign(baz=df.agg(lambda x: f"{x['bar']} is {x['foo']}", axis=1))
def cs2(df):
a = np.char.array(df['bar'].values)
b = np.char.array(df['foo'].values)
return df.assign(baz=(a + b' is ' + b).astype(str))
def cs3(df):
return df.assign(
baz=[str(x) + ' is ' + y for x, y in zip(df['bar'], df['foo'])])
df['bar'].tolist()
unddf['foo'].tolist()
in zu verwendencs3()
? Ich vermute, dass es die "Basis" -Zeit leicht erhöhen würde, aber es würde besser skalieren.Das Problem in Ihrem Code ist, dass Sie die Operation auf jede Zeile anwenden möchten. Die Art und Weise, wie Sie es geschrieben haben, nimmt die gesamten Spalten 'bar' und 'foo', konvertiert sie in Zeichenfolgen und gibt Ihnen eine große Zeichenfolge zurück. Sie können es schreiben wie:
df.apply(lambda x:'%s is %s' % (x['bar'],x['foo']),axis=1)
Es ist länger als die andere Antwort, aber allgemeiner (kann mit Werten verwendet werden, die keine Zeichenfolgen sind).
quelle
Sie könnten auch verwenden
df['bar'] = df['bar'].str.cat(df['foo'].values.astype(str), sep=' is ')
quelle
df['bar'] = df['bar'].astype(str).str.cat(df['foo'], sep=' is ')
.df.astype(str).apply(lambda x: ' is '.join(x), axis=1) 0 1 is a 1 2 is b 2 3 is c dtype: object
quelle
@ DanielVelkov Antwort ist die richtige, aber die Verwendung von String-Literalen ist schneller:
# Daniel's %timeit df.apply(lambda x:'%s is %s' % (x['bar'],x['foo']),axis=1) ## 963 µs ± 157 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each) # String literals - python 3 %timeit df.apply(lambda x: f"{x['bar']} is {x['foo']}", axis=1) ## 849 µs ± 4.28 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
quelle
series.str.cat
ist der flexibelste Weg, um dieses Problem anzugehen:Zum
df = pd.DataFrame({'foo':['a','b','c'], 'bar':[1, 2, 3]})
df.foo.str.cat(df.bar.astype(str), sep=' is ') >>> 0 a is 1 1 b is 2 2 c is 3 Name: foo, dtype: object
ODER
df.bar.astype(str).str.cat(df.foo, sep=' is ') >>> 0 1 is a 1 2 is b 2 3 is c Name: bar, dtype: object
Am wichtigsten (und anders als
.join()
) ist, dass Sie damitNull
Werte ignorieren oder durch denna_rep
Parameter ersetzen können .quelle
.join()
verwirrt mich