Comment faire cela chez les pandas:
J'ai une fonction extract_text_features
sur une seule colonne de texte, renvoyant plusieurs colonnes de sortie. Plus précisément, la fonction renvoie 6 valeurs.
La fonction fonctionne, mais il ne semble pas y avoir de type de retour approprié (pandas DataFrame / tableau numpy / liste Python) de sorte que la sortie puisse être correctement affectée df.ix[: ,10:16] = df.textcol.map(extract_text_features)
Je pense donc que je dois revenir à l'itération avec df.iterrows()
, selon cela ?
MISE À JOUR: Itérer avec df.iterrows()
est au moins 20 fois plus lent, j'ai donc abandonné et divisé la fonction en six .map(lambda ...)
appels distincts .
MISE À JOUR 2: cette question a été posée autour de la v0.11.0 . Par conséquent, une grande partie des questions et réponses ne sont pas trop pertinentes.
df.ix[: ,10:16]
. Je pense que vous devrez intégrermerge
vos fonctionnalités dans l'ensemble de données.apply
Réponses:
À partir de la réponse de user1827356, vous pouvez effectuer l'affectation en une seule passe en utilisant
df.merge
:EDIT: Veuillez être conscient de l'énorme consommation de mémoire et de la faible vitesse: https://ys-l.github.io/posts/2015/08/28/how-not-to-use-pandas-apply/ !
la source
Je le fais habituellement en utilisant
zip
:la source
temp = list(zip(*df['num'].map(powers))); for i, c in enumerate(columns): df[c] = temp[c]
for i, c in enumerate(columns): df[c] = temp[i]
. Grâce à cela, j'ai vraiment eu le but deenumerate
: Dzip(*df['col'].map(function))
est probablement la voie à suivre.C'est ce que j'ai fait dans le passé
Modification pour l'exhaustivité
la source
df[['col1', 'col2']] = df['col3'].apply(lambda x: pd.Series('val1', 'val2'))
C'est la manière correcte et la plus simple d'accomplir cela pour 95% des cas d'utilisation:
la source
pd.Series({k:v})
et de sérialiser l'affectation de colonne comme dans la réponse d'Ewan?En 2018, j'utilise
apply()
avec argumentresult_type='expand'
la source
pd.Series
ce qui est toujours agréable en ce qui concerne les problèmes de performancesdf.apply
renvoie adict
, les colonnes sortiront nommées en fonction des clés.Utilisez simplement
result_type="expand"
la source
Résumé: si vous ne souhaitez créer que quelques colonnes, utilisez
df[['new_col1','new_col2']] = df[['data1','data2']].apply( function_of_your_choosing(x), axis=1)
Pour cette solution, le nombre de nouvelles colonnes que vous créez doit être égal au nombre de colonnes que vous utilisez comme entrée pour la fonction .apply (). Si vous voulez faire autre chose, jetez un œil aux autres réponses.
Détails Supposons que vous ayez une trame de données à deux colonnes. La première colonne est la taille d'une personne lorsqu'elle a 10 ans; la seconde est la taille de ladite personne à 20 ans.
Supposons que vous deviez calculer à la fois la moyenne des hauteurs de chaque personne et la somme des hauteurs de chaque personne. Cela représente deux valeurs par ligne.
Vous pouvez le faire via la fonction suivante, qui sera bientôt appliquée:
Vous pouvez utiliser cette fonction comme ceci:
(Pour être clair: cette fonction d'application prend les valeurs de chaque ligne de la trame de données sous-ensemble et renvoie une liste.)
Cependant, si vous procédez ainsi:
vous allez créer 1 nouvelle colonne qui contient les listes [moyenne, somme], que vous voudriez probablement éviter, car cela nécessiterait une autre Lambda / Apply.
Au lieu de cela, vous souhaitez décomposer chaque valeur dans sa propre colonne. Pour ce faire, vous pouvez créer deux colonnes à la fois:
la source
df["mean"], df["sum"] = df[['height_at_age_10','height_at_age_20']] .apply(mean_and_sum(x),axis=1)
return pd.Series([mean,sum])
Pour moi, cela a fonctionné:
Entrée df
Fonction
Créez 2 nouvelles colonnes:
Production:
la source
J'ai cherché plusieurs façons de le faire et la méthode présentée ici (renvoyer une série de pandas) ne semble pas être la plus efficace.
Si nous commençons avec une grande trame de données de données aléatoires:
L'exemple montré ici:
Une méthode alternative:
À mon avis, il est beaucoup plus efficace de prendre une série de tuples, puis de la convertir en DataFrame. Je serais intéressé d'entendre les gens penser s'il y a une erreur dans mon travail.
la source
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
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.
Timings
Étonnamment, vous pouvez obtenir de meilleures performances en parcourant chaque valeur
Un autre exemple avec de fausses données numériques
Créez 1 million de nombres aléatoires et testez la
powers
fonction d'en haut.L'attribution de chaque colonne est 25 fois plus rapide et très lisible:
J'ai fait une réponse similaire avec plus de détails ici sur pourquoi ce
apply
n'est généralement pas la voie à suivre.la source
Ont posté la même réponse dans deux autres questions similaires. La façon dont je préfère le faire est de récapituler les valeurs de retour de la fonction dans une série:
Et puis utilisez Appliquer comme suit pour créer des colonnes distinctes:
la source
vous pouvez renvoyer la ligne entière au lieu de valeurs:
où la fonction renvoie la ligne
la source
extract_text_features
à chaque colonne du df, seulement à la colonne de textedf.textcol
Cela a fonctionné pour moi. Une nouvelle colonne sera créée avec les anciennes données de colonne traitées.
la source