2015-04-27 3 views
1

Я работаю с данными, который выглядит как DataFrame описываемогоУстановленное значение 90-го процентиля для каждого столбца в DataFrame

df = pd.DataFrame({'AAA': [1,1,1,2,2,2,3,3], 'BBB': [2,1,3,4,6,1,2,3]}) 

То, что я хотел бы сделать, это установить значение сводке (90%) если значение превышает 90-й процентиль. Так что это как ограничение максимального уровня до 90-го процентиля.

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

Я могу получить 90-й процентиль значение с помощью:

df.describe(percentiles=[.9]) 

Так что для столбца ВВВ, 6 больше, чем 4,60 (90-й процентиль), следовательно, он должен быть изменен на 5 (облаву 4.60).

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

ответ

2

Один vectorised метод будет сочетать np.minimum и df.quantile:

>>> np.minimum(df, df.quantile(0.9)) 
    AAA BBB 
0 1 2.0 
1 1 1.0 
2 1 3.0 
3 2 4.0 
4 2 4.6 
5 2 1.0 
6 3 2.0 
7 3 3.0 

Для большего использования скорости наддува:

np.minimum(df, np.percentile(df, 90, axis=0)) 

df.quantile оказывается медленнее, чем np.percentile (возможно, потому, что он возвращает серию, а не простой массив NumPy).

+0

Не знаете, почему, но вы заметили, что в опубликованных тестах этот метод выглядит медленнее, чем применяемый метод. +1 для более чистого однострочного. – Zero

+0

Кажется, что 'np.percentile' довольно немного быстрее (целых 3x), чем' df.quantile' - возможно, потому что последний возвращает серию. –

+0

только для более короткой версии, принято это как ответ, иначе для меня как работает, так и спасибо. – Yantraguru

1

Один из способов сделать это применить clip_upper() на 90 значение процентиля np.percentile(x, 90) для каждого столбца

In [242]: df.apply(lambda x: x.clip_upper(np.percentile(x, 90))) 
Out[242]: 
    AAA BBB 
0 1 2.0 
1 1 1.0 
2 1 3.0 
3 2 4.0 
4 2 4.6 
5 2 1.0 
6 3 2.0 
7 3 3.0 

я представлял @ajcr элегантное решение будет быстрее, чем apply. Но

Ниже тестов для len(df) ~ 130K

In [245]: %timeit df.apply(lambda x: x.clip_upper(np.percentile(x, 90))) 
100 loops, best of 3: 7.49 ms per loop 

In [246]: %timeit np.minimum(df, df.quantile(0.9)) 
100 loops, best of 3: 11.1 ms per loop 

len(df) ~ 1M И

In [248]: %timeit df.apply(lambda x: x.clip_upper(np.percentile(x, 90))) 
10 loops, best of 3: 54.5 ms per loop 

In [249]: %timeit np.minimum(df, df.quantile(0.9)) 
10 loops, best of 3: 73.9 ms per loop 
+0

прохладный. Это то, чего я хотел. Не знаю о clip_upper. – Yantraguru

+0

Спасибо за тайминги! Я подумал об одном и том же, но, только что проверил тайминги на моей машине, кажется, что «apply» может иногда удивляться :-) –

+0

(На самом деле это выглядит как «np.percentile» - причина большей скорости ...) –

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

  • Нет связанных вопросов^_^