Нахождение соответствующих значений отсечки - PullRequest
1 голос
/ 07 марта 2011

Я пытаюсь реализовать Оценки Хэмпела Тана , чтобы нормализовать сильно асимметричные данные.Для этого мне нужно выполнить следующие вычисления:

Учитывая x - отсортированный список чисел и m - медиану x, мне нужно найти a такойчто примерно 70% значений в x попадают в диапазон (m-a; m+a).Мы ничего не знаем о распределении значений в x.Я пишу на python, используя numpy, и лучшая идея, которая у меня была, - написать какой-то стохастический итеративный поиск (например, как было описано Solis and Wets ), но я подозреваю, что есть лучшийподход, либо в виде лучшего алгоритма, либо в виде готовой функции.Я искал документацию по numpy и scipy, но не смог найти никакой полезной подсказки.

РЕДАКТИРОВАТЬ

Сет предложил использовать scipy.stats.mstats.trimboth, однако в моем тесте для перекошенного дистрибутива это предложение не сработало:

from scipy.stats.mstats import trimboth
import numpy as np

theList = np.log10(1+np.arange(.1, 100))
theMedian = np.median(theList)

trimmedList = trimboth(theList, proportiontocut=0.15)
a = (trimmedList.max() - trimmedList.min()) * 0.5

#check how many elements fall into the range
sel = (theList > (theMedian - a)) * (theList < (theMedian + a))

print np.sum(sel) / float(len(theList))

Выход составляет 0,79 (~ 80%, вместо 70)

Ответы [ 3 ]

2 голосов
/ 07 марта 2011

Сначала необходимо симметризовать распределение, сложив все значения меньше среднего значения справа.Затем вы можете использовать стандартные функции scipy.stats в этом одностороннем распределении:

from scipy.stats import scoreatpercentile
import numpy as np

theList = np.log10(1+np.arange(.1, 100))
theMedian = np.median(theList)

oneSidedList = theList[:]               # copy original list
# fold over to the right all values left of the median
oneSidedList[theList < theMedian] = 2*theMedian - theList[theList < theMedian]

# find the 70th centile of the one-sided distribution
a = scoreatpercentile(oneSidedList, 70) - theMedian

#check how many elements fall into the range
sel = (theList > (theMedian - a)) * (theList < (theMedian + a))

print np.sum(sel) / float(len(theList))

Это дает результат 0.7 по мере необходимости.

1 голос
/ 07 марта 2011

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

Пусть меньший индекс будет n1, а больший индекс - n2; они не независимы. Значения из списка по индексам x[n1] = m-b и x[n2]=m+c. Теперь вы хотите выбрать n1 (и, следовательно, n2), чтобы b и c были как можно ближе. Это происходит, когда (b - c)**2 минимально. Это довольно просто, используя numpy.argmin. Параллельно с примером в вопросе, вот интерактивная сессия, иллюстрирующая подход:

$ python
Python 2.6.5 (r265:79063, Jun 12 2010, 17:07:01)
[GCC 4.3.4 20090804 (release) 1] on cygwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import numpy as np
>>> theList = np.log10(1+np.arange(.1, 100))
>>> theMedian = np.median(theList)
>>> listHead = theList[0:30]
>>> listTail = theList[-30:]
>>> b = np.abs(listHead - theMedian)
>>> c = np.abs(listTail - theMedian)
>>> squaredDiff = (b - c) ** 2
>>> np.argmin(squaredDiff)
25
>>> listHead[25] - theMedian, listTail[25] - theMedian
(-0.2874888056626983, 0.27859407466756614)
0 голосов
/ 07 марта 2011

Что вы хотите, это scipy.stats.mstats.trimboth .Установите proportiontocut=0.15.После обрезки возьмите (max-min)/2.

...