2016-12-13 7 views
0

Ich habe eine quadratische Korrelationsmatrix in Pandas und versuche, die effizienteste Möglichkeit zu finden, alle Werte zurückzugeben, wo der Wert (immer ein Float -1 < = x < = 1) über a ist bestimmte Schwelle.Pandas - Filter über alle Spalten

Die Methode pandas.DataFrame.filter fragt nach einer Liste von Spalten oder einer RegEx, aber ich möchte immer alle Spalten übergeben. Gibt es eine Best Practice?

+5

Können Sie Probe hinzufügen mit gewünschte Ausgabe? Wenn Werte außerhalb der Bedingungen dann durch 'NaN' ersetzt werden? – jezrael

Antwort

5

Nicht sicher, was Sie gewünscht, Ausgabe ist, da Sie keine Probe zur Verfügung gestellt haben, aber ich gebe Ihnen meine zwei Cent auf, was ich tun würde:

In[1]: 
import pandas as pd 
import numpy as np 

df = pd.DataFrame(np.random.rand(10,5)) 
corr = df.corr() 
corr.shape 

Out[1]: (5, 5) 

Nun extrahieren wir das obere Dreieck der Korrelationsmatrix (es ist symmetrisch), ohne die Diagonale. Dazu werden wir np.tril verwenden, dies als Boolean darstellen und das Gegenteil davon mit dem Operator ~ erreichen.

In [2]: corr_triu = corr.where(~np.tril(np.ones(corr.shape)).astype(np.bool)) 
     corr_triu 
Out[2]: 
    0   1   2   3   4 
0 NaN 0.228763 -0.276406 0.286771 -0.050825 
1 NaN  NaN -0.562459 -0.596057 0.540656 
2 NaN  NaN  NaN 0.402752 0.042400 
3 NaN  NaN  NaN  NaN -0.642285 
4 NaN  NaN  NaN  NaN  NaN 

Nun wollen wir diese Stack und alle Werte filtern, die über 0.3 zum Beispiel sind:

In [3]: corr_triu = corr_triu.stack() 
     corr_triu[corr_triu > 0.3] 
Out[3]: 
1 4 0.540656 
2 3 0.402752 
dtype: float64 

Wenn Sie es ein bisschen schöner machen wollen:

In [4]: corr_triu.name = 'Pearson Correlation Coefficient' 
     corr_triu.index.names = ['Col1', 'Col2'] 

In [5]: corr_triu[corr_triu > 0.3].to_frame() 
Out[5]: 
      Pearson Correlation Coefficient 
Col1 Col2     
1 4    0.540656 
2 3    0.402752 
+1

Ich hob auf, weil dies mir eine gute Methode für den Fall einer symmetrischen Matrix beibrachte. –

7

Es gibt zwei Möglichkeiten, um dies zu:

Angenommen:

In [7]: c = np.array([-1,-2,-2,-3,-4,-6,-7,-8]) 

In [8]: a = np.array([1,2,3,4,6,7,8,9]) 

In [9]: b = np.array([2,4,6,8,10,12,13,15]) 

In [10]: c = np.array([-1,-2,-2,-3,-4,-6,-7,-8]) 

In [11]: corr = np.corrcoef([a,b,c]) 

In [12]: df = pd.DataFrame(corr) 

In [13]: df 
Out[13]: 
      0   1   2 
0 1.000000 0.995350 -0.980521 
1 0.995350 1.000000 -0.971724 
2 -0.980521 -0.971724 1.000000 

Dann können Sie einfach:

In [14]: df > 0.5 
Out[14]: 
     0  1  2 
0 True True False 
1 True True False 
2 False False True 

In [15]: df[df > 0.5] 
Out[15]: 
     0  1 2 
0 1.00000 0.99535 NaN 
1 0.99535 1.00000 NaN 
2  NaN  NaN 1.0 

Wenn Sie nur die Werte wollen, dann ist der einfachste Weg mit den zugrunde liegenden numpy Datenstrukturen mit dem values Attribut zu arbeiten:

In [17]: df.values 
Out[17]: 
array([[ 1.  , 0.99535001, -0.9805214 ], 
     [ 0.99535001, 1.  , -0.97172394], 
     [-0.9805214 , -0.97172394, 1.  ]]) 

In [18]: df.values[(df > 0.5).values] 
Out[18]: array([ 1.  , 0.99535001, 0.99535001, 1.  , 1.  ]) 

Statt .values, wie ayhan wies darauf hin, können Sie stack verwenden, die NaN automatisch sinkt und auch Etiketten hält ...

In [22]: df.index = ['a','b','c'] 

In [23]: df.columns=['a','b','c'] 

In [24]: df 
Out[24]: 
      a   b   c 
a 1.000000 0.995350 -0.980521 
b 0.995350 1.000000 -0.971724 
c -0.980521 -0.971724 1.000000 


In [25]: df.stack() > 0.5 
Out[25]: 
a a  True 
    b  True 
    c False 
b a  True 
    b  True 
    c False 
c a False 
    b False 
    c  True 
dtype: bool 

In [26]: df.stack()[df.stack() > 0.5] 
Out[26]: 
a a 1.00000 
    b 0.99535 
b a 0.99535 
    b 1.00000 
c c 1.00000 
dtype: float64 

Sie jederzeit zurückgehen ...

In [29]: (df.stack()[df.stack() > 0.5]).unstack() 
Out[29]: 
     a  b c 
a 1.00000 0.99535 NaN 
b 0.99535 1.00000 NaN 
c  NaN  NaN 1.0 
+2

Zusätzlich zu 'values' ist' stack() 'auch nützlich, da es NaNs automatisch löscht, aber Labels behält. – ayhan

+0

@ayhan guten Ruf –

+0

Ihre Lösung fühlt sich definitiv natürlicher an als meine, aber ich würde davor warnen, dass es unnötige Elemente (die '('x', 'x')' diejenigen, die immer notwendig sind 1) sowie Permutationen beibehalten: '('a', 'b')' ist das gleiche wie '('b', 'a')'. (Und das ist in Ordnung, da wir immer noch nicht wissen, die genauen OP-Anforderungen, also habe ich es upvoted) –

Verwandte Themen