2012-12-27 17 views
29

Próbuję pomnożyć dwie istniejące kolumny w DataFame pandy (orders_df) - Ceny (cena zamknięcia) i Kwota (wielkości zapasów) i dodaj obliczenia do nowej kolumny o nazwie "Wartość". Z jakiegoś powodu, gdy uruchamiam ten kod, wszystkie wiersze w kolumnie "Wartość" są liczbami dodatnimi, a niektóre wiersze powinny być ujemne. W kolumnie Action w DataFrame znajduje się siedem wierszy z łańcuchem "Sell" i siedmiu z łańcuchem "Buy".Chcę pomnożyć dwie kolumny w DataFrame pand i dodać wynik do nowej kolumny

for i in orders_df.Action: 
if i == 'Sell': 
    orders_df['Value'] = orders_df.Prices*orders_df.Amount 
elif i == 'Buy': 
    orders_df['Value'] = -orders_df.Prices*orders_df.Amount) 

Proszę dać mi znać, co robię źle!

Odpowiedz

12

Jeśli jesteśmy gotowi poświęcić lapidarność roztworu Haydena, można też zrobić coś takiego:

In [22]: orders_df['C'] = orders_df.Action.apply(
       lambda x: (1 if x == 'Sell' else -1)) 

In [23]: orders_df # New column C represents the sign of the transaction 
Out[23]: 
    Prices Amount Action C 
0  3  57 Sell 1 
1  89  42 Sell 1 
2  45  70 Buy -1 
3  6  43 Sell 1 
4  60  47 Sell 1 
5  19  16 Buy -1 
6  56  89 Sell 1 
7  3  28 Buy -1 
8  56  69 Sell 1 
9  90  49 Buy -1 

Teraz musimy wyeliminować potrzebę rachunku if. Używając DataFrame.apply(), usuwamy również pętlę . Jak zauważył Hayden, operacje wektorowe są zawsze szybsze.

In [24]: orders_df['Value'] = orders_df.Prices * orders_df.Amount * orders_df.C 

In [25]: orders_df # The resulting dataframe 
Out[25]: 
    Prices Amount Action C Value 
0  3  57 Sell 1 171 
1  89  42 Sell 1 3738 
2  45  70 Buy -1 -3150 
3  6  43 Sell 1 258 
4  60  47 Sell 1 2820 
5  19  16 Buy -1 -304 
6  56  89 Sell 1 4984 
7  3  28 Buy -1 -84 
8  56  69 Sell 1 3864 
9  90  49 Buy -1 -4410 

To rozwiązanie zajmuje dwa wiersze kodu, a nie jedno, ale jest nieco łatwiejsze do odczytania. Podejrzewam, że koszty obliczeniowe są również podobne.

17

Można użyć metody DataFrame apply:

order_df['Value'] = order_df.apply(lambda row: (row['Prices']*row['Amount'] 
               if row['Action']=='Sell' 
               else -row['Prices']*row['Amount']), 
            axis=1) 

jest to zwykle szybciej korzystać z tych metod zamiast na pętli.

+0

błyskotliwe, dziękuję !! – OAK

58

myślę eleganckim rozwiązaniem jest użycie metody where (również zobaczyć API docs):

In [37]: values = df.Prices * df.Amount 

In [38]: df['Values'] = values.where(df.Action == 'Sell', other=-values) 

In [39]: df 
Out[39]: 
    Prices Amount Action Values 
0  3  57 Sell  171 
1  89  42 Sell 3738 
2  45  70 Buy -3150 
3  6  43 Sell  258 
4  60  47 Sell 2820 
5  19  16 Buy -304 
6  56  89 Sell 4984 
7  3  28 Buy  -84 
8  56  69 Sell 3864 
9  90  49 Buy -4410 

Co więcej powinno być najszybszym rozwiązaniem.

+0

dzięki za rozwiązanie, oba z nich pięknie działają. – OAK

+3

czy możesz wskazać, że to odpowiada na twoje pytanie? –

+1

Oznacz to jako odpowiedź, @OAK – Blairg23

0

Dla mnie, jest to najczystszy i najbardziej intuicyjny:

values = [] 
for action in ['Sell','Buy']: 
    amounts = orders_df['Amounts'][orders_df['Action'==action]].values 
    if action == 'Sell': 
     prices = orders_df['Prices'][orders_df['Action'==action]].values 
    else: 
     prices = -1*orders_df['Prices'][orders_df['Action'==action]].values 
    values += list(amounts*prices) 
orders_df['Values'] = values 

Sposób .values zwraca numpy array pozwala łatwo pomnożyć element mądry, a następnie można kumulatywnie wygenerować listę przez „dodanie” do niego .

3

Ponieważ to pytanie pojawiło się ponownie, myślę, że dobrym czystym podejściem jest używanie assign.

Kod jest dość wyrazisty i samo-opisujące:

df = df.assign(Value = lambda x: x.Prices * x.Amount * x.Action.replace({'Buy' : 1, 'Sell' : -1})) 
Powiązane problemy