Обратный np.percentile () [duplicate]

Ответы Doug stevenson помогли мне лучше:

TL; DR: Это предупреждающее сообщение. если вы не выполняете исходящие вызовы, вы в порядке

Это предупреждение появляется для всех функций при выполнении плана Spark. Это просто предупреждение - вы можете игнорировать его, если вы делаете какие-либо исходящие сети в своих собственных.

Мы изучаем, как это сообщение было изменено или удалено, так что оно менее запутанно.

[...]

blockquote>

21
задан Matthew Adams 13 September 2012 в 21:20
поделиться

8 ответов

Я думаю, что ваш пример ввода / вывода не соответствует типичным способам вычисления процентиля. Если вы вычисляете процентиль как «пропорцию точек данных, строго меньших этого значения», то верхнее значение должно быть 0,8 (поскольку 4 из 5 значений меньше самого большого). Если вы подсчитаете его как «процент точек данных, меньших или равных этому значению», то нижнее значение должно быть 0,2 (поскольку 1 из 5 значений равно наименьшему). Таким образом, процентили будут [0, 0.2, 0.4, 0.6, 0.8] или [0.2, 0.4, 0.6, 0.8, 1]. Ваше определение, по-видимому, представляет собой «количество точек данных, строго меньшее этого значения, которое рассматривается как доля от числа точек данных, не равных этому значению», но, по моему опыту, это не общее определение (см., Например, wikipedia ).

С типичными определениями процентилей процентиль точки данных равен ее рангу, деленному на количество точек данных. (См., Например, этот вопрос по статистике SE, в котором просят, как сделать то же самое в R.) Различия в том, как вычислить процентную долю в различиях в том, как вычислить ранг (например, как ранжировать привязанные значения). Функция scipy.stats.percentileofscore предоставляет четыре способа вычисления процентилей:

>>> x = [1, 1, 2, 2, 17]
>>> [stats.percentileofscore(x, a, 'rank') for a in x]
[30.0, 30.0, 70.0, 70.0, 100.0]
>>> [stats.percentileofscore(x, a, 'weak') for a in x]
[40.0, 40.0, 80.0, 80.0, 100.0]
>>> [stats.percentileofscore(x, a, 'strict') for a in x]
[0.0, 0.0, 40.0, 40.0, 80.0]
>>> [stats.percentileofscore(x, a, 'mean') for a in x]
[20.0, 20.0, 60.0, 60.0, 90.0]

(я использовал набор данных, содержащий ссылки, чтобы проиллюстрировать, что происходит в таких случаях.)

Метод «ранга» присваивает связанным группам ранг, равный среднему числу рангов, которые они будут покрывать (т. е. трехсторонняя связь для 2-го места получает звание 3, потому что она «занимает» звания 2, 3 и 4). «Слабый» метод присваивает процентиль, исходя из доли точек данных, меньших или равных данной точке; «строгий» - это то же самое, но счет пропорции точек строго меньше данной точки. «Средний» метод является средним из последних двух.

Как заметил Кевин Х. Линь, вызов percentileofscore в цикле неэффективен, поскольку он должен пересчитать ряды на каждом проходе. Однако эти процентильные вычисления могут быть легко реплицированы с использованием различных методов ранжирования, предоставляемых scipy.stats.rankdata , позволяя вам сразу вычислить процентили:

>>> from scipy import stats
>>> stats.rankdata(x, "average")/len(x)
array([ 0.3,  0.3,  0.7,  0.7,  1. ])
>>> stats.rankdata(x, 'max')/len(x)
array([ 0.4,  0.4,  0.8,  0.8,  1. ])
>>> (stats.rankdata(x, 'min')-1)/len(x)
array([ 0. ,  0. ,  0.4,  0.4,  0.8])

. В последнем случае ранги скорректированы вниз на один, чтобы они начинались с 0 вместо 1. (я опустил «среднее», но его можно было легко получить, усреднив результаты последних двух методов.)

I сделал некоторые тайминги. С небольшими данными, такими как в вашем примере, использование rankdata несколько медленнее, чем решение Кевина Х. Лина (предположительно из-за того, что накладные расходы приходится на преобразование вещей в массивы numpy под капотом), но быстрее, чем вызов percentileofscore в как и в ответе рептилия:

