2013-02-01 25 views
6

Ho problemi a mascherare un pannello nello stesso modo in cui vorrei un DataFrame. Quello che voglio fare è semplice, ma non ho trovato un modo per guardare i documenti e i forum online. Ho un semplice esempio qui sotto:maschera booleana in pannello panda

import pandas 
import numpy as np 
import datetime 
start_date = datetime.datetime(2009,3,1,6,29,59) 
r = pandas.date_range(start_date, periods=12) 
cols_1 = ['AAPL', 'AAPL', 'GOOG', 'GOOG', 'GS', 'GS'] 
cols_2 = ['close', 'rate', 'close', 'rate', 'close', 'rate'] 
dat = np.random.randn(12, 6) 

dftst = pandas.DataFrame(dat, columns=pandas.MultiIndex.from_arrays([cols_1, cols_2], names=['ticker','field']), index=r) 
pn = dftst.T.to_panel().transpose(2,0,1) 
print pn 

Out[14]: 
<class 'pandas.core.panel.Panel'> 
Dimensions: 2 (items) x 12 (major_axis) x 3 (minor_axis) 
Items axis: close to rate 
Major_axis axis: 2009-03-01 06:29:59 to 2009-03-12 06:29:59 
Minor_axis axis: AAPL to GS 

ora ho un oggetto del pannello, se prendo una fetta lungo l'asse articoli, ottengo un dataframe

close_p = pn['close'] 
print close_p 

Out[16]: 
ticker     AAPL  GOOG  GS 
2009-03-01 06:29:59 -0.082203 -0.286354 1.227193 
2009-03-02 06:29:59 0.340005 -0.688933 -1.505137 
2009-03-03 06:29:59 -0.525567 0.321858 -0.035047 
2009-03-04 06:29:59 -0.123549 -0.841781 -0.616523 
2009-03-05 06:29:59 -0.407504 0.188372 1.311262 
2009-03-06 06:29:59 0.272883 0.817179 0.584664 
2009-03-07 06:29:59 -1.767227 1.168876 0.443096 
2009-03-08 06:29:59 -0.685501 -0.534373 -0.063906 
2009-03-09 06:29:59 0.851820 0.068740 0.566537 
2009-03-10 06:29:59 0.390678 -0.012422 -0.152375 
2009-03-11 06:29:59 -0.985585 -0.917705 -0.585091 
2009-03-12 06:29:59 0.067498 -0.764343 0.497270 

posso filtrare questi dati in due modi :

1) creo una maschera e mascherare i dati come segue:

msk = close_p > 0 
close_p = close_p.mask(msk) 

2) posso solo tagliare dal op booleano erator in MSK sopra

close_p = close_p[close_p > 0] 
Out[28]: 
ticker     AAPL  GOOG  GS 
2009-03-01 06:29:59  NaN  NaN 1.227193 
2009-03-02 06:29:59 0.340005  NaN  NaN 
2009-03-03 06:29:59  NaN 0.321858  NaN 
2009-03-04 06:29:59  NaN  NaN  NaN 
2009-03-05 06:29:59  NaN 0.188372 1.311262 
2009-03-06 06:29:59 0.272883 0.817179 0.584664 
2009-03-07 06:29:59  NaN 1.168876 0.443096 
2009-03-08 06:29:59  NaN  NaN  NaN 
2009-03-09 06:29:59 0.851820 0.068740 0.566537 
2009-03-10 06:29:59 0.390678  NaN  NaN 
2009-03-11 06:29:59  NaN  NaN  NaN 
2009-03-12 06:29:59 0.067498  NaN 0.497270 

Quello che non riesco a capire come fare è il filtro tutti i miei dati sulla base di una maschera senza un ciclo for. Posso fare quanto segue:

msk = (pn['rate'] > 0) & (pn['close'] > 0) 
def mask_panel(pan, msk): 
    for item in pan.items: 
     pan[item] = pan[item].mask(msk) 
    return pan 
print pn['close'] 

Out[32]: 
ticker     AAPL  GOOG  GS 
2009-03-01 06:29:59 -0.082203 -0.286354 1.227193 
2009-03-02 06:29:59 0.340005 -0.688933 -1.505137 
2009-03-03 06:29:59 -0.525567 0.321858 -0.035047 
2009-03-04 06:29:59 -0.123549 -0.841781 -0.616523 
2009-03-05 06:29:59 -0.407504 0.188372 1.311262 
2009-03-06 06:29:59 0.272883 0.817179 0.584664 
2009-03-07 06:29:59 -1.767227 1.168876 0.443096 
2009-03-08 06:29:59 -0.685501 -0.534373 -0.063906 
2009-03-09 06:29:59 0.851820 0.068740 0.566537 
2009-03-10 06:29:59 0.390678 -0.012422 -0.152375 
2009-03-11 06:29:59 -0.985585 -0.917705 -0.585091 
2009-03-12 06:29:59 0.067498 -0.764343 0.497270 

