2012-10-15 5 views
7

Sono nuovo di panda e sto cercando di leggere uno strano file formattato in un DataFrame. Il file originale assomiglia a questo:Espansione efficiente di righe da panda DataFrame

; No Time Date MoistAve MatTemp TDRConduct TDRAve DeltaCount tpAve Moist1 Moist2 Moist3 Moist4 TDR1 TDR2 TDR3 TDR4 
1 11:38:17 11.07.2012 11.37 48.20 5.15 88.87 15 344.50 11.84 11.35 11.59 15.25 89.0 89.0 89.0 88.0 
2 11:38:18 11.07.2012 11.44 48.20 5.13 88.88 2 346.22 12.08 11.83 -1.00 -1.00 89.0 89.0 -1.0 -1.0 
3 11:38:19 11.07.2012 11.10 48.20 4.96 89.00 3 337.84 11.83 11.59 10.62 -1.00 89.0 89.0 89.0 -1.0 
4 11:38:19 11.07.2012 11.82 48.20 5.54 88.60 3 355.92 11.10 13.54 12.32 -1.00 89.0 88.0 88.0 -1.0 

sono riuscito ad ottenere un dataframe altrettanto strutturato con:

In [42]: date_spec = {'FetchTime': [1, 2]} 

In [43]: df = pd.read_csv('MeasureCK32450-20120711114050.mck', header=7, sep='\s\s+', 
          parse_dates=date_spec, na_values=['-1.0', '-1.00']) 

In [44]: df 
Out[52]: 
       FetchTime ; No MoistAve MatTemp TDRConduct TDRAve DeltaCount tpAve Moist1 Moist2 Moist3 Moist4 TDR1 TDR2 TDR3 TDR4 
0 2012-11-07 11:38:17  1  11.37  48.2  5.15 88.87   15 344.50 11.84 11.35 11.59 15.25 89 89 89 88 
1 2012-11-07 11:38:18  2  11.44  48.2  5.13 88.88   2 346.22 12.08 11.83  NaN  NaN 89 89 NaN NaN 
2 2012-11-07 11:38:19  3  11.10  48.2  4.96 89.00   3 337.84 11.83 11.59 10.62  NaN 89 89 89 NaN 
3 2012-11-07 11:38:19  4  11.82  48.2  5.54 88.60   3 355.92 11.10 13.54 12.32  NaN 89 88 88 NaN 

Ma ora devo espandere ogni riga di questo dataframe

.... Moist1 Moist2 Moist3 Moist4 TDR1 TDR2 TDR3 TDR4 
1 .... 11.84 11.35 11.59 15.25 89 89 89 88 
2 .... 12.08 11.83  NaN  NaN 89 89 NaN NaN 

in quattro righe (con tre indici No, FetchTime e MeasureNo):

        .... Moist TDR 
No   FetchTime MeasureNo 
0 2012-11-07 11:38:17   1 .... 11.84 89 # from line 1, Moist1 and TDR1 
1        2 .... 11.35 89 # from line 1, Moist2 and TDR2 
2        3 .... 11.59 89 # from line 1, Moist3 and TDR3 
3        4 .... 15.25 88 # from line 1, Moist4 and TDR4 
4 2012-11-07 11:38:18   1 .... 12.08 89 # from line 2, Moist1 and TDR1 
5        2 .... 11.83 89 # from line 2, Moist2 and TDR2 
6        3 .... NaN NaN # from line 2, Moist3 and TDR3 
7        4 .... NaN NaN # from line 2, Moist4 and TDR4 

conservando le altre colonne e MASSIMO importante, mantenendo l'ordine delle voci. I so che posso scorrere su ogni riga con for row in df.iterrows(): ... ma ho letto questo è non molto veloce. Il mio primo approccio è stato questo:

In [54]: data = [] 
In [55]: for d in range(1,5): 
....:  temp = df.ix[:, ['FetchTime', 'MoistAve', 'MatTemp', 'TDRConduct', 'TDRAve', 'DeltaCount', 'tpAve', 'Moist%d' % d, 'TDR%d' % d]] 
....:  temp.columns = ['FetchTime', 'MoistAve', 'MatTemp', 'TDRConduct', 'TDRAve', 'DeltaCount', 'tpAve', 'RawMoist', 'RawTDR'] 
....:  temp['MeasureNo'] = d 
....:  data.append(temp) 
....:  
In [56]: test = pd.concat(data, ignore_index=True) 
In [62]: test.head() 
Out[62]: 
      FetchTime MoistAve MatTemp TDRConduct TDRAve DeltaCount tpAve RawMoist RawTDR MeasureNo 
0 2012-11-07 11:38:17  11.37  48.2  5.15 88.87   15 344.50  11.84  89   1 
1 2012-11-07 11:38:18  11.44  48.2  5.13 88.88   2 346.22  12.08  89   1 
2 2012-11-07 11:38:19  11.10  48.2  4.96 89.00   3 337.84  11.83  89   1 
3 2012-11-07 11:38:19  11.82  48.2  5.54 88.60   3 355.92  11.10  89   1 
4 2012-11-07 11:38:20  12.61  48.2  5.87 88.38   3 375.72  12.80  89   1 

Ma io non vedo un modo per influenzare la concatenazione per ottenere l'ordine che ho bisogno ... c'è un altro modo per ottenere il dataframe risultante ho bisogno?

