La solution acceptée va être extrêmement lente pour beaucoup de données. La solution avec le plus grand nombre de votes positifs est un peu difficile à lire et également lente avec les données numériques. Si chaque nouvelle colonne peut être calculée indépendamment des autres, je voudrais simplement attribuer chacune d'elles directement sans utiliser apply.
Exemple avec de fausses données de caractère
Créez 100 000 chaînes dans un 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
Supposons que nous voulions extraire certaines fonctionnalités de texte comme cela a été fait dans la question d'origine. Par exemple, extrayons le premier caractère, comptons l'occurrence de la lettre «e» et mettons en majuscule la phrase.
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)
Étonnamment, vous pouvez obtenir de meilleures performances en parcourant chaque valeur
%%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)
Un autre exemple avec de fausses données numériques
Créez 1 million de nombres aléatoires et testez la powersfonction d'en haut.
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)
L'attribution de chaque colonne est 25 fois plus rapide et très lisible:
%%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)
J'ai fait une réponse similaire avec plus de détails ici sur pourquoi ce applyn'est généralement pas la voie à suivre.
df.ix[: ,10:16]. Je pense que vous devrez intégrermergevos fonctionnalités dans l'ensemble de données.