J'ai un pandas dataframe
dans lequel une colonne de chaînes de texte contient des valeurs séparées par des virgules. Je veux diviser chaque champ CSV et créer une nouvelle ligne par entrée (supposez que le CSV est propre et ne doit être divisé que sur ','). Par exemple, a
devrait devenir b
:
In [7]: a
Out[7]:
var1 var2
0 a,b,c 1
1 d,e,f 2
In [8]: b
Out[8]:
var1 var2
0 a 1
1 b 1
2 c 1
3 d 2
4 e 2
5 f 2
Jusqu'à présent, j'ai essayé diverses fonctions simples, mais la .apply
méthode ne semble accepter qu'une seule ligne comme valeur de retour lorsqu'elle est utilisée sur un axe, et je ne peux pas me mettre .transform
au travail. Toute suggestion serait très appréciée!
Exemples de données:
from pandas import DataFrame
import numpy as np
a = DataFrame([{'var1': 'a,b,c', 'var2': 1},
{'var1': 'd,e,f', 'var2': 2}])
b = DataFrame([{'var1': 'a', 'var2': 1},
{'var1': 'b', 'var2': 1},
{'var1': 'c', 'var2': 1},
{'var1': 'd', 'var2': 2},
{'var1': 'e', 'var2': 2},
{'var1': 'f', 'var2': 2}])
Je sais que cela ne fonctionnera pas parce que nous perdons les métadonnées DataFrame en passant par numpy, mais cela devrait vous donner une idée de ce que j'ai essayé de faire:
def fun(row):
letters = row['var1']
letters = letters.split(',')
out = np.array([row] * len(letters))
out['var1'] = letters
a['idx'] = range(a.shape[0])
z = a.groupby('idx')
z.transform(fun)
Réponses:
Que diriez-vous quelque chose comme ça:
Ensuite, il vous suffit de renommer les colonnes
la source
UPDATE2: fonction vectorisée plus générique, qui fonctionnera pour plusieurs
normal
et plusieurslist
colonnesDémo:
Plusieurs
list
colonnes - toutes leslist
colonnes doivent avoir le même nombre d'éléments dans chaque ligne:conservation des valeurs d'index d'origine:
Installer:
Colonne CSV:
en utilisant cette petite astuce, nous pouvons convertir une colonne de type CSV en
list
colonne:MISE À JOUR: approche générique vectorisée (fonctionnera également pour plusieurs colonnes):
DF d'origine:
Solution:
convertissons d'abord les chaînes CSV en listes:
Maintenant, nous pouvons le faire:
VIEILLE réponse:
Inspiré par la solution @AFinkelstein , je voulais le rendre un peu plus généralisé qui pourrait être appliqué à DF avec plus de deux colonnes et aussi rapide, enfin presque, aussi rapide que la solution d'AFinkelstein):
la source
.explode()
méthode dans l'API (voir également cette réponse ).Après une expérimentation douloureuse pour trouver quelque chose de plus rapide que la réponse acceptée, j'ai réussi à travailler. Il a fonctionné environ 100 fois plus vite sur l'ensemble de données sur lequel je l'ai essayé.
Si quelqu'un connaît un moyen de rendre cela plus élégant, modifiez certainement mon code. Je ne pouvais pas trouver un moyen qui fonctionne sans définir les autres colonnes que vous souhaitez conserver comme index, puis réinitialiser l'index et renommer les colonnes, mais j'imagine qu'il y a autre chose qui fonctionne.
la source
TypeError: object of type 'float' has no len()
à la toute première étape (DataFrame(df.var1.str.split(',').tolist())
)NaN
dans cette colonne, donc le remplacement estb = DataFrame(a.var1.str.split(',').values.tolist(), index=a.var2).stack()
Voici une fonction que j'ai écrite pour cette tâche courante. C'est plus efficace que les méthodes
Series
/stack
. L'ordre et les noms des colonnes sont conservés.Avec cette fonction, la question d'origine est aussi simple que:
la source
Pandas> = 0,25
Les méthodes Series et DataFrame définissent une
.explode()
méthode qui fait exploser les listes en lignes distinctes. Voir la section docs sur Exploser une colonne de type liste .Puisque vous avez une liste de chaînes séparées par des virgules, divisez la chaîne sur une virgule pour obtenir une liste d'éléments, puis appelez
explode
cette colonne.Notez que
explode
ne fonctionne que sur une seule colonne (pour l'instant).Les NaN et les listes vides reçoivent le traitement qu'ils méritent sans que vous ayez à sauter à travers des cerceaux pour bien faire les choses.
C'est un sérieux avantage sur les solutions basées sur
ravel
+repeat
(qui ignorent complètement les listes vides et s'étouffent avec les NaN).la source
Question similaire: pandas: comment diviser le texte d'une colonne en plusieurs lignes?
Vous pourriez faire:
la source
s.name = 'var1'
TL; DR
Manifestation
Créons un nouveau dataframe
d
qui a des listesObservations générales
Je vais utiliser
np.arange
avecrepeat
pour produire des positions d'index de trame de données que je peux utiliser aveciloc
.FAQ
Pourquoi je n'utilise pas
loc
?Parce que l'index peut ne pas être unique et l'utilisation
loc
retournera chaque ligne qui correspond à un index interrogé.Pourquoi n'utilisez-vous pas l'
values
attribut et ne le découpez-vous pas?En appelant
values
, si l'intégralité de la trame de données est dans un "bloc" cohérent, Pandas retournera une vue du tableau qui est le "bloc". Sinon, les Pandas devront bricoler un nouveau tableau. Lors du bricolage, ce tableau doit être d'un type uniforme. Cela signifie souvent renvoyer un tableau avec dtypeobject
. En utilisantiloc
au lieu de trancher levalues
attribut, je me soulage de devoir gérer cela.Pourquoi utilisez-vous
assign
?Quand j'utilise
assign
le même nom de colonne que j'explose, j'écrase la colonne existante et conserve sa position dans la trame de données.Pourquoi les valeurs d'index sont-elles répétées?
Grâce à l'utilisation
iloc
sur des positions répétées, l'indice résultant montre le même motif répété. Une répétition pour chaque élément de la liste ou de la chaîne.Cela peut être réinitialisé avec
reset_index(drop=True)
Pour cordes
Je ne veux pas avoir à couper les cordes prématurément. Donc, au lieu de cela, je compte les occurrences de l'
sep
argument en supposant que si je devais diviser, la longueur de la liste résultante serait un de plus que le nombre de séparateurs.J'utilise ensuite cela
sep
pourjoin
les cordessplit
.Pour les listes
Similaire aux chaînes, sauf que je n'ai pas besoin de compter les occurrences
sep
car elles sont déjà divisées.J'utilise Numpy's
concatenate
pour brouiller les listes ensemble.la source
Il est possible de diviser et d'exploser la trame de données sans changer la structure de la trame de données
Contribution:
En dehors:
Édition-1
Réindexation basée sur la colonne de référence et alignement des informations de valeur de colonne avec la pile
En dehors:
la source
J'ai trouvé une solution pour les cadres de données avec un nombre arbitraire de colonnes (tout en ne séparant que les entrées d'une colonne à la fois).
la source
Voici un message assez simple qui utilise la
split
méthode de l'str
accessoire pandas , puis utilise NumPy pour aplatir chaque ligne en un seul tableau.Les valeurs correspondantes sont récupérées en répétant la colonne non fractionnée le nombre correct de fois avec
np.repeat
.la source
J'ai eu du mal avec une expérience de mémoire insuffisante en utilisant diverses façons d'exploser mes listes, j'ai donc préparé des repères pour m'aider à décider quelles réponses à voter. J'ai testé cinq scénarios avec des proportions variables de la longueur de la liste par rapport au nombre de listes. Partager les résultats ci-dessous:
Temps: (moins c'est mieux, cliquez pour voir la grande version)
Utilisation maximale de la mémoire: (moins c'est mieux)
Conclusions :
Tous les détails (fonctions et code de référence) sont dans cet essentiel GitHub . Veuillez noter que le problème de référence a été simplifié et n'incluait pas le fractionnement des chaînes dans la liste - ce que la plupart des solutions ont effectué de manière similaire.
la source
Basé sur l'excellente solution de @ DMulligan , voici une fonction générique vectorisée (sans boucles) qui fractionne une colonne d'une trame de données en plusieurs lignes, et la fusionne à nouveau à la trame de données d'origine. Il utilise également une excellente
change_column_order
fonction générique de ce réponse .Exemple:
Notez qu'il conserve l'index et l'ordre d'origine des colonnes. Il fonctionne également avec les trames de données qui ont un index non séquentiel.
la source
Le split de fonction de chaîne peut prendre un argument booléen option 'expand'.
Voici une solution utilisant cet argument:
la source
Je viens d'utiliser l'excellente réponse de jiln ci-dessus, mais il fallait l'étendre pour diviser plusieurs colonnes. Je pensais partager.
la source
mise à jour de la réponse de MaxU avec prise en charge de MultiIndex
la source
One-liner using
split(___, expand=True)
et les argumentslevel
etname
pourreset_index()
:Si vous devez
b
ressembler exactement à la question, vous pouvez également:la source
J'ai trouvé la solution suivante à ce problème:
la source
Une autre solution qui utilise un package de copie python
la source
Il y a beaucoup de réponses ici, mais je suis surpris que personne n'ait mentionné la fonction d'explosion des pandas intégrée. Consultez le lien ci-dessous: https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.explode.html#pandas.DataFrame.explode
Pour une raison quelconque, je n'ai pas pu accéder à cette fonction, j'ai donc utilisé le code ci-dessous:
Ci-dessus est un échantillon de mes données. Comme vous pouvez voir les gens colonne des avait une série de personnes, et j'essayais de l'exploser. Le code que j'ai donné fonctionne pour les données de type liste. Essayez donc d'obtenir vos données de texte séparées par des virgules au format liste. De plus, comme mon code utilise des fonctions intégrées, il est beaucoup plus rapide que les fonctions personnalisées / appliquées.
Remarque: vous devrez peut-être installer pandas_explode avec pip.
la source
J'ai eu un problème similaire, ma solution consistait d'abord à convertir la trame de données en une liste de dictionnaires, puis à effectuer la transition. Voici la fonction:
Exemple:
Vous pouvez également modifier un peu la fonction pour prendre en charge la séparation des lignes de type liste.
la source