mask_panel(pn, msk) 

print pn['close'] 

Out[34]: 
ticker     AAPL  GOOG  GS 
2009-03-01 06:29:59 -0.082203 -0.286354  NaN 
2009-03-02 06:29:59  NaN -0.688933 -1.505137 
2009-03-03 06:29:59 -0.525567  NaN -0.035047 
2009-03-04 06:29:59 -0.123549 -0.841781 -0.616523 
2009-03-05 06:29:59 -0.407504  NaN  NaN 
2009-03-06 06:29:59  NaN  NaN  NaN 
2009-03-07 06:29:59 -1.767227  NaN  NaN 
2009-03-08 06:29:59 -0.685501 -0.534373 -0.063906 
2009-03-09 06:29:59  NaN  NaN  NaN 
2009-03-10 06:29:59  NaN -0.012422 -0.152375 
2009-03-11 06:29:59 -0.985585 -0.917705 -0.585091 
2009-03-12 06:29:59  NaN -0.764343  NaN 

Quindi il ciclo di cui sopra fa il trucco. So che c'è un modo più veloce per fare questo usando il ndarray, ma non l'ho ancora messo insieme. Sembra anche che questa dovrebbe essere la funzionalità incorporata nella libreria pandas. Se c'è un modo per farlo che mi manca, qualsiasi suggerimento sarebbe molto apprezzato.

+0

Ci si sente come si dovrebbe essere in grado per usare il pannello booleano 'pn.gt (0)' ... –

+0

grazie Andy, a meno che non sbaglio penso che farebbe qualcosa di diverso. Ciò renderebbe nullo ogni DataFrame nel mio pannello in cui i suoi valori sono inferiori a 0. Ciò che voglio fare è nidificare ogni DataFrame nel mio Pannello, dove 'close' è minore di 0. Di nuovo, close è uno specifico DataFrame nel mio Pannello . Continuerò a giocherellare e pubblicare se trovo qualcosa di più bello. – granders19

+0

Ciò influirebbe solo sulla dataframe chiusa (parte del pannello)? Vuoi cambiarlo nel pannello e lasciare l'altro invariato? –

risposta

9

penso che questo funzionerà (e cosa Panel.where dovrebbe fare, ma è un po 'non banale perché deve gestire un gruppo di casi)

# construct the mask in 2-d (a frame) 
In [36]: mask = (pn['close']>0) & (pn['rate']>0) 

In [37]: mask 
Out[37]: 
ticker    AAPL GOOG  GS 
2009-03-01 06:29:59 False False False 
2009-03-02 06:29:59 False False True 
.... 

# here's the key, this broadcasts, setting the values which 
# don't meet the condition to nan 
In [38]: masked_values = np.where(mask,pn.values,np.nan) 

# reconstruct the panel (the _construct_axes_dict is an internal function that returns 
# dict of the axes, e.g. items -> the items, major_axis -> ..... 
In [42]: x = pd.Panel(masked_values,**pn._construct_axes_dict()) 
Out[42]: 
<class 'pandas.core.panel.Panel'> 
Dimensions: 2 (items) x 12 (major_axis) x 3 (minor_axis) 
Items axis: close to rate 
Major_axis axis: 2009-03-01 06:29:59 to 2009-03-12 06:29:59 
Minor_axis axis: AAPL to GS 

# the values 
In [43]: x 
Out[43]: 
array([[[  nan,   nan,   nan], 
    [  nan,   nan, 0.09575723], 
    [  nan,   nan,   nan], 
    [  nan,   nan,   nan], 
    [  nan, 2.07229823, 0.04347515], 
    [  nan,   nan,   nan], 
    [  nan,   nan, 2.18342239], 
    [  nan,   nan, 1.73674381], 
    [  nan, 2.01173087,   nan], 
    [ 0.24109645, 0.94583072,   nan], 
    [ 0.36953467,   nan, 0.18044432], 
    [ 1.74164222, 1.02314752, 1.73736033]], 

    [[  nan,   nan,   nan], 
    [  nan,   nan, 0.06960387], 
    [  nan,   nan,   nan], 
    [  nan,   nan,   nan], 
    [  nan, 0.63202199, 0.56724391], 
    [  nan,   nan,   nan], 
    [  nan,   nan, 0.71964824], 
    [  nan,   nan, 1.03482927], 
    [  nan, 0.18256148,   nan], 
    [ 1.29451667, 0.49804327,   nan], 
    [ 2.04726538,   nan, 0.12883128], 
    [ 0.70647885, 0.7277734 , 0.77844475]]]) 
+0

grazie Jeff, ha funzionato alla grande! è una soluzione migliore rispetto al ciclo che ho creato. Sono d'accordo che sarebbe bello se questo fosse incorporato in un metodo .where per i pannelli. – granders19

+0

no prob - ci arriveremo ad un certo punto https://github.com/pydata/pandas/issues/2790 – Jeff