Получение межквартильного диапазона и медианы от групп панд, заполнение нулями для всех не упомянутых дат
У меня есть датафрейм (кроме моего очень большой):
user1 user2 day hour quantity
-------------------------------------
Alice Bob 1 12 250
Alice Bob 1 13 250
Bob Carol 1 10 20
Alice Bob 4 1 600
.
.
.
... тогда предположим, что я получаю следующую групповую и агрегацию user1
, user2
а также day
):
user1 user2 day quantity
---------------------
Alice Bob 1 500
4 600
Bob Carol 1 20
3 100
где день должен идти от 0-364 (365 дней). То, что я хочу, это межквартильный диапазон (и медиана) отсчетов для каждого пользователя за все дни - за исключением того, что нули не подсчитываются.
Жизнь была бы проще, если бы у меня были явные нули для всех исключенных дней:
user1 user2 day quantity
---------------------
Alice Bob 1 500
2 0
3 0
4 600
.....
Bob Carol 1 20
2 0
3 100
...
... потому что тогда я мог сделать df.reset_index().agg({'quantity':scipy.stats.iqr})
но я работаю с очень большим фреймом данных (пример выше - фиктивный), и переиндексация с нулями просто невозможна.
У меня есть идея, как это сделать: так как я знаю, что есть 365 дней, то я должен просто дополнить остальные числа нулями:
Alice-Bob: [500,600] + (365-2) * [0]
и получить scipy.stats.iqr
(и медиана) этого. Тем не менее, это будет включать в себя итерации по всем user1-user2
пар. По опыту это занимает много времени.
Есть ли векторизованное решение для этого? Я также должен получить медиану, и я думаю, что тот же самый подход должен сохраняться.
1 ответ
Чтобы использовать нули, не помещая их в фрейм данных, вы можете использовать что-то вроде этого:
test = df.groupby(['user1', 'user2', 'day'])['quantity'].mean().reset_index()\
.groupby(['user1', 'user2'])\
.agg({'day': lambda x: tuple(x), 'quantity': lambda x: tuple(x)})\
.reset_index()
def med_from_tuple(row):
# starts with everything zero, and replaces some with the nonzero values in the dataframe
z = np.zeros(365)
np.put(z, row['day'], row['quantity'])
return np.median(z)
test['example'] = test.apply(lambda x: med_from_tuple(x), axis=1)
Это создаст медиану количества, как если бы в кадре данных были нули.
test
# user1 user2 day quantity example
#0 Alice Bob (1, 4) (250, 600) 0.0
#1 Bob Carol (1,) (20,) 0.0