J'ai un bloc de données pandas et une liste de listes, je veux que chaque ligne du bloc de données pandas soit dupliqué autant de fois dans la liste et ajoute la liste en tant que nouvelle colonne.
input: p >
col1 col2 0 row1 a 1 row1 b 2 row2 a 3 row2 b 4 row2 c 5 row3 nan
pd.DataFrame({'col1':['row1','row1','row2','row2','row2','row3'],'col2':['a','b','a','b','c','nan']})
résultat attendu:
col1 0 row1 1 row2 2 row3
df = pd.DataFrame({'col1':['row1','row2','row3']})
ll = [['a','b'],['a','b','c'],[]]
3 Réponses :
IIUC:
rows = ['row1','row2','row3'] ll = [['a','b'],['a','b','c'],[]] t = [] for r, l1 in zip(rows,ll): for l2 in l1: t.append([r,l2]) df = pd.DataFrame(t, columns = ['col1','col2'])
Merci pour cela, je l'ai déjà fait mais je cherchais un moyen plus efficace sans ces boucles, un moyen pythonique d'améliorer la vitesse. peut-être une méthode pandas intégrée ou une approche vectorisée ou autre chose.
vous pouvez essayer exploser sur une série construite à partir de ll , et reset_index comme:
df = df.join(pd.Series(ll, df.index, name='col2').explode()).reset_index() print (df) col1 col2 0 row1 a 1 row1 b 2 row2 a 3 row2 b 4 row2 c 5 row3 NaN
@cerofrais merci, mais si la vitesse est votre préoccupation, je ne suis pas sûr que ce soit sa meilleure façon
@cerofrais et je ne suis pas sûr qu'il existe un moyen plus rapide que de faire pd.DataFrame ([[r, l] pour r, l1 dans zip (df ['col1'], ll) pour l dans l1], colonnes = ['col1', 'col2']) , similaire à la réponse d'Umbreon29 lorsque la taille augmente
C'est probablement la bonne solution, je ne savais pas exploser
@ umbreon29 c'est un peu nouveau et c'est vraiment pratique :)
si vous voulez que la dernière cellule soit vide, vous pouvez la passer sous forme de liste:
from itertools import product, chain
res = chain.from_iterable(product([first],last)
for first, last
in zip(df.col1,ll)
)
pd.DataFrame(res)
0 1
0 row1 a
1 row1 b
2 row2 a
3 row2 b
4 row2 c
5 row3 None
ensuite est une combinaison de zip, produit , chain pour obtenir votre sortie avant de la lire dans un dataframe pandas:
df = pd.DataFrame({'col1':['row1','row2','row3']})
ll = [['a','b'],['a','b','c'],[None]] # or np.nan
vitesse de retour sur ceci est 373 µs  ± 9,05 µs par boucle (moyenne ± écart standard de 7 courses, 1000 boucles chacune)
retour de vitesse en utilisant la solution de @ Ben.T: 2,03 ms ± 64,6 µs par boucle (moyenne ± écart type de 7 courses, 100 boucles chacune)
vitesse en utilisant l'approche de @ umbreon29: 460 µs ± 7,41 µs par boucle (moyenne: ± std. dev. de 7 courses, 1000 boucles chacune)
bien sûr, c'est un très petit ensemble de données. un test approprié sur un grand ensemble de données devrait être plus précis
sympa et oui c'est plus rapide sur la petite taille, mais deux choses: vous devez d'abord avoir [None] ou [np.nan] au lieu de [] < / code> sinon il ne donne pas le résultat attendu et en second lieu, lorsque la taille augmente, il ne va pas plus vite que la compréhension de la liste :)
oui, c'est la mise en garde. par rapport à la compréhension de la liste. pour le test de vitesse, j'aimerais le voir pour de plus grands ensembles de données. qui sait, il pourrait y avoir une optimisation que quelqu'un d'autre pourrait apporter à la table.
J'ai essayé avec df = pd.concat ([pd.DataFrame ({'col1': ['row1', 'row2', 'row3']})] * 10 00, ignore_index = True) code > et ll = [['a', 'b'], ['a', 'b', 'c'], [None]] * 1000 , et cette méthode semble plus lente que la compréhension de la liste d'environ 25%, mais exploser est le pire :)
Joli. Je jouerai avec quand je serai de retour sur mon PC.
je vais devoir partager votre code de compréhension de liste. cos je l'ai essayé et l'utilisation des expressions itertools / generateur est plus rapide.
J'ai utilisé celui-ci pd.DataFrame ([[r, l] pour r, l1 dans zip (df ['col1'], ll) pour l dans l1]) qui donne le même résultat que le vôtre