In [11]: %timeit [stats.percentileofscore(x, i) for i in x]
1000 loops, best of 3: 414 µs per loop

In [12]: %timeit list_to_percentiles(x)
100000 loops, best of 3: 11.1 µs per loop

In [13]: %timeit stats.rankdata(x, "average")/len(x)
10000 loops, best of 3: 39.3 µs per loop

Однако при большом наборе данных преимущество работы numpy вступает в силу, а использование rankdata в 10 раз быстрее, чем у Кевина list_to_percentiles:

In [18]: x = np.random.randint(0, 10000, 1000)

In [19]: %timeit [stats.percentileofscore(x, i) for i in x]
1 loops, best of 3: 437 ms per loop

In [20]: %timeit list_to_percentiles(x)
100 loops, best of 3: 1.08 ms per loop

In [21]: %timeit stats.rankdata(x, "average")/len(x)
10000 loops, best of 3: 102 µs per loop

Это преимущество будет только более выраженным в больших и больших наборах данных.

28
ответ дан Community 22 August 2018 в 20:35
поделиться
  • 1
    Преимущества, которые вы проиллюстрировали выше, были подтверждены. – Jubbles 18 February 2015 в 20:02
  • 2
    Ницца. Если вы посмотрите на реализацию scipy.stats.rankdata ( github.com/scipy/scipy/blob/v0.16.0/scipy/stats/… ), вы увидите, что он использует argsort(). Их алгоритм по существу тот же, что и мой, и разница полностью объясняется различием между списками Python и массивами numpy. – Kevin H. Lin 5 August 2015 в 21:46

Чистая numpy версия решения Кевина

Как сказал Кевин, оптимальное решение работает в O (n log (n)) времени. Вот быстрая версия его кода в numpy, который работает почти в то же время, что и stats.rankdata:

percentiles = numpy.argsort(numpy.argsort(array)) * 100. / (len(array) - 1)

PS. Это один из моих любимых трюков в numpy.

10
ответ дан Alleo 22 August 2018 в 20:35
поделиться

это может показаться излишним, но как насчет этого:

def percentile(x):
    pc = float(1)/(len(x)-1)
    return ["%.2f"%(n*pc) for n, i in enumerate(x)]

EDIT:

def percentile(x):
    unique = set(x)
    mapping = {}
    pc = float(1)/(len(unique)-1)
    for n, i in enumerate(unique):
        mapping[i] = "%.2f"%(n*pc)
    return [mapping.get(el) for el in x]
2
ответ дан aschmid00 22 August 2018 в 20:35
поделиться
  • 1
    Близко, но это имеет ту же проблему, что и первая попытка Аладдина выше. – Jubbles 13 September 2012 в 21:48
  • 2
    проверьте мое редактирование. это может работать для u – aschmid00 13 September 2012 в 21:56

С точки зрения сложности, я думаю, что ответ Рептилия не является оптимальным. Это время O (n ^ 2).

Вот решение, которое принимает время O (n log n).

def list_to_percentiles(numbers):
    pairs = zip(numbers, range(len(numbers)))
    pairs.sort(key=lambda p: p[0])
    result = [0 for i in range(len(numbers))]
    for rank in xrange(len(numbers)):
        original_index = pairs[rank][1]
        result[original_index] = rank * 100.0 / (len(numbers)-1)
    return result

Я не уверен, но я думаю это оптимальная временная сложность, которую вы можете получить. Грубая причина, по которой я думаю, что она оптимальна, состоит в том, что информация обо всех процентилях по существу эквивалентна информации отсортированного списка, и вы не можете добиться большего, чем O (n log n) для сортировки.

EDIT: В зависимости от вашего определения «процентиль» это может не всегда давать правильный результат. См. Ответ BrenBarn для более подробного объяснения и лучшего решения, которое использует scipy / numpy.

8
ответ дан Kevin H. Lin 22 August 2018 в 20:35
поделиться
  • 1
    После того, как я опубликовал этот ответ, кто-то решил последовательно перечислить все мои сообщения SO. Не круто... – Kevin H. Lin 23 December 2014 в 02:32
  • 2
    Благодаря! Вы совершенно правы, что ответ, использующий понимание списка с scipy.stats.percentileofscore, «не оптимален». Я приурочил оба подхода к timeit, и ваша функция великолепна. – Jubbles 12 February 2015 в 01:50

