Мультикатегория Python - PullRequest
       2

Мультикатегория Python

0 голосов
/ 02 марта 2019

У меня есть этот проект, который требует ежедневных коэффициентов в неделю в год, как показано ниже

Week | Year | Weekday | Volume 1 2000 1 0 1 2000 2 10 1 2000 3 10 2 2000 1 10 2 2000 2 0 1 2001 1 0 1 2001 2 10 1 2001 3 10 2 2001 1 10 2 2001 2 0

Я хочу, чтобы результат был примерно таким

Week | Year | Weekday | Volume | Ratio 1 2000 1 0 0 1 2000 2 10 .5 1 2000 3 10 .5 2 2000 1 10 1 2 2000 2 0 0 1 2001 1 0 0 1 2001 2 10 .5 1 2001 3 10 .5 2 2001 1 10 1 2 2001 2 0 0

У меня есть текущее решение, которое делает что-то похожее на эту

for year in years
    for week in weeks 
        ratio = week/weeklytotal
        weeklyratios = pd.concat([weeklyratios,ratio], blablabla)

, проблема в том, что это невероятно неэффективно, тем более, что я должен выполнить этот процесс более 30 тысяч раз.В результате получается время выполнения 2,3 секунды, что соответствует времени выполнения кода 24 часа.

Есть ли лучший способ сделать это, чтобы он мог работать быстрее?

Ответы [ 2 ]

0 голосов
/ 02 марта 2019

Вы можете выполнять сгруппированные операции, используя функции индексации и groupby в пандах.

Если у вас есть фрейм данных df со столбцами ['week', 'year', 'weekday', 'volume'], ваше решение будет выглядеть примерно так:

import numpy as np
import pandas as pd
import timeit as t

# make up some data, only 1000 groups not your 30000, but it gets the point across
dates = pd.date_range(start = '2000-01-01', end = '2019-02-28', freq = 'D')
volume = np.random.randint(0,100,len(dates))

df = pd.DataFrame(list(zip(dates.week,dates.year,dates.dayofweek,volume)),
                  columns = ['week','year','weekday','volume'])

# group
grp = df.groupby(['year','week'])
grp_vol = grp['volume'].sum()

# rename to avoid overlap in names
grp_vol.name  = 'weekly_volume'
# rejoin to calculate your ratio
df = df.join(grp_vol, on = ['year','week'])
df['ratio'] = df['volume']/df['weekly_volume']

А затем время для хорошей меры

%timeit df['ratio'] = df['volume']/df['weekly_volume']
196 µs ± 4.32 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)

Так намного меньше, чем 24 часа.

0 голосов
/ 02 марта 2019

Вы можете использовать groupby для вычисления общего объема в неделю.Затем вы можете присоединить этот общий объем к исходному кадру данных и вычислить соотношение в векторизованном виде.

Предполагая, что исходный кадр данных равен df (тип d int):

   Week  Year  Weekday  Volume

0     1  2000        1       0
1     1  2000        2      10
2     1  2000        3      10
3     2  2000        1      10
4     2  2000        2       0
5     1  2001        1       0
6     1  2001        2      10
7     1  2001        3      10
8     2  2001        1      10
9     2  2001        2       0

вы можете использовать:

s = df.groupby(['Week', 'Year']).sum().drop('Weekday', axis=1)
df2 = df.set_index(['Week', 'Year']).join(s,rsuffix='_tot').sort_index(level=1)
df2['ratio'] = df2.Volume / df2.Volume_tot

print(df2)

дает:

           Weekday  Volume  Volume_tot  ratio
Week Year                                    
1    2000        1       0          20    0.0
     2000        2      10          20    0.5
     2000        3      10          20    0.5
2    2000        1      10          10    1.0
     2000        2       0          10    0.0
1    2001        1       0          20    0.0
     2001        2      10          20    0.5
     2001        3      10          20    0.5
2    2001        1      10          10    1.0
     2001        2       0          10    0.0

Вы можете получить ожидаемый результат с помощью:

print(df2.drop('Volume_tot', axis=1).reset_index())

, что дает:

   Week  Year  Weekday  Volume  ratio
0     1  2000        1       0    0.0
1     1  2000        2      10    0.5
2     1  2000        3      10    0.5
3     2  2000        1      10    1.0
4     2  2000        2       0    0.0
5     1  2001        1       0    0.0
6     1  2001        2      10    0.5
7     1  2001        3      10    0.5
8     2  2001        1      10    1.0
9     2  2001        2       0    0.0
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...