+0

è possibile caricare 2 fotogrammi di dati separati e unire/groupby sul datetime? – reptilicus

+0

Vedere anche http://stackoverflow.com/questions/11795992/pandas-efficiently-splitting-entries –

risposta

0

Questo offre ogni tipo dà quarta fila in prova a partire da 'i':

test.ix[i::4] 

Usando lo stesso ciclo di base di cui sopra, basta aggiungere l'insieme di fila ogni via a partire da 0-3 dopo aver eseguito la tua codice sopra.

data = []  
for i in range(0,3:):  
    temp = test.ix[i::4] 
    data.append(temp) 
test2 = pd.concat(data,ignore_index=True) 

Aggiornamento: mi rendo conto ora che cosa è che ci si vuole non è ogni quarta fila ma ogni riga mese, quindi questo sarebbe solo i suggerimenti di loop sopra. Scusate.

Aggiornamento 2: Forse no. Possiamo approfittare del fatto che anche se il concatenato non restituisce l'ordine desiderato, ciò che restituisce ha una mappatura fissa su ciò che vuoi. d è il numero di righe per timestamp e m è il numero di timestamp.

Sembra che le righe provino come segue: [0, m, 2m, 3m, 1, m + 1,2m + 1,3m + 1,2, m + 2,2m + 2,3m +2, ..., m-1,2m-1,3m-1,4m-1]

Sono sicuro che ci sono molti modi migliori per generare quell'elenco di indici, ma questo ha funzionato per me

d = 4 
m = 10 
small = (np.arange(0,m).reshape(m,1).repeat(d,1).T.reshape(-1,1)) 
shifter = (np.arange(0,d).repeat(m).reshape(-1,1).T * m) 
NewIndex = (shifter.reshape(d,-1) + small.reshape(d,-1)).T.reshape(-1,1) 
NewIndex = NewIndex.reshape(-1) 
test = test.ix[NewIndex] 
+0

C'è un altro approccio che coinvolge pd.stack e pd.merge che potrebbero funzionare. Dipende dai campi temporali. Come vedo i campi nei tuoi dati, le righe 3 e 4 hanno lo stesso timbro di ora e giorno. È un prodotto della formattazione o della precisione in cui i dati sono registrati. Chiedo perché quando mostri l'output: – BKay

+0

Se è solo la formattazione e il tempo è registrato con precisione che tutte le voci sono uniche, quindi impilare e unire sarebbe fallo. Fammi sapere e posterò del codice. – BKay

1

Ecco una soluzione basata sull'indicizzazione di numpy e l'indicizzazione di array per creare valori di de-stack e l'unione di panda per l'output del risultato concatenato.

Prima caricare un campione dei dati in un DataFrame (leggermente modificato gli argomenti di read_csv).

from cStringIO import StringIO 

data = """; No Time Date MoistAve MatTemp TDRConduct TDRAve DeltaCount tpAve Moist1 Moist2 Moist3 Moist4 TDR1 TDR2 TDR3 TDR4 
1 11:38:17 11.07.2012 11.37 48.20 5.15 88.87 15 344.50 11.84 11.35 11.59 15.25 89.0 89.0 89.0 88.0 
2 11:38:18 11.07.2012 11.44 48.20 5.13 88.88 2 346.22 12.08 11.83 -1.00 -1.00 89.0 89.0 -1.0 -1.0 
3 11:38:19 11.07.2012 11.10 48.20 4.96 89.00 3 337.84 11.83 11.59 10.62 -1.00 89.0 89.0 89.0 -1.0 
4 11:38:19 11.07.2012 11.82 48.20 5.54 88.60 3 355.92 11.10 13.54 12.32 -1.00 89.0 88.0 88.0 -1.0 
""" 

date_spec = {'FetchTime': [1, 2]} 
df = pd.read_csv(StringIO(data), header=0, sep='\s\s+',parse_dates=date_spec, na_values=['-1.0', '-1.00']) 

Poi costruire un de-stacked vettore di TDR e fonderlo con il frame di dati originali

stacked_col_names = ['TDR1','TDR2','TDR3','TDR4'] 

repeated_row_indexes = np.repeat(np.arange(df.shape[0]),4) 
repeated_col_indexes = [np.where(df.columns == c)[0][0] for c in stacked_col_names] 

destacked_tdrs = pd.DataFrame(data=df.values[repeated_row_indexes,repeated_col_indexes],index=df.index[repeated_row_indexes],columns=['TDR']) 

ouput = pd.merge(left_index = True, right_index = True, left = df, right = destacked_tdrs) 

Con l'output desiderato:

output.ix[:,['TDR1','TDR2','TDR3','TDR4','TDR']] 

    TDR1 TDR2 TDR3 TDR4 TDR 
0 89 89 89 88 89 
0 89 89 89 88 89 
0 89 89 89 88 89 
0 89 89 89 88 88 
1 89 89 NaN NaN 89 
1 89 89 NaN NaN 89 
1 89 89 NaN NaN NaN 
1 89 89 NaN NaN NaN 
2 89 89 89 NaN 89 
2 89 89 89 NaN 89 
2 89 89 89 NaN 89 
2 89 89 89 NaN NaN 
3 89 88 88 NaN 89 
3 89 88 88 NaN 88 
3 89 88 88 NaN 88 
3 89 88 88 NaN NaN