Если я правильно вас понимаю, все, что вы хотите сделать, это определить процентиль, который этот элемент представляет в массиве, насколько массив находится перед этим элементом. как в [1, 2, 3, 4, 5] должно быть [0.0, 0.25, 0.5, 0.75, 1.0]

Я считаю, что такого кода будет достаточно:

def percentileListEdited(List):
    uniqueList = list(set(List))
    increase = 1.0/(len(uniqueList)-1)
    newList = {}
    for index, value in enumerate(uniqueList):
        newList[index] = 0.0 + increase * index
    return [newList[val] for val in List]
1
ответ дан Mahmoud Aladdin 22 August 2018 в 20:35
поделиться
  • 1
    Закрыть, но не совсем. Если я попробую percentileList([1,2,3,4,4,5,5]), возвращается список [0.0, 0.17, 0.33, 0.5, 0.67, 0.83, 0.99], где я хотел бы вернуть [0.0, 0.17, 0.33, 0.50, 0.50, 1.00, 1.00]. – Jubbles 13 September 2012 в 21:35
  • 2
    Ну, я хочу знать больше, о том, что вы хотите сделать, повторяющиеся числа должны иметь одинаковый процентиль, но все же их процентиль зависит от количества повторных номеров?! – Mahmoud Aladdin 13 September 2012 в 21:51
  • 3
    Да, в то время как множественные наблюдения отдельных значений должны иметь одинаковый процентиль, каждое наблюдение все еще добавляет к числу наблюдений, которые строго меньше наблюдений с большими значениями. Процентники не так прямолинейны, как думают некоторые люди. – Jubbles 13 September 2012 в 21:59
  • 4
    @Jubbles, действительно, это не так. Я признаю, что я немного смущен приведенным выше примером. Наименьшее значение должно быть 0.0 и , причем наивысшее значение 100.0 кажется непоследовательным. – senderle 13 September 2012 в 23:09
  • 5
    – Rob Bednark 20 September 2012 в 20:54

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

def what_pctl_number_of(x, a, pctls=np.arange(1, 101)):
    return np.argmax(np.sign(np.append(np.percentile(x, pctls), np.inf) - a))

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

_x = np.random.randn(100, 1)
what_pctl_number_of(_x, 1.6, [25, 50, 75, 100])

Выход:

3

, поэтому он достигает диапазона 75 ~ 100

0
ответ дан mde 22 August 2018 в 20:35
поделиться

Я думаю, что вы хотите scipy.stats.percentileofscore

Пример:

percentileofscore([1, 2, 3, 4], 3)
75.0
percentiles = [percentileofscore(data, i) for i in data]
13
ответ дан reptilicus 22 August 2018 в 20:35
поделиться
  • 1
    В частности, [percentileofscore(score) for score in original_list]. – Karl Knechtel 13 September 2012 в 21:55
  • 2
    yup, отредактированный, чтобы добавить это. – reptilicus 13 September 2012 в 21:58
  • 3
    @ user1443118 и @Karl Knechtel: Это так. Конкретно для моих предпочтений, [percentileofscore(data, i, 'weak') for i in data] - это то, что я ищу. Очень Pythonic тоже. – Jubbles 13 September 2012 в 22:08
  • 4
    Я думаю, что это решение O (n ^ 2), которое не является оптимальным. – Kevin H. Lin 15 December 2014 в 23:31

Для меня лучшим решением является использование QuantileTransformer в sklearn.preprocessing.

from sklearn.preprocessing import QuantileTransformer
fn = lambda input_list : QuantileTransformer(100).fit_transform(np.array(input_list).reshape([-1,1])).ravel().tolist()
input_raw = [1, 2, 3, 4, 17]
output_perc = fn( input_raw )

print "Input=", input_raw
print "Output=", np.round(output_perc,2)

Вот результат

Input= [1, 2, 3, 4, 17]
Output= [ 0.    0.25  0.5   0.75  1.  ]

Примечание: эта функция имеет две характерные особенности:

  1. входные исходные данные НЕ обязательно сортируются .
  2. входные исходные данные НЕ обязательно одиночные столбцы.
0
ответ дан user36624 22 August 2018 в 20:35
поделиться
Другие вопросы по тегам:

Похожие вопросы: