2017-09-30 5 views
1

ich mit Worten und Tags ein Pandas DatenrahmenWie man Liste von Liste von Dataframe Pandas macht?

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

haben Gibt es eine Methode, wie erstelle ich Liste der Liste der Datenrahmen etwas wie folgt aus:

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

Es wird eine Liste von Listen von Tupeln. Für jede Liste in der Liste sind durch ('.','ZZ') getrennt. Ich meine, dass es ein Satz ist.

Ich kann auf jeder Zeile von Datenrahmen und erstellen Liste und anhängen, wenn die Bedingung wahr ist, aber gibt es irgendwelche "Pandas" Weg, es zu lösen?

Antwort

5

Sie erste Tupel von allen Werten erstellen und sie dann zu Sublisten trennen, wenn die Leistung ist wichtig:

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')]] 

Timings:

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 

Für getrennt Sublisten ich Frage erstellen, können Sie Lösung überprüfen 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

Diese Methode ist definitiv am schnellsten. – Dark

+0

In der Tat sehr schnell. – Alexander

+0

Aha! Schnell in der Tat! –

3

Hier ist eine Art und Weise

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')]] 

Oder

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

Oder

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

Einzelheiten

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

Der erste Teil (df.groupby((df.shift().values == ['.', 'ZZ']).all(axis=1).cumsum())) gruppiert den Datenrahmen auf zusammenhängenden Werten in der Spalte "Wörter" des Datenrahmens bis einschließlich eines Zeitraums, in dem die zweite Spalte ebenfalls Z ist. Dies ist eine Variation der shift-cumsum Muster (Suche Pandas Verschiebung Cumsum auf SO und Sie sollten viele Variationen finden).

Der zweite Teil (.apply(lambda group: zip(group['words'], group['tags']))) erzeugt Tupelpaare für jede Zeile, z.B.

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

Der letzte Teil (.values.tolist()) wandelt den Datenrahmen auf das gewünschte Format als eine Liste von Listen.

>>> 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 Notwendigkeit 'für jede Liste in Listen getrennt sind by ('.', 'ZZ'). '... – jezrael

+1

Ich denke, Alex ging davon aus, dass, da dies NLP-Tags sind,' '. ''wird immer mit'' ZZ' 'markiert. – Zero

+1

Aber ich änderte es um die spezifische Anforderung zu berücksichtigen. – Alexander

3

Sie können auch 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)])) 

oder

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] 

Ausgang:

[[('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')]] 
Verwandte Themen