#python #pandas #finance
Вопрос:
У меня есть pd.DataFrame (pandas.core.frame.Фрейм данных) с некоторыми биржевыми сделками.
data = {'Date': ['2021-01-15', '2021-01-21', '2021-02-28', '2021-01-30', '2021-02-16', '2021-03-22', '2021-01-08', '2021-03-02', '2021-02-25', '2021-04-04', '2021-03-15', '2021-04-08'], 'Ticker': ['MFST', 'AMZN', 'GOOG', 'AAPL','MFST', 'AMZN', 'GOOG', 'AAPL','MFST', 'AMZN', 'GOOG', 'AAPL'], 'Quantity': [2,3,7,2,6,4,-3,8,-2,9,11,1]}
df = pd.DataFrame(data)
Date Ticker Quantity
0 2021-01-15 MFST 2
1 2021-01-21 AMZN 3
2 2021-02-28 GOOG 7
3 2021-01-30 AAPL 2
4 2021-02-16 MFST 6
5 2021-03-22 AMZN 4
6 2021-01-08 GOOG -3
7 2021-03-02 AAPL 8
8 2021-02-25 MFST -2
9 2021-04-04 AMZN 9
10 2021-03-15 GOOG 11
11 2021-04-08 AAPL 1
Количество относится к количеству купленных акций.
Я ищу эффективный способ создания нового df, который содержит количество акций для каждого тикера в день.
Первая сделка состоялась в 2021-01-08, а последняя-в 2021-04-08. Мне нужен новый фрейм данных, содержащий все дни между этими датами в виде строк и тикеры в виде столбцов. Значениями должно быть количество акций, которыми я владею в определенный день. Следовательно, если я куплю 4 акции в 2021-03-15 годах (при условии, что дальнейшая покупка или продажа не будет) Они будут у меня с 2021-03-15 по 2021-04-08, которые должны быть представлены в виде 4 в каждой строке для этого конкретного тикера. Если я решу купить больше акций, это число изменится в тот день и во все последующие дни.
Может быть что-то вроде этого:
Date MFST AMZN GOOG APPL
2021-01-08 2 3 1 0
2021-01-09 2 3 1 0
2021-01-10 2 3 1 0
...
2021-04-08 2 3 1 7
Мое первое предположение состояло в том, чтобы создать пустой фрейм данных, а затем выполнить итерацию с двумя циклами for по всем его датам и тикерам. Однако я думаю, что это не самый эффективный способ. Я благодарен за любую рекомендацию!
Ответ №1:
Вы можете использовать df.pivot()
для преобразования ваших данных в табличную форму, как показано на ожидаемом макете вывода, следующим образом:
df.pivot(index='Date', columns='Ticker', values='Quantity').rename_axis(columns=None).reset_index().fillna(0, downcast='infer')
Если вам нужно агрегировать Quantity
данные на одну и ту же дату для каждой акции, вы можете использовать df.pivot_table()
параметр with aggfunc='sum'
следующим образом:
df.pivot_table(index='Date', columns='Ticker', values='Quantity', aggfunc='sum').rename_axis(columns=None).reset_index().fillna(0, downcast='infer')
Результат:
Date AAPL AMZN GOOG MFST
0 2021-01-21 0 3 0 0
1 2021-02-28 0 0 1 0
2 2021-03-15 0 0 0 2
3 2021-04-30 7 0 0 0
Дополнительный Тестовый Случай:
Чтобы продемонстрировать функцию агрегирования df.pivot_table()
, я добавил некоторые данные следующим образом:
data = {'Date': ['2021-03-15',
'2021-01-21',
'2021-01-21',
'2021-02-28',
'2021-02-28',
'2021-04-30',
'2021-04-30'],
'Ticker': ['MFST', 'AMZN', 'AMZN', 'GOOG', 'GOOG', 'AAPL', 'AAPL'],
'Quantity': [2, 3, 4, 1, 2, 7, 2]}
df = pd.DataFrame(data)
Date Ticker Quantity
0 2021-03-15 MFST 2
1 2021-01-21 AMZN 3
2 2021-01-21 AMZN 4
3 2021-02-28 GOOG 1
4 2021-02-28 GOOG 2
5 2021-04-30 AAPL 7
6 2021-04-30 AAPL 2
df.pivot_table(index='Date', columns='Ticker', values='Quantity', aggfunc='sum').rename_axis(columns=None).reset_index().fillna(0, downcast='infer')
Date AAPL AMZN GOOG MFST
0 2021-01-21 0 7 0 0
1 2021-02-28 0 0 3 0
2 2021-03-15 0 0 0 2
3 2021-04-30 9 0 0 0
Редактировать
На основе последних требований:
Первая сделка состоялась в 2021-03-15 годах, а последняя-в 2021-04-30 годах. Мне нужен новый фрейм данных, содержащий все дни между этими датами в виде строк и тикеры в виде столбцов. Значениями должно быть количество акций, которыми я владею в определенный день. Следовательно, если я куплю 4 акции в 2021-03-15 годах (при условии, что дальнейшая покупка или продажа не будет) У меня они будут с 2021-03-15 по 2021-04-30, которые должны быть представлены в виде 4 в каждой строке для этого конкретного тикера. Если я решу купить больше акций, это число изменится в тот день и во все последующие дни.
Вот усовершенствованное решение:
data = {'Date': ['2021-01-15', '2021-01-21', '2021-02-28', '2021-01-30', '2021-02-16', '2021-03-22', '2021-01-08', '2021-03-02', '2021-02-25', '2021-04-04', '2021-03-15', '2021-04-08'], 'Ticker': ['MFST', 'AMZN', 'GOOG', 'AAPL','MFST', 'AMZN', 'GOOG', 'AAPL','MFST', 'AMZN', 'GOOG', 'AAPL'], 'Quantity': [2,3,7,2,6,4,-3,8,-2,9,11,1]}
df = pd.DataFrame(data)
df['Date'] = pd.to_datetime(df['Date'])
df = df.sort_values('Date')
df1 = df.set_index('Date').asfreq('D')
df1['Ticker'] = df1['Ticker'].ffill().bfill()
df1['Quantity'] = df1['Quantity'].fillna(0)
df2 = df1.pivot_table(index='Date', columns='Ticker', values='Quantity', aggfunc='sum').rename_axis(columns=None).reset_index().fillna(0, downcast='infer')
df3 = df2[['Date']].join(df2.iloc[:,1:].cumsum())
Результат:
print(df3)
Date AAPL AMZN GOOG MFST
0 2021-01-08 0 0 -3 0
1 2021-01-09 0 0 -3 0
2 2021-01-10 0 0 -3 0
3 2021-01-11 0 0 -3 0
4 2021-01-12 0 0 -3 0
5 2021-01-13 0 0 -3 0
6 2021-01-14 0 0 -3 0
7 2021-01-15 0 0 -3 2
8 2021-01-16 0 0 -3 2
9 2021-01-17 0 0 -3 2
10 2021-01-18 0 0 -3 2
11 2021-01-19 0 0 -3 2
12 2021-01-20 0 0 -3 2
13 2021-01-21 0 3 -3 2
14 2021-01-22 0 3 -3 2
15 2021-01-23 0 3 -3 2
16 2021-01-24 0 3 -3 2
17 2021-01-25 0 3 -3 2
18 2021-01-26 0 3 -3 2
19 2021-01-27 0 3 -3 2
20 2021-01-28 0 3 -3 2
21 2021-01-29 0 3 -3 2
22 2021-01-30 2 3 -3 2
23 2021-01-31 2 3 -3 2
24 2021-02-01 2 3 -3 2
25 2021-02-02 2 3 -3 2
26 2021-02-03 2 3 -3 2
27 2021-02-04 2 3 -3 2
28 2021-02-05 2 3 -3 2
29 2021-02-06 2 3 -3 2
30 2021-02-07 2 3 -3 2
31 2021-02-08 2 3 -3 2
32 2021-02-09 2 3 -3 2
33 2021-02-10 2 3 -3 2
34 2021-02-11 2 3 -3 2
35 2021-02-12 2 3 -3 2
36 2021-02-13 2 3 -3 2
37 2021-02-14 2 3 -3 2
38 2021-02-15 2 3 -3 2
39 2021-02-16 2 3 -3 8
40 2021-02-17 2 3 -3 8
41 2021-02-18 2 3 -3 8
42 2021-02-19 2 3 -3 8
43 2021-02-20 2 3 -3 8
44 2021-02-21 2 3 -3 8
45 2021-02-22 2 3 -3 8
46 2021-02-23 2 3 -3 8
47 2021-02-24 2 3 -3 8
48 2021-02-25 2 3 -3 6
49 2021-02-26 2 3 -3 6
50 2021-02-27 2 3 -3 6
51 2021-02-28 2 3 4 6
52 2021-03-01 2 3 4 6
53 2021-03-02 10 3 4 6
54 2021-03-03 10 3 4 6
55 2021-03-04 10 3 4 6
56 2021-03-05 10 3 4 6
57 2021-03-06 10 3 4 6
58 2021-03-07 10 3 4 6
59 2021-03-08 10 3 4 6
60 2021-03-09 10 3 4 6
61 2021-03-10 10 3 4 6
62 2021-03-11 10 3 4 6
63 2021-03-12 10 3 4 6
64 2021-03-13 10 3 4 6
65 2021-03-14 10 3 4 6
66 2021-03-15 10 3 15 6
67 2021-03-16 10 3 15 6
68 2021-03-17 10 3 15 6
69 2021-03-18 10 3 15 6
70 2021-03-19 10 3 15 6
71 2021-03-20 10 3 15 6
72 2021-03-21 10 3 15 6
73 2021-03-22 10 7 15 6
74 2021-03-23 10 7 15 6
75 2021-03-24 10 7 15 6
76 2021-03-25 10 7 15 6
77 2021-03-26 10 7 15 6
78 2021-03-27 10 7 15 6
79 2021-03-28 10 7 15 6
80 2021-03-29 10 7 15 6
81 2021-03-30 10 7 15 6
82 2021-03-31 10 7 15 6
83 2021-04-01 10 7 15 6
84 2021-04-02 10 7 15 6
85 2021-04-03 10 7 15 6
86 2021-04-04 10 16 15 6
87 2021-04-05 10 16 15 6
88 2021-04-06 10 16 15 6
89 2021-04-07 10 16 15 6
90 2021-04-08 11 16 15 6
Комментарии:
1. Спасибо за этот намек. Как бы вы перешли оттуда к фрейму данных, который содержит количество акций на тикер и за день?
2. @Philipp Извините, не могли бы вы немного подробнее объяснить свой вопрос ? Что именно вы хотите знать ?
3. @Philipp Будет ли более одной записи для каждого тикера на каждую дату ? Если нет, просто используйте мою первую часть решения, чтобы получить нужный вам макет. Если да, используйте второе. Оба они представлены в табличной форме с тикерами в виде столбцов в соответствии с вашим желаемым макетом.
4. Конечно. Первая сделка состоялась в 2021-03-15 годах, а последняя-в 2021-04-30 годах. Мне нужен новый фрейм данных, содержащий все дни между этими датами в виде строк и тикеры в виде столбцов. Значениями должно быть количество акций, которыми я владею в определенный день. Следовательно, если я куплю 4 акции в 2021-03-15 годах (при условии, что дальнейшая покупка или продажа не будет) У меня они будут с 2021-03-15 по 2021-04-30, которые должны быть представлены в виде 4 в каждой строке для этого конкретного тикера. Если я решу купить больше акций, это число изменится в тот день и во все последующие дни.
5. @Philipp Найдите, что моя правка выше переписана с учетом ваших пересмотренных требований.
Ответ №2:
Воспользуйся df.groupby
df.groupby(['Date']).agg('sum')