2016-07-26 24 views
3

Ich habe einen Datensatz basierend auf verschiedene Wetterstationen für mehrere Variablen (Temperatur, Druck, etc.),Python Pandas - konstruieren multivariate Pivot-Tabelle Anzahl der NaNs angezeigt werden und nicht-NaNs

stationID | Time | Temperature | Pressure |... 
----------+------+-------------+----------+ 
123  | 1 |  30  | 1010.5 | 
123  | 2 |  31  | 1009.0 | 
202  | 1 |  24  | NaN  | 
202  | 2 |  24.3 | NaN  | 
202  | 3 |  NaN  | 1000.3 | 
... 

und ich würde wie eine Pivot-Tabelle zu erstellen, die die Anzahl der NaNs und nicht-NaNs pro Wetterstation, so dass zeigen würde:

stationID | nanStatus | Temperature | Pressure |... 
----------+-----------+-------------+----------+ 
123  | NaN  |  0  |  0 |  
      | nonNaN |  2  |  2 | 
202  | NaN  |  1  |  2 | 
      | nonNaN |  2  |  1 | 
... 

im Folgenden werde ich zeigen, was ich bisher getan haben, was (in eine umständliche Art und Weise) eignen sich für Temperatur. Aber wie kann ich das gleiche für beide Variablen erhalten, wie oben gezeigt?

import pandas as pd 
import bumpy as np 
df = pd.DataFrame({'stationID':[123,123,202,202,202], 'Time':[1,2,1,2,3],'Temperature':[30,31,24,24.3,np.nan],'Pressure':[1010.5,1009.0,np.nan,np.nan,1000.3]}) 

dfnull = df.isnull() 
dfnull['stationID'] = df['stationID'] 
dfnull['tempValue'] = df['Temperature'] 
dfnull.pivot_table(values=["tempValue"], index=["stationID","Temperature"], aggfunc=len,fill_value=0) 

Die Ausgabe lautet:

---------------------------------- 
         tempValue 
stationID | Temperature   
123  | False    2 
202  | False    2 
      | True     1 

Antwort

3

UPDATE: dank @root:

In [16]: df.groupby('stationID')[['Temperature','Pressure']].agg([nans, notnans]).astype(int).stack(level=1) 
Out[16]: 
        Temperature Pressure 
stationID 
123  nans    0   0 
      notnans   2   2 
202  nans    1   2 
      notnans   2   1 

Ursprüngliche Antwort:

In [12]: %paste 
def nans(s): 
    return s.isnull().sum() 

def notnans(s): 
    return s.notnull().sum() 
## -- End pasted text -- 

In [37]: df.groupby('stationID')[['Temperature','Pressure']].agg([nans, notnans]).astype(np.int8) 
Out[37]: 
      Temperature   Pressure 
       nans notnans  nans notnans 
stationID 
123     0  2  0  2 
202     1  2  2  1 
+2

Sie es beenden können mit einem '.STACK (level = 1)' – root

+0

@root, ja, das ist es, dank ab Menge! – MaxU

+0

Super, @MaxU und @root! Der '.stack (level = 1)' war das Sahnehäubchen! (Ich wünschte nur, es gäbe eine Möglichkeit, die Ausgabe auf die nächste ganze Zahl zu runden. Ich habe versucht, 'round' und' int' zu verwenden, aber sie haben nicht funktioniert) – mmeclimate

0

Ich gebe zu, das ist nicht die schönste Lösung, aber es funktioniert. Definieren Sie zunächst zwei temporäre Spalten TempNaN und PresNaN:

df['TempNaN'] = df['Temperature'].apply(lambda x: 'NaN' if x!=x else 'NonNaN') 
df['PresNaN'] = df['Pressure'].apply(lambda x: 'NaN' if x!=x else 'NonNaN') 

dann Ihre Ergebnisse Datenrahmen definieren einen Multiindex mit:

Results = pd.DataFrame(index=pd.MultiIndex.from_tuples(list(zip(*[sorted(list(df['stationID'].unique())*2),['NaN','NonNaN']*df['stationID'].nunique()])),names=['stationID','NaNStatus'])) 

Speichern Sie Ihre Berechnungen in den Datenrahmen Ergebnisse:

Results['Temperature'] = df.groupby(['stationID','TempNaN'])['Temperature'].apply(lambda x: x.shape[0]) 
Results['Pressure'] = df.groupby(['stationID','PresNaN'])['Pressure'].apply(lambda x: x.shape[0]) 

und füllen Sie den Leerwerte mit Null:

Results.fillna(value=0,inplace=True) 

Sie können die Spalten überlappen, wenn das einfacher ist. Zum Beispiel:

Results = pd.DataFrame(index=pd.MultiIndex.from_tuples(list(zip(*[sorted(list(df['stationID'].unique())*2),['NaN','NonNaN']*df['stationID'].nunique()])),names=['stationID','NaNStatus'])) 
for col in ['Temperature','Pressure']: 
    df[col + 'NaN'] = df[col].apply(lambda x: 'NaN' if x!=x else 'NonNaN') 
    Results[col] = df.groupby(['stationID',col + 'NaN'])[col].apply(lambda x: x.shape[0]) 
    df.drop([col + 'NaN'],axis=1,inplace=True) 
Results.fillna(value=0,inplace=True) 
0
d = {'stationID':[], 'nanStatus':[], 'Temperature':[], 'Pressure':[]} 

for station_id, data in df.groupby(['stationID']): 

    temp_nans = data.isnull().Temperature.mean()*data.isnull().Temperature.count() 
    pres_nans = data.isnull().Pressure.mean()*data.isnull().Pressure.count() 

    d['stationID'].append(station_id) 
    d['nanStatus'].append('NaN') 
    d['Temperature'].append(temp_nans) 
    d['Pressure'].append(pres_nans) 

    d['stationID'].append(station_id) 
    d['nanStatus'].append('nonNaN') 
    d['Temperature'].append(data.isnull().Temperature.count() - temp_nans) 
    d['Pressure'].append(data.isnull().Pressure.count() - pres_nans) 

df2 = pd.DataFrame.from_dict(d) 
print(df2) 

Das Ergebnis ist:

Pressure Temperature nanStatus stationID 
0  0.0   0.0  NaN  123 
1  2.0   2.0 nonNaN  123 
2  2.0   1.0  NaN  202 
3  1.0   2.0 nonNaN  202