2017-09-30 1 views
1

J'ai un dataframe Pandas avec des mots et des étiquettesComment faire une liste de liste de pandas de données?

words tags 
0 I  WW 
1 am  XX 
2 newbie YY 
3 .  ZZ 
4 You  WW 
5 are  XX 
6 cool YY 
7 .  ZZ 

est-il une méthode sur comment puis-je créer une liste de la liste de la chose dataframe comme ceci:

[[('I', 'WW'), ('am', 'XX'), ('newbie', 'YY'), ('.','ZZ')], 
[('You', 'WW'), ('are', 'XX'), ('cool', 'YY'), ('.','ZZ')]] 

Il est une liste de listes de tuples. Pour chaque liste dans la liste sont séparés par ('.','ZZ'). Cela signifie que c'est une phrase.

Je peux itérer sur chaque ligne de données et créer une liste et l'ajouter si la condition est vraie, mais existe-t-il un moyen de la résoudre?

Répondre

5

Vous pouvez d'abord créer tuples de toutes les valeurs et les séparer pour les sous-listes, si la performance est importante:

from itertools import groupby 

L = list(zip(df['words'], df['tags'])) 
print (L) 
[('I', 'WW'), ('am', 'XX'), ('newbie', 'YY'), 
('.', 'ZZ'), ('You', 'WW'), ('are', 'XX'), 
('cool', 'YY'), ('.', 'ZZ')] 

sep = ('.','ZZ') 
new_L = [list(g) + [sep] for k, g in groupby(L, lambda x: x==sep) if not k] 
print (new_L) 

[[('I', 'WW'), ('am', 'XX'), ('newbie', 'YY'), ('.', 'ZZ')], 
[('You', 'WW'), ('are', 'XX'), ('cool', 'YY'), ('.', 'ZZ')]] 

minutage:

df = pd.concat([df]*1000).reset_index(drop=True) 

def zero(df): 
    dft = df.apply(tuple, 1) 
    return ([x.values.tolist() for _, x in dft.groupby((dft == ('.', 'ZZ')).shift().cumsum().bfill())]) 

In [55]: %timeit ([list(g) + [('.','ZZ')] for k, g in groupby(list(zip(df['words'], df['tags'])), lambda x: x==('.','ZZ')) if not k]) 
100 loops, best of 3: 4.14 ms per loop 

def pir(df): 
    v = df.values 
    return ([list(map(tuple, x)) for x in np.split(v, np.where((v == ['.', 'ZZ']).all(1)[:-1])[0] + 1)]) 

In [68]: %timeit (pir(df)) 
10 loops, best of 3: 21.9 ms per loop 


In [56]: %timeit (zero(df)) 
1 loop, best of 3: 328 ms per loop 

In [57]: %timeit (df.groupby((df.shift().values == ['.', 'ZZ']).all(axis=1).cumsum()).apply(lambda group: list(zip(group['words'], group['tags']))).values.tolist()) 
1 loop, best of 3: 286 ms per loop 

In [58]: %timeit (list(filter(None,[i.apply(tuple,1).values.tolist() for i in np.array_split(df,df[(df['words'] == '.') & (df['tags'] == 'ZZ')].index+1)]))) 
1 loop, best of 3: 1.31 s per loop 

Pour séparés à des listes secondaires que je crée question, vous pouvez vérifier la solution here:

def jez_coldspeed(df): 
    L = list(zip(df['words'], df['tags'])) 
    L2 = [] 
    for i in L[::-1]: 
     if i == ('.','ZZ'): 
      L2.append([]) 

     L2[-1].append(i) 

    return [x[::-1] for x in L2[::-1]] 

def jez_coldspeed1(df): 
    L = list(zip(df['words'], df['tags'])) 
    L2 = [] 
    sep = ('.','ZZ') 
    for i in reversed(L): 
     if i == sep: 
      L2.append([]) 

     L2[-1].append(i) 

    return [x[::-1] for x in reversed(L2)] 


In [74]: %timeit (jez_coldspeed(df)) 
100 loops, best of 3: 2.96 ms per loop 

In [75]: %timeit (jez_coldspeed1(df)) 
100 loops, best of 3: 2.95 ms per loop 

def jez_theBuzzyCoder(df): 
    L = list(zip(df['words'], df['tags'])) 
    a = list() 
    start = 0 
    sep = ('.', 'ZZ') 

    while start < len(L) and (L.index(sep, start) != -1): 
     end = L.index(sep, start) + 1 
     a.append(L[start:end]) 
     start = end 
    return a 


