получить список процентов равным 100 - PullRequest
0 голосов
/ 30 марта 2019

У меня есть данные, которые показывают, какой вес ETF содержится в стране.Проблема в том, что источник данных имеет незначительные расхождения во взвешивании.Например, для ETF VTI сумма всех процентов (США + Канада) равна 1,026, что означает, что общая сумма составляет приблизительно 102%.

Небольшие процентные расхождения являются проблемой, когда я строю график или отображаю данные, это косметическая / визуальная проблема, когда на графиках отображаются итоговые значения> или <затем 100% </p>

Это то, чтоданные выглядят так:

d = {'Name': [US, US, US, CA], 'Weight': [1, 1, 1.0197, 0.0009], 'ETF': [SPY, IVV, VTI, VTI]}
df = pd.DataFrame(data=d)
df
    Name   Weight     ETF
0     US     1        SPY
1     US     1        IVV
2     US     1.0197   VTI
3     CA     0.0009   VTI

Ниже я написал код, который пытается это исправить, но столкнулся с другой проблемой.Код, который я написал, рассматривает разницу между реальной суммой и 100%, а затем добавляет или вычитает эту разницу по всем значениям в списке, как показано ниже.Проблема в том, что, когда нужно вычесть процент, я получаю небольшие, но, тем не менее, отрицательные значения, что нежелательно.

def re_weight(df):

     etfs= df['ETF'].unique()

     for etf in etfs: 


         l = (df[df['ETF']==etf].shape)[0]
         total = float(df[df['ETF']==etf]['Weight'].sum())
         diff = 1-total 

         filler = diff/l

         df.loc[df['ETF']==etf, 'Weight'] = df[df['ETF']==etf]['Weight']+filler


     return df

countries = pd.read_csv('output\\countries.csv')

countries[['Weight','ETF']] = re_weight(countries[['Weight','ETF']])

Это результат вышеприведенного кода, теперь все равно 1, ноЯ застрял в определенных местах с отрицательными процентными значениями.

df = pd.DataFrame(data=d)
df
    Name   Weight     ETF
0     US     1        SPY
1     US     1        IVV
2     US     1.0094   VTI
3     CA    -0.0094   VTI

Как я могу отформатировать проценты так, чтобы они всегда составляли 100% и чтобы не было отрицательных значений?

Ответы [ 2 ]

2 голосов
/ 30 марта 2019

Вы можете использовать groupby.transform здесь, чтобы получить "неправильную" сумму рядом с каждой строкой, а затем поделить на эту сумму, чтобы внести исправление. Как предложено @ThierrLathuille в комментариях:

print(df)
            Name  Weight  ETF
0  United States  1.0000  SPY
1  United States  1.0000  IVV
2  United States  1.0197  VTI
3         Canada  0.0009  VTI

Применить логику, описанную выше

df['weight_recalc'] = df['Weight'] / df.groupby(['ETF']).Weight.transform('sum')
print(df)
            Name  Weight  ETF  weight_recalc
0  United States  1.0000  SPY       1.000000
1  United States  1.0000  IVV       1.000000
2  United States  1.0197  VTI       0.999118
3         Canada  0.0009  VTI       0.000882

Показать, что пересчет прошел правильно

print(df.groupby('ETF').weight_recalc.sum())
ETF
IVV    1.0
SPY    1.0
VTI    1.0
Name: weight_recalc, dtype: float64
1 голос
/ 30 марта 2019

Вам не нужно что-то добавлять или вычитать, потому что вы будете изменять пропорции этим методом.

Давайте представим, что у вас есть 3 точки данных:

US     40%
Canada 50%
Japan  30%

Как видите, общий процент составляет 40 + 50 + 30 = 120%.

И пропорции между различными значениями:

US / Canada = 40/50 = 0.8
US / Japan = 40/30 = 1.33333
Canada / Japan = 50/30 = 1.66666

Теперь мы получим 120 - 100 = 20 и вычтем 1/3 от каждой точки данных:

US    33.33333
Canada  43.33333
Japan 23.33333

И пропорции теперь:

US / Canada = 33.3333/43.33333 = 0.769
US / Japan = 33.3333/23.3333 = 1.428
Canada / Japan = 43.33333/23.33333 = 1.857

См? Пропортины изменились непредсказуемым образом.

Итак, чтобы сохранить их правильными, вы должны просто выровнять масштаб ваших данных.

1) Суммируйте все значения:

30 + 40 + 50 = 120

2) Разделите 100 на сумму: 100/120 = 0,83333333

3) Умножить каждое значение на предыдущий результат (в данном случае 0,8333333):

В этом примере мы получим:

US     33.33333
Canada 41.66666
Japan  25

Вы можете проверить, но я говорю вам, что пропорции в этом случае не изменились, а сумма теперь равна 100 (с некоторым округлением)

В псевдокоде (у меня нет большого опыта работы с математикой панд):

s = sum(df['ETF'])
df['ETF'] = df['ETF'] * 100 / s
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...