#python #pandas #dataframe
#python #pandas #фрейм данных
Вопрос:
Я не знаю, с чего начать, но у меня есть данные для двух портфелей акций, которые мне нужно объединить, чтобы представить один портфель. Ниже приведен фрейм данных, с которого я начинаю, а также с которым я хочу закончить.
Вот данные, которые у меня уже есть
rawdata = {'portfolio': ['port1', 'port2', 'port1', 'port2'],
'portfolioname': ['portfolioone', 'portfoliotwo', 'portfolioone', 'portfoliotwo'],
'date': ['04/12/2020', '04/12/2020', '04/12/2020', '04/12/2020'],
'code': ['ABC', 'ABC', 'XYZ', 'XYZ'],
'quantity': [2, 3, 10, 11],
'price': [1.5, 1.5, 0.2, 0.2],
'value': [3, 4.5, 2, 2.2],
'weight': [.6, .67, .4, .328]}
df1 = pd.DataFrame(rawdata)
Вот данные, которые я хочу создать
finisheddata = {'portfolio': ['port3', 'port3'],
'portfolioname': ['portfoliothree', 'portfoliothree'],
'date': ['04/12/2020', '04/12/2020'],
'code': ['ABC', 'XYZ'],
'quantity': [5, 21],
'price': [1.5, 0.2],
'value': [7.5, 4.2],
'weight': [.64, .36]}
df2 = pd.DataFrame(finisheddata)
Итак, что я пытаюсь сделать, это сгруппировать два портфеля вместе по «коду», где «портфолио» и «имя_портфеля» являются произвольными, «дата» всегда одинакова для обоих портфелей, «количество» — это сумма, «цена» берется либо из порта 1, либо из порта 2, ‘значение ‘ — это ‘цена’ х ‘количество’, а ‘вес’ — это ‘значение’, деленное на сумму портфеля.
Большое, очень большое спасибо.
Комментарии:
1. Как вы определяете имя для ‘port1’ и ‘port2’ после их группировки? Аналогично для portfolioname?
2. Я обновил свой ответ. Первое — это жестко заданное значение для столбцов portfolio и portfolio name после агрегации, второе, которое я реализовал логикой
port5 port6 = port11
иportfolioone portfoliofive = portfoliosix
. В настоящее время работает только для отдельных цифр и их суммы, так что будьте осторожны.
Ответ №1:
Чтобы сохранить столбцы при использовании agg, вы можете использовать ‘first’, как указано ниже:
Код:
import pandas as pd
rawdata = {'portfolio': ['port1', 'port2', 'port1', 'port2'],
'portfolioname': ['portfolioone', 'portfoliotwo', 'portfolioone', 'portfoliotwo'],
'date': ['04/12/2020', '04/12/2020', '04/12/2020', '04/12/2020'],
'code': ['ABC', 'ABC', 'XYZ', 'XYZ'],
'quantity': [2, 3, 10, 11],
'price': [1.5, 1.5, 0.2, 0.2],
'value': [3, 4.5, 2, 2.2],
'weight': [.6, .67, .4, .328]}
df1 = pd.DataFrame(rawdata)
print(df1, 'n')
finisheddata = {'portfolio': ['port3', 'port3'],
'portfolioname': ['portfoliothree', 'portfoliothree'],
'date': ['04/12/2020', '04/12/2020'],
'code': ['ABC', 'XYZ'],
'quantity': [5, 21],
'price': [1.5, 0.2],
'value': [7.5, 4.2],
'weight': [.64, .36]}
df2 = pd.DataFrame(finisheddata) # Desired
print(df2, 'n')
df3 = df1.groupby(['code']).agg({'portfolio' : 'first', 'portfolioname' : 'first', 'date' : 'first', 'quantity': 'sum', 'price' : 'first', 'weight': 'mean'}).reset_index()
df3['value'] = df3.price * df3.quantity
df3 = df3[['portfolio', 'portfolioname', 'date', 'code', 'quantity', 'price', 'value', 'weight']]
df3['portfolio'] = df3['portfolioname'] = 'combined'
print(df3)
Вывод:
portfolio portfolioname date code quantity price value weight
0 port1 portfolioone 04/12/2020 ABC 2 1.5 3.0 0.600
1 port2 portfoliotwo 04/12/2020 ABC 3 1.5 4.5 0.670
2 port1 portfolioone 04/12/2020 XYZ 10 0.2 2.0 0.400
3 port2 portfoliotwo 04/12/2020 XYZ 11 0.2 2.2 0.328
portfolio portfolioname date code quantity price value weight
0 port3 portfoliothree 04/12/2020 ABC 5 1.5 7.5 0.64
1 port3 portfoliothree 04/12/2020 XYZ 21 0.2 4.2 0.36
portfolio portfolioname date code quantity price value weight
0 combined combined 04/12/2020 ABC 5 1.5 7.5 0.635
1 combined combined 04/12/2020 XYZ 21 0.2 4.2 0.364
Ответ №2:
Это неэлегантно, но показывает, как использовать groupby, а затем создавать серию данных. Затем, как только данные будут построены, переместите их в dataframe. После того, как большая часть выходных данных собрана, используйте выходные данные для вычисления веса в dataframe.
data = []
for cname, dfsub in df1.groupby('code'):
port = 'portx'
portname = 'portnew'
code = cname
quant = dfsub.quantity.sum()
date = dfsub.date.iloc[0]
price = dfsub.price.iloc[0]
value = quant * price
data.append([port,portname,date,code,quant,price,value])
dfout = pd.DataFrame(data, columns=['portfolio', 'portfolioname', 'date', 'code', 'quantity', 'price', 'value'])
sumval = dfout.value.sum()
dfout['weight'] = dfout['value'] / sumval
результат выглядит следующим образом
portfolio portfolioname date code quantity price value weight
0 portx portnew 04/12/2020 ABC 5 1.5 7.5 0.641026
1 portx portnew 04/12/2020 XYZ 21 0.2 4.2 0.358974
Если вы хотите уменьшить количество цифр в весе, то dfout.round({'weight': 3})
округлите его до 3 знаков после запятой
Ответ №3:
Вы можете просто определить словарь со столбцами и соответствующими агрегациями и использовать agg()
with groupby()
, чтобы получить то, что вам нужно.
g = {'portfolio':lambda x:'portx',
'portfolioname':lambda x:'portfoliox',
'date':'first',
'quantity':'sum',
'price':'mean',
'value':'sum',
'weight':'mean'}
df1.groupby(['code']).agg(g).reset_index()
code portfolio portfolioname date quantity price value weight
0 ABC portx portfoliox 04/12/2020 5 1.5 7.5 0.635
1 XYZ portx portfoliox 04/12/2020 21 0.2 4.2 0.364
Моя путаница связана с portx
и portfoliox
. Прямо сейчас я жестко запрограммировал их, потому что вы упомянули, что они являются арбитражными. Есть ли логика в объединении port1
port2
строк, которые вы хотите реализовать во время агрегации? Дайте мне знать, и я смогу соответствующим образом обновить свой ответ.
РЕДАКТИРОВАТЬ: агрегирование по portx и portfoliox
Поскольку я не получил ответа от OP, вот код, если вы хотите сгенерировать portx
и portfoliox
на основе существующих значений путем агрегирования —
word2int = {'one': 1,
'two': 2,
'three': 3,
'four': 4,
'five': 5,
'six': 6,
'seven': 7,
'eight': 8,
'nine': 9,
'zero' : 0}
int2word = {v:k for k,v in word2int.items()}
g = {'portfolio':lambda x: 'port' str(sum([int(i[-1]) for i in x])),
'portfolioname':lambda x: 'portfolio' int2word.get(sum([word2int.get(i[9:]) for i in x])),
'date':'first',
'quantity':'sum',
'price':'mean',
'value':'sum',
'weight':'mean'}
df1.groupby(['code']).agg(g).reset_index()
code portfolio portfolioname date quantity price value weight
0 ABC port3 portfoliothree 04/12/2020 5 1.5 7.5 0.635
1 XYZ port3 portfoliothree 04/12/2020 21 0.2 4.2 0.364