DataFrame计算平均购买价格

时间:2017-08-01 22:17:59

标签: python pandas dataframe

我有一个包含两列的数据框:数量和价格。

df = pd.DataFrame([
[ 1, 5],
[-1, 6],
[ 2, 3],
[-1, 2],
[-1, 4],
[ 1, 2],
[ 1, 3],
[ 1, 4],
[-2, 5]], columns=['quantity', 'price'])

df['amount'] = df['quantity'] * df['price']
df['cum_qty'] = df['quantity'].cumsum()

我添加了两个新列金额和cum_qty(累计数量)。 现在数据框看起来像这样(正数表示买入,负数表示卖出):

   quantity  price  amount  cum_qty
0         1      5       5        1
1        -1      6      -6        0
2         2      3       6        2
3        -1      2      -2        1
4        -1      4      -4        0
5         1      2       2        1
6         1      3       3        2
7         1      4       4        3
8        -2      5     -10        1

我想计算平均买入价。

每当cum_qty = 0时,qantity和amount应重置为零。 所以我们正在查看index = [5,6,7]的行。 对于每一行,一个项目以2,3和4的价格购买,这意味着我的每个库存3,平均价格为3 [(2 + 3 + 4)/ 3]。

在指数= 8卖出后(卖出交易不改变买入价),我将以3的价格买到一个。

所以,基本上,我必须将所有累积购买金额除以上次累计数量不是零的累计数量。

如何通过pandas DataFrame进行所有交易来计算手头买入量?

3 个答案:

答案 0 :(得分:1)

根据我的理解,您需要为每个交易圈购买价格,然后您可以试试这个。

df['new_index'] = df.cum_qty.eq(0).shift().cumsum().fillna(0.)#give back the group id for each trading circle.*
df=df.loc[df.quantity>0]# kick out the selling action
df.groupby('new_index').apply(lambda x:(x.amount.sum()/x.quantity.sum()))

new_index
0.0    5.0# 1st ave price 5
1.0    3.0# 2nd ave price 3
2.0    3.0# 3nd ave price 3 ps: this circle no end , your position still pos 1
dtype: float64

EDIT1为您提供额外要求

DF=df.groupby('new_index',as_index=False).apply(lambda x : x.amount.cumsum()/ x.cum_qty).reset_index()
DF.columns=['Index','AvePrice']
DF.index=DF.level_1
DF.drop(['level_0',  'level_1'],axis=1,inplace=True)
pd.concat([df,DF],axis=1)

Out[572]: 
         quantity  price  amount  cum_qty  new_index    0
level_1                                                  
0               1      5       5        1        0.0  5.0
2               2      3       6        2        1.0  3.0
5               1      2       2        1        2.0  2.0
6               1      3       3        2        2.0  2.5
7               1      4       4        3        2.0  3.0

答案 1 :(得分:1)

这是使用循环的另一种解决方案:

import pandas as pd
import numpy as np

# Original data
df = pd.DataFrame({
    'quantity': [ 1, -1,  2, -1, -1,  1,  1,  1, -2],
    'price': [5, 6, 3, 2, 4, 2, 3, 4, 5]
})

# Process the data and add the new columns
df['amount'] = df['quantity'] * df['price']
df['cum_qty'] = df['quantity'].cumsum()
df['prev_cum_qty'] = df['cum_qty'].shift(1, fill_value=0)
df['average_price'] = np.nan
for i, row in df.iterrows():
    if row['quantity'] > 0:
        df.iloc[i, df.columns == 'average_price' ] = (
            row['amount'] +
            df['average_price'].shift(1, fill_value=df['price'][0])[i] *
            df['prev_cum_qty'][i]
        )/df['cum_qty'][i]
    else:
        df.iloc[i, df.columns == 'average_price' ] = df['average_price'][i-1]
df.drop('prev_cum_qty', axis=1)

此方法的优点是,如果有新的购买,它也将起作用 cum_qty变为零之前。例如,假设有一个新购买 5的价格为3的价格,也就是说,在处理 数据:

# Add more data, exemplifying a different situation
df = df.append({'quantity': 5, 'price': 3}, ignore_index=True)

我希望得到以下结果:

   quantity  price  amount  cum_qty  average_price
0         1      5       5        1            5.0
1        -1      6      -6        0            5.0
2         2      3       6        2            3.0
3        -1      2      -2        1            3.0
4        -1      4      -4        0            3.0
5         1      2       2        1            2.0
6         1      3       3        2            2.5
7         1      4       4        3            3.0
8        -2      5     -10        1            3.0
9         5      3      15        6            3.0 # Not 4.0

也就是说,由于仍然有3件商品以3元的价格购买,所以cum_qty现在是6元,平均价格仍然是3元。

答案 2 :(得分:0)

df[df['cum_qty'].map(lambda x: x == 0)].index

将为您提供cum_qty为0

的行
df[df['cum_qty'].map(lambda x: x == 0)].index.max()

为您提供0 cum_qty

的最后一行
start = df[df['cum_qty'].map(lambda x: x == 0)].index.max() + 1
end = len(df) - 1

为您提供您所指的范围的起始和结束行号

df['price'][start:end].sum() / df['quantity'][start:end].sum()

为您提供您在给出的示例中所做的答案

如果你想知道每次出现的cum_qty 0的这个值,那么你可以使用每个的索引(我的第一行代码的结果)来应用开始/结束逻辑。

相关问题