2015-09-24 9 views
5

Czy istnieje dobry sposób na znalezienie zestawu indeksów kolumn dla niezerowych wartości w każdym wierszu w ramce danych pandy? Czy muszę przechodzić przez ramkę danych wiersz po rzędzie?znaleźć zestaw indeksów kolumn dla wartości niezerowych w każdym wierszu w ramce danych pandy

Na przykład, ramka danych

c1 c2 c3 c4 c5 c6 c7 c8 c9 
1 1 0 0 0 0 0 0 0 
1 0 0 0 0 0 0 0 0 
0 1 0 0 0 0 0 0 0 
1 0 0 0 0 0 0 0 0 
0 1 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 
0 2 1 1 1 1 1 0 2 
1 5 5 0 0 1 0 4 6 
4 3 0 1 1 1 1 5 10 
3 5 2 4 1 2 2 1 3 
6 4 0 1 0 0 0 0 0 
3 9 1 0 1 0 2 1 0 

Oczekuje się wyjściowy będzie

['c1','c2'] 
['c1'] 
['c2'] 
... 

Odpowiedz

5

Wygląda na to, że musisz przejść przez ramkę DataFrame według wiersza.

cols = df.columns 
bt = df.apply(lambda x: x > 0) 
bt.apply(lambda x: list(cols[x.values]), axis=1) 

a dostaniesz:

0         [c1, c2] 
1          [c1] 
2          [c2] 
3          [c1] 
4          [c2] 
5          [] 
6    [c2, c3, c4, c5, c6, c7, c9] 
7     [c1, c2, c3, c6, c8, c9] 
8   [c1, c2, c4, c5, c6, c7, c8, c9] 
9  [c1, c2, c3, c4, c5, c6, c7, c8, c9] 
10       [c1, c2, c4] 
11    [c1, c2, c3, c5, c7, c8] 
dtype: object 

Jeśli wydajność jest materia, spróbuj przejść raw=True do logicznej tworzenia DataFrame jak poniżej:

%timeit df.apply(lambda x: x > 0, raw=True).apply(lambda x: list(cols[x.values]), axis=1) 
1000 loops, best of 3: 812 µs per loop 

To przynosi lepszy przyrost wydajności. Poniżej raw=False (co jest domyślne) Wynik:

%timeit df.apply(lambda x: x > 0).apply(lambda x: list(cols[x.values]), axis=1) 
100 loops, best of 3: 2.59 ms per loop 
1

potencjalnie lepszym struktura danych (zamiast serii list) znajduje się stos:

In [11]: res = df[df!=0].stack() 

In [12]: res 
Out[12]: 
0 c1  1 
    c2  1 
1 c1  1 
2 c2  1 
3 c1  1 
... 

I można powtórzyć w stosunku do oryginalnych wierszy:

In [13]: res.loc[0] 
Out[13]: 
c1 1 
c2 1 
dtype: float64 

In [14]: res.loc[0].index 
Out[14]: Index(['c1', 'c2'], dtype='object') 

Uwaga: Myślałam, że kiedyś stanie wrócić listę w sposób zastosować (aby utworzyć DataFrame który ma elementy listy) to nie wydaje się być przypadek.

2

Jak o takim podejściu?

#create a True/False data frame 
df_boolean = df>0 

#a little helper method that uses boolean slicing internally 
def bar(x,columns): 
    return ','.join(list(columns[x])) 

#use an apply along the column axis 
df_boolean['result'] = df_boolean.apply(lambda x: bar(x,df_boolean.columns),axis=1) 

# filter out the empty "rows" adn grab the result column 
df_result = df_boolean[df_boolean['result'] != '']['result'] 

#append an axis, just so each line will will output a list 
lst_result = df_result.values[:,np.newaxis] 

print '\n'.join([ str(myelement) for myelement in lst_result]) 

a to produkuje:

['c1,c2'] 
['c1'] 
['c2'] 
['c1'] 
['c2'] 
['c2,c3,c4,c5,c6,c7,c9'] 
['c1,c2,c3,c6,c8,c9'] 
['c1,c2,c4,c5,c6,c7,c8,c9'] 
['c1,c2,c3,c4,c5,c6,c7,c8,c9'] 
['c1,c2,c4'] 
['c1,c2,c3,c5,c7,c8'] 
+0

Scari ma pokonać mnie do niego i bardziej zwięzły rozwiązanie. Mogę zostawić swoją odpowiedź online, aby zademonstrować zapisanie wyników lub z przyjemnością je usunąć. – Dickster

Powiązane problemy