print (jez_theBuzzyCoder(df)) 

In [81]: %timeit (jez_theBuzzyCoder(df)) 
100 loops, best of 3: 3.16 ms per loop 
+0

Cette méthode est certainement la plus rapide. – Dark

+0

Très rapide en effet. – Alexander

+0

Aha! Rapide en effet! –

3

est ici une façon

In [5149]: dft = df.apply(tuple, 1) 

In [5150]: parts = (dft == ('.', 'ZZ')).shift().cumsum().bfill() 
      # parts = (dft.shift() == ('.', 'ZZ')).cumsum()  from Alexander's 

In [5151]: [x.values.tolist() for _, x in dft.groupby(parts)] 
Out[5151]: 
[[('I', 'WW'), ('am', 'XX'), ('newbie', 'YY'), ('.', 'ZZ')], 
[('You', 'WW'), ('are', 'XX'), ('cool', 'YY'), ('.', 'ZZ')]] 

Ou,

In [5152]: dft.groupby(parts).apply(list).tolist() 
Out[5152]: 
[[('I', 'WW'), ('am', 'XX'), ('newbie', 'YY'), ('.', 'ZZ')], 
[('You', 'WW'), ('are', 'XX'), ('cool', 'YY'), ('.', 'ZZ')]] 

Ou,

In [5165]: list(dft.groupby(parts).apply(list)) 
Out[5165]: 
[[('I', 'WW'), ('am', 'XX'), ('newbie', 'YY'), ('.', 'ZZ')], 
[('You', 'WW'), ('are', 'XX'), ('cool', 'YY'), ('.', 'ZZ')]] 

Détails

In [5153]: parts 
Out[5153]: 
0 0.0 
1 0.0 
2 0.0 
3 0.0 
4 1.0 
5 1.0 
6 1.0 
7 1.0 
dtype: float64 
1

La première partie (df.groupby((df.shift().values == ['.', 'ZZ']).all(axis=1).cumsum())) regroupera la trame de données sur les valeurs contiguës dans la colonne «Mots» de la trame jusqu'à et y compris une période où la seconde colonne est égale à Z. Ceci est une variation du motif shift-cumsum (recherche pandas shift cumsum sur SO et vous devriez trouver beaucoup de variantes).

La deuxième partie (.apply(lambda group: zip(group['words'], group['tags']))) crée des paires de tuples pour chaque ligne, par ex.

0  [(I, WW), (am, XX), (newbie, YY), (., ZZ)] 
1 [(You, WW), (are, XX), (cool, YY), (., ZZ)] 
dtype: object 

La dernière partie (.values.tolist()) convertit le dataframe au format de votre choix comme une liste de listes.

>>> df.groupby((df.shift().values == ['.', 'ZZ']).all(axis=1).cumsum()).apply(
     lambda group: zip(group['words'], group['tags'])).values.tolist() 
[[('I', 'WW'), ('am', 'XX'), ('newbie', 'YY'), ('.', 'ZZ')], 
[('You', 'WW'), ('are', 'XX'), ('cool', 'YY'), ('.', 'ZZ')]] 
+0

OP besoin 'pour chaque liste dans la liste sont séparés par ('.', 'ZZ'). '... – jezrael

+1

Je pense, Alex est allé avec l'hypothèse que puisque ce sont des balises NLP,' '. '' sera toujours marqué '' ZZ''. – Zero

+1

Mais je l'ai modifié pour tenir compte de l'exigence spécifique. – Alexander

3

Vous pouvez également faire np.array_split i.e

li = list(filter(None,[i.apply(tuple,1).values.tolist() \ 
    for i in np.array_split(df,df[(df['words'] == '.') & (df['tags'] == 'ZZ')].index+1)])) 

ou

x = df.apply(tuple,1) 
li = [ i.tolist() for i in np.array_split(x,x[x==('.','ZZ')].index+1) if len(i.tolist())>1] 

Sortie:

[[('I', 'WW'), ('am', 'XX'), ('newbie', 'YY'), ('.', 'ZZ')], 
[('You', 'WW'), ('are', 'XX'), ('cool', 'YY'), ('.', 'ZZ')]] 
3
v = df.values 

[ 
    list(map(tuple, x)) 
    for x in np.split(v, np.where((v == ['.', 'ZZ']).all(1)[:-1])[0] + 1) 
] 

[[('I', 'WW'), ('am', 'XX'), ('newbie', 'YY'), ('.', 'ZZ')], 
[('You', 'WW'), ('are', 'XX'), ('cool', 'YY'), ('.', 'ZZ')]]