Оцените среднее значение DataFrameGroupBy, рассматривая только значения в диапазоне процентилей - PullRequest
0 голосов
/ 13 ноября 2018

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

Например, учитывая фрагмент

import numpy as np
import pandas as pd
a = np.matrix('1 1; 1 2; 1 4; 2 1; 2 2; 2 4')
data = pd.DataFrame(a)
groupby = data.groupby(0)
m1 = groupby.mean()

, результат равен

m1 =            1
      0          
      1  2.333333
      2  2.333333

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

m1 =     1
      0          
      1  2
      2  2

Как отфильтровать для каждой группы значения между произвольный диапазон процентилей до оценки среднего значения?Например, только с учетом значений между 20-м и 80-м процентилями.

Ответы [ 5 ]

0 голосов
/ 13 ноября 2018

Используйте np.percentile или np.quantile с groupby + apply:

a = np.matrix('1 1 2; 1 2 3; 1 4 4; 2 1 6; 2 2 8; 2 4 16;7 8 45;9 10 9;11 12 3')
df = pd.DataFrame(a,columns=['a','b','c'])
#drop column which is key for grouping
min_val,max_val = np.percentile(df.drop('a',1).values,[20,80],axis=0)
#alternative np.quantile(df.drop('a',1).values,[0.2,0.8],axis=0)
df1 = df.groupby('a').apply(lambda x: x[(x<max_val)&(x>min_val)].mean())

print(df1)
      b    c
a           
1   3.0  4.0
2   3.0  7.0
7   8.0  NaN
9   NaN  9.0
11  NaN  NaN
0 голосов
/ 13 ноября 2018

Вы можете использовать пользовательскую функцию с np.percentile или pd.Series.quantile. Разница в производительности незначительна. Приведенный ниже пример включает значения только выше 20-го и ниже 80-го процентиля при расчете группового среднего.

import pandas as pd
import numpy as np

a = np.matrix('1 1; 1 2; 1 4; 2 1; 2 2; 2 4')
data = pd.DataFrame(a)

def jpp_np(df):
    def meaner(x, lowperc, highperc):
        low, high = np.percentile(x, [lowperc, highperc])
        return x[(x > low) & (x < high)].mean()
    return df.groupby(0)[1].apply(meaner, 20, 80).reset_index()

def jpp_pd(df):
    def meaner(x, lowperc, highperc):
        low, high = x.quantile([lowperc/100, highperc/100]).values
        return x[x.between(low, high, inclusive=False)].mean()
    return df.groupby(0)[1].apply(meaner, 20, 80).reset_index()

data = pd.concat([data]*10000)

assert np.array_equal(jpp_np(data), jpp_pd(data))

%timeit jpp_np(data)  # 11.2 ms per loop
%timeit jpp_pd(data)  # 12.5 ms per loop
0 голосов
/ 13 ноября 2018

1001 * попробовать *

data.sort_values(by=1).groupby(by=0).agg(['first','last']).mean()

OR

data.sort_values(by=1).groupby(by=0).agg(['min','max']).mean()
0 голосов
/ 13 ноября 2018

Один из подходов состоит в том, чтобы отфильтровать кадр данных перед использованием группировки.Вы можете отсортировать фрейм данных по интересующему столбцу, а затем исключить первую и последнюю строки.

data = data.sort_values(1).iloc[1:-1,:]
groupby = data.groupby(0)
m1 = groupby.mean()

Еще одно примечание: рекомендуется не использовать имя переменной в качестве распространенного метода, такого как groupby.».Если вы можете изменить это имя на другое, это очень рекомендуется.

0 голосов
/ 13 ноября 2018

Вы можете определить функцию для вычисления этого среднего для кадра данных, а затем использовать метод apply.Что-то вроде:

def mean_percent(df,per1,per2):
    #Write meaningful code here

data = pd.DataFrame(a)
groupby = data.groupby(0)
m1 = groupby.apply(lambda df: mean_percent(df,20,80))

Это будет вычислять среднее значение со значением в диапазоне 20-80 процентилей для каждой группы.Если вам нужна помощь в написании первой функции, не стесняйтесь спрашивать в комментарии, и я отредактирую этот ответ.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...