2014-12-24 4 views
3

У меня есть рамка данных pandas, которую я хотел бы разбить на группы, вычислить среднее и стандартное отклонение, а затем заменить все выбросы на среднее значение группы. Выбросы определяются как таковые, если они больше трех стандартных отклонений от среднего значения группы.Pandas - Заменить выбросы с помощью группового значения

df = pandas.DataFrame({'a': ['A','A','A','B','B','B','B'], 'b': [1.1,1.2,1.1,3.3,3.4,3.3,100.0]}) 

Я думал, что следующий будет работать:

df.groupby('a')['b'].transform(lambda x: x[i] if np.abs(x[i]-x.mean())<=(3*x.std()) else x.mean() for i in range(0,len(x))) 

но получаю следующее сообщение об ошибке:

NameError: name 'x' is not defined

Я также попытался определить функцию преобразования по отдельности:

def trans_func(x): 
    mean = x.mean() 
    std = x.std() 
    length = len(x) 
    for i in range(0,length): 
     if abs(x[i]-mean)<=(3*std): 
      return x 
     else: 
      return mean 

и п называть его так:

df.groupby('a')['b'].transform(lambda x: trans_func(x)) 

, но я получаю другую ошибку:

KeyError: 0

Наконец, я прибегал к созданию отдельного столбца в целом:

df['c'] = [df.groupby('a')['b'].transform(mean) if df.groupby('a')['b'].transform(lambda x: (x - x.mean())/x.std()) > 3 else df['b']] 

, но это не имеет работало либо:

ValueError: The truth value of a Series is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all().

Любые советы очень ценятся.

ответ

6

Попробуйте это:

def replace(group): 
    mean, std = group.mean(), group.std() 
    outliers = (group - mean).abs() > 3*std 
    group[outliers] = mean  # or "group[~outliers].mean()" 
    return group 

df.groupby('a').transform(replace) 

Примечание: Если вы хотите, чтобы устранить 100 в последней группе, вы можете заменить 3*std, просто 1*std. Стандартное отклонение в этой группе составляет 48.33, поэтому оно будет включено в результат.

+0

Но разве это не повлияло бы на это влияние? – jayarjo

Смежные вопросы