Среднее значение за 6 месяцев для разных категорий (подмножеств / комбинаций строк) в Pandas - PullRequest
0 голосов
/ 14 января 2019

Мои данные содержат 700,00 строк

Я попытался использовать цикл for, который занял 30 часов. Пожалуйста, дайте мне знать, как быстрее получить результат.

Я прилагаю пример данных. Каждая строка уникальна и соответствует столбцам [period, dimname, средства, serv, cpt]. Я хочу найти среднее значение для скользящих месяцев столбца (gcr) по отношению к столбцам [period-dimname-Facility-CPT]. (Последний столбец (avg6month) содержит желаемый результат). Для лучшего понимания прилагается набор результатов фильтра в формате JPEG.

data.sort_values(by='period', inplace=True, ascending=True)
for fa in data.loc[(data.dimname == 'fac_cpt'), ].facility.dropna().unique():
    for pr in data.loc[(data.dimname == 'fac_cpt') & (data.facility == fa), ].cpt.dropna().unique():
        data.loc[(data.dimname == 'fac_cpt') & (data.facility == fa) & (data.cpt == pr), ['avg6monthgcr']]=round(data.loc[(data.dimname == 'fac_cpt') & (data.facility == fa) & (data.cpt == pr), ].gcr.rolling(6, min_periods=1).mean(), 4)

Sample_Data:

sample_data

Samples_Results:

result1 result2 result3 result4

1 Ответ

0 голосов
/ 14 января 2019

Мне удалось получить то, что вам нужно с векторными операциями, поэтому это должен быть самый быстрый способ из возможных.

import pandas as pd

data = pd.DataFrame({
    "period": [
        '3/1/2017', '3/1/2017', '3/1/2017', '3/1/2017', '3/1/2017', '3/1/2017', '3/1/2017',
        '4/1/2017', '4/1/2017', '4/1/2017', '4/1/2017', '4/1/2017', '4/1/2017', '4/1/2017'
    ],
    "dimname": [
        'fac_cpt', 'fac_cpt', 'fac_cpt', 'fac_cpt', 'fac_cpt', 'ser_cpt', 'ser_cpt',
        'fac_cpt', 'fac_cpt', 'fac_cpt', 'fac_cpt', 'fac_cpt', 'ser_cpt', 'ser_cpt'
    ],
    "facility": ['a', 'a', 'a', 'b', 'b', None, None, 'a', 'a', 'a', 'b', 'b', None, None],
    "cpt": ['p1', 'p2', 'p3', 'p1', 'p2', 'p1', 'p2', 'p1', 'p2', 'p3', 'p1', 'p2', 'p1', 'p1'],
    "ser": [None, None, None, None, None, 'c', 'c', None, None, None, None, None, 'd', 'd'],
    "gcr": [1, 10, 2, 3, 8, 12, 4, 4, 10, 2, 4, 11, 6, 2]
})
data.period = data.period.apply(pd.to_datetime)

data[["period", "dimname", "facility", "cpt", "gcr"]].groupby(
    ['dimname', 'facility', 'cpt']
).rolling(6, min_periods=1, on='period').mean().reset_index(
    3, drop=True
).reset_index().rename(columns={'gcr': 'avg6monthgcr'})
# Output:
  | dimname | facility | cpt | avg6monthgcr | period
----------------------------------------------------
0 | fac_cpt |        a |  p1 |          1.0 | 2017-03-01
1 | fac_cpt |        a |  p1 |          2.5 | 2017-04-01
2 | fac_cpt |        a |  p2 |         10.0 | 2017-03-01
3 | fac_cpt |        a |  p2 |         10.0 | 2017-04-01
4 | fac_cpt |        a |  p3 |          2.0 | 2017-03-01
5 | fac_cpt |        a |  p3 |          2.0 | 2017-04-01
6 | fac_cpt |        b |  p1 |          3.0 | 2017-03-01
7 | fac_cpt |        b |  p1 |          3.5 | 2017-04-01
8 | fac_cpt |        b |  p2 |          8.0 | 2017-03-01
9 | fac_cpt |        b |  p2 |          9.5 | 2017-04-01

Я рассчитал время для вашего набора данных, но выигрыш был лишь незначительный, возможно, потому, что большая часть инициализации заняла большую часть времени, а не вычисления, поэтому вы должны попробовать его на полном наборе данных.

# your method:
27.6 ms ± 1.85 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
# my method:
24.9 ms ± 2.03 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

Если вам нужно объединить его с исходным фреймом данных, вы должны изменить код, чтобы сохранить исходный индекс, потому что слияние выполняется быстрее для них, поэтому это будет выглядеть так:

avg_data = data[["period", "dimname", "facility", "cpt", "gcr"]].groupby(['dimname', 'facility', 'cpt']).rolling(6, min_periods=1, on='period').mean().reset_index(level=3).reset_index(drop=True).set_index('level_3').rename(columns={'gcr': 'avg6monthgcr'}).drop('period', axis=1)

data.merge(avg_data, left_index=True, right_index=True, how='left')
...