Die akzeptierte Lösung wird für viele Daten extrem langsam sein. Die Lösung mit der größten Anzahl von Upvotes ist etwas schwer zu lesen und auch mit numerischen Daten langsam. Wenn jede neue Spalte unabhängig von den anderen berechnet werden kann, würde ich sie einfach direkt zuweisen, ohne sie zu verwendenapply
.
Beispiel mit gefälschten Zeichendaten
Erstellen Sie 100.000 Zeichenfolgen in einem DataFrame
df = pd.DataFrame(np.random.choice(['he jumped', 'she ran', 'they hiked'],
size=100000, replace=True),
columns=['words'])
df.head()
words
0 she ran
1 she ran
2 they hiked
3 they hiked
4 they hiked
Angenommen, wir wollten einige Textfunktionen extrahieren, wie in der ursprünglichen Frage beschrieben. Lassen Sie uns zum Beispiel das erste Zeichen extrahieren, das Vorkommen des Buchstabens 'e' zählen und die Phrase groß schreiben.
df['first'] = df['words'].str[0]
df['count_e'] = df['words'].str.count('e')
df['cap'] = df['words'].str.capitalize()
df.head()
words first count_e cap
0 she ran s 1 She ran
1 she ran s 1 She ran
2 they hiked t 2 They hiked
3 they hiked t 2 They hiked
4 they hiked t 2 They hiked
Timings
%%timeit
df['first'] = df['words'].str[0]
df['count_e'] = df['words'].str.count('e')
df['cap'] = df['words'].str.capitalize()
127 ms ± 585 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
def extract_text_features(x):
return x[0], x.count('e'), x.capitalize()
%timeit df['first'], df['count_e'], df['cap'] = zip(*df['words'].apply(extract_text_features))
101 ms ± 2.96 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
Überraschenderweise können Sie eine bessere Leistung erzielen, indem Sie jeden Wert durchlaufen
%%timeit
a,b,c = [], [], []
for s in df['words']:
a.append(s[0]), b.append(s.count('e')), c.append(s.capitalize())
df['first'] = a
df['count_e'] = b
df['cap'] = c
79.1 ms ± 294 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
Ein weiteres Beispiel mit gefälschten numerischen Daten
Erstellen Sie 1 Million Zufallszahlen und testen Sie die powers
Funktion von oben.
df = pd.DataFrame(np.random.rand(1000000), columns=['num'])
def powers(x):
return x, x**2, x**3, x**4, x**5, x**6
%%timeit
df['p1'], df['p2'], df['p3'], df['p4'], df['p5'], df['p6'] = \
zip(*df['num'].map(powers))
1.35 s ± 83.6 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
Das Zuweisen jeder Spalte ist 25x schneller und gut lesbar:
%%timeit
df['p1'] = df['num'] ** 1
df['p2'] = df['num'] ** 2
df['p3'] = df['num'] ** 3
df['p4'] = df['num'] ** 4
df['p5'] = df['num'] ** 5
df['p6'] = df['num'] ** 6
51.6 ms ± 1.9 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
Ich habe hier eine ähnliche Antwort mit weiteren Details gegeben, warum dies apply
normalerweise nicht der richtige Weg ist.
df.ix[: ,10:16]
. Ich denke, Sie müssenmerge
Ihre Funktionen in den Datensatz aufnehmen.