2
votes

Pandas Python: exploser plusieurs lignes

Je dois en dessous de dataframe:

   name                 item                       itemVal
   John                item1                      item1Val
   John                item2                      item2Val
   John                item3                      item3Val
    Tom                item4                      item4Val

Le dataframe est comme ceci:

   name                 item                       itemVal
   John  item1||item2||item3  item1Val||item2Val||item3Val
    Tom                item4                      item4Val

Je veux exploser la ligne en plusieurs lignes pour qu'elle soit comme ça (notez que l' item et son itemVal doivent correspondre).

import pandas as pd

a = pd.DataFrame([{"name": "John", 
                   "item" : "item1||item2||item3", 
                   "itemVal" : "item1Val||item2Val||item3Val"}, 
                  {"name" : "Tom", 
                   "item":"item4", 
                   "itemVal" : "item4Val"
                  }
                 ])

J'ai regardé d'autres réponses ici:

Fractionner (exploser) l'entrée de chaîne de dataframe pandas pour séparer les lignes

pandas: Comment diviser le texte d'une colonne en plusieurs lignes?

Mais les travaux sur une seule colonne. Comment le faire fonctionner sur plusieurs colonnes? J'utilise Pandas 1.0.1 et Python 3.8


2 commentaires

Est-ce toujours le cas que item et itemVal aient le même nombre de partitions?


@MichaelDelgado Oui toujours


3 Réponses :


3
votes
exploded = a[['item', 'itemVal']].apply(lambda x: [v.split('||') for v in x]).apply(pd.Series.explode)
print( pd.concat([a['name'], exploded], axis=1) )

1 commentaires

Merci pour votre solution, cela fonctionne. Cependant, existe-t-il un moyen de spécifier les seules colonnes que je souhaite fractionner?



1
votes

Une combinaison de fermeture éclair , de produit et de chaîne peut réaliser la division en rangées. Comme cela implique des chaînes et, plus important encore, pas de calcul numérique, vous devriez obtenir des vitesses plus rapides en Python que de l'exécuter dans Pandas.

from itertools import product,chain
combine = chain.from_iterable

#pair item and itemval columns
merge = zip(df.item,df.itemVal) 

#pair the entires from the splits of item and itemval
merge = [zip(first.split("||"),last.split("||")) for first, last in merge]

#create a cartesian product with the name column
merger = [product([ent],cont) for ent, cont in zip(df.name,merge)]

#create ur exploded values
res = [(ent,*cont) for ent, cont in combine(merger)]
pd.DataFrame(res,columns=['name','item','itemVal'])

    name    item    itemVal
0   John    item1   item1Val
1   John    item2   item2Val
2   John    item3   item3Val
3   Tom     item4   item4Val


0 commentaires

0
votes

Ce n'est peut-être pas aussi rapide que la réponse suggérée par Sammywemmy, mais voici une fonction générique qui fonctionne à l'aide des fonctions Pandas. Notez que la fonction d'éclatement ne fonctionne que sur une colonne à la fois. Donc:

df = pd.DataFrame({'A': [1, 2], 'B': [['a','b'], ['c','d']], 'C': [['z','y'], ['x','w']]})

A    B     C
--------------
1 [a, b] [z, y]
2 [c, d] [x, w]

##Logic for multi-col explode
list_cols = {'B','C'}
other_cols = list(set(df.columns) - set(list_cols))
exploded = [df[col].explode() for col in list_cols]
df2 = pd.DataFrame(dict(zip(list_cols, exploded)))
df2 = df[other_cols].merge(df2, how="right", left_index=True, right_index=True)

A B C
------
1 a z
1 b y
2 c x
2 d w


0 commentaires