2013-07-21 18 views
6

Ho uno DataFrame che contiene valori di magazzino.Nuova colonna in base alla selezione condizionale dai valori di 2 altre colonne in un DataFrame di Pandas

Ecco come si presenta:

>>>Data Open High Low Close Volume Adj Close Date              
2013-07-08 76.91 77.81 76.85 77.04 5106200 77.04 

Quando provo a fare una nuova colonna condizionale con la seguente if:

Data['Test'] =Data['Close'] if Data['Close'] > Data['Open'] else Data['Open'] 

ottengo il seguente errore:

Traceback (most recent call last): 
    File "<pyshell#116>", line 1, in <module> 
    Data[1]['Test'] =Data[1]['Close'] if Data[1]['Close'] > Data[1]['Open'] else Data[1]['Open'] 
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all() 

Ho quindi utilizzato a.all():

Data[1]['Test'] =Data[1]['Close'] if all(Data[1]['Close'] > Data[1]['Open']) else Data[1]['Open'] 

Il risultato è stato che è stata selezionata l'intera colonna ['Open']. Non ho ottenuto la condizione che volevo, ovvero selezionare ogni volta il valore più grande tra le colonne ['Open'] e ['Close'].

Qualsiasi aiuto è apprezzato.

Grazie.

risposta

4

Da un dataframe come:

>>> df 
     Date Open High Low Close Volume Adj Close 
0 2013-07-08 76.91 77.81 76.85 77.04 5106200  77.04 
1 2013-07-00 77.04 79.81 71.81 72.87 1920834  77.04 
2 2013-07-10 72.87 99.81 64.23 93.23 2934843  77.04 

La cosa più semplice che posso pensare sarebbe:

>>> df["Test"] = df[["Open", "Close"]].max(axis=1) 
>>> df 
     Date Open High Low Close Volume Adj Close Test 
0 2013-07-08 76.91 77.81 76.85 77.04 5106200  77.04 77.04 
1 2013-07-00 77.04 79.81 71.81 72.87 1920834  77.04 77.04 
2 2013-07-10 72.87 99.81 64.23 93.23 2934843  77.04 93.23 

df.ix[:,["Open", "Close"]].max(axis=1) potrebbe essere un po 'più veloce, ma non credo che sia come piacevole da guardare a.

In alternativa, è possibile utilizzare .apply sulle righe:

>>> df["Test"] = df.apply(lambda row: max(row["Open"], row["Close"]), axis=1) 
>>> df 
     Date Open High Low Close Volume Adj Close Test 
0 2013-07-08 76.91 77.81 76.85 77.04 5106200  77.04 77.04 
1 2013-07-00 77.04 79.81 71.81 72.87 1920834  77.04 77.04 
2 2013-07-10 72.87 99.81 64.23 93.23 2934843  77.04 93.23 

O ricadere NumPy:

>>> df["Test"] = np.maximum(df["Open"], df["Close"]) 
>>> df 
     Date Open High Low Close Volume Adj Close Test 
0 2013-07-08 76.91 77.81 76.85 77.04 5106200  77.04 77.04 
1 2013-07-00 77.04 79.81 71.81 72.87 1920834  77.04 77.04 
2 2013-07-10 72.87 99.81 64.23 93.23 2934843  77.04 93.23 

Il problema di fondo è che if/else non gioca bene con gli array, perché if (something) imposta sempre something in un singolo bool.Non è equivalente a "per ogni elemento nell'array qualcosa, se la condizione vale" o qualcosa del genere.

0

Il problema è che stai chiedendo a python di valutare una condizione (Data['Close'] > Data['Open']) che contiene più di un valore booleano. Non si desidera utilizzare any o all in quanto, poiché ciò imposterà Data['Test'] su Data['Open'] o Data['Close'].

Ci potrebbe essere un metodo più pulito, ma un approccio è quello di utilizzare una maschera (array booleano):

mask = Data['Close'] > Data['Open'] 
Data['Test'] = pandas.concat([Data['Close'][mask].dropna(), Data['Open'][~mask].dropna()]).reindex_like(Data) 
3
In [7]: df = DataFrame(randn(10,2),columns=list('AB')) 

In [8]: df 
Out[8]: 
      A   B 
0 -0.954317 -0.485977 
1 0.364845 -0.193453 
2 0.020029 -1.839100 
3 0.778569 0.706864 
4 0.033878 0.437513 
5 0.362016 0.171303 
6 2.880953 0.856434 
7 -0.109541 0.624493 
8 1.015952 0.395829 
9 -0.337494 1.843267 

Questa è una in cui condizionale, dicendo dammi il valore per A se A> B, altrimenti dammi B

# this syntax is EQUIVALENT to 
# df.loc[df['A']>df['B'],'A'] = df['B'] 

In [9]: df['A'].where(df['A']>df['B'],df['B']) 
Out[9]: 
0 -0.485977 
1 0.364845 
2 0.020029 
3 0.778569 
4 0.437513 
5 0.362016 
6 2.880953 
7 0.624493 
8 1.015952 
9 1.843267 
dtype: float64 

In questo caso max equivale

In [10]: df.max(1) 
Out[10]: 
0 -0.485977 
1 0.364845 
2 0.020029 
3 0.778569 
4 0.437513 
5 0.362016 
6 2.880953 
7 0.624493 
8 1.015952 
9 1.843267 
dtype: float64 
+0

dove ho '' df ['B'] '' puoi inserire uno scalare (ad es. 'Chiudi'), anche se dovresti farlo in un'altra colonna (es. Colonne da cui selezioni, '' df [' A '] '' non deve essere uguale alla maschera '' df [' A ']> df [' B '] '', altrimenti otterrai una colonna flottante/stringa mista, generalmente non utile (e non efficiente per qualsiasi cosa) .Puoi anche avere un'altra colonna dove ho '' df ['B'] '' come valore di sostituzione (e i panda lo allineeranno alla colonna del selettore). FYI questo è esattamente equivalente a: '' df .loc [df ['A']> df ['B'], 'A'] = df ['B'] '' – Jeff

Problemi correlati