Подтвердить что ты не робот

Как отрезать ненужные края бункера?

Мой вопрос такой же, как и предыдущий:

Объединение с нулевыми значениями в pandas

однако, я все же хочу включить значения 0 в фрактал. Есть ли способ сделать это? Другими словами, если у меня есть 600 значений, 50% из которых равны 0, а остальным - от 1 до 100, как бы классифицировать все значения 0 в фрактале 1, а затем остальные ненулевые значения в метрических меток с 2 по 10 (при условии, что я хочу 10 фракций). Могу ли я преобразовать 0 в nan, qcut оставшиеся не-нано данные в 9 фракций (от 1 до 9), затем добавить 1 к каждой метке (теперь от 2 до 10) и пометить все значения 0 как фрактали 1 вручную? Даже это сложно, потому что в моих данных, помимо 600 значений, у меня также есть еще пара сотен, которые уже могут быть наном, прежде чем я переконвертирую 0s в nan.

Обновление 1/26/14:

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

def fractile_cut(ser, num_fractiles):
    num_valid = ser.valid().shape[0]
    remain_fractiles = num_fractiles
    vcounts = ser.value_counts()
    high_freq = []
    i = 0
    while vcounts.iloc[i] > num_valid/ float(remain_fractiles):
        curr_val = vcounts.index[i]
        high_freq.append(curr_val)
        remain_fractiles -= 1
        num_valid = num_valid - vcounts[i]
        i += 1
    curr_ser = ser.copy()
    curr_ser = curr_ser[~curr_ser.isin(high_freq)]
    qcut = pd.qcut(curr_ser, remain_fractiles, retbins=True)
    qcut_bins = qcut[1]
    all_bins = list(qcut_bins)
    for val in high_freq:
        bisect.insort(all_bins, val)
    cut = pd.cut(ser, bins=all_bins)
    ser_fractiles = pd.Series(cut.labels + 1, index=ser.index)
    return ser_fractiles
4b9b3361

Ответ 1

Вы спрашиваете о биннинге с неповторимыми краями ящиков, для которых у меня довольно простой ответ. В случае вашего примера ваше намерение и поведение qcut расходятся, где в функции pandas.tools.tile.qcut, где определены ячейки:

bins = algos.quantile(x, quantiles)

Что из-за того, что ваши данные равны 50% 0, заставляет бины возвращаться с несколькими краями ящиков при значении 0 для любого значения квантилей, большего, чем 2. Я вижу два возможных разрешения. Во-первых, пространство фрактали делится равномерно, заполняя все 0s, но не только 0s, в первом ящике. Во втором случае пространство фрактали равномерно делится на значения, превышающие 0, забивая все 0s и только 0s в первом бункере.

import numpy as np
import pandas as pd
import pandas.core.algorithms as algos
from pandas import Series

В обоих случаях я создам некоторые случайные данные образца, соответствующие вашему описанию 50% нулей, а оставшиеся значения между 1 и 100

zs = np.zeros(300)
rs = np.random.randint(1, 100, size=300)
arr=np.concatenate((zs, rs))
ser = Series(arr)

Решение 1: bin 1 содержит как 0s, так и низкие значения

bins = algos.quantile(np.unique(ser), np.linspace(0, 1, 11))
result = pd.tools.tile._bins_to_cuts(ser, bins, include_lowest=True)

Результат

In[61]: result.value_counts()
Out[61]: 
[0, 9.3]        323
(27.9, 38.2]     37
(9.3, 18.6]      37
(88.7, 99]       35
(57.8, 68.1]     32
(68.1, 78.4]     31
(78.4, 88.7]     30
(38.2, 48.5]     27
(48.5, 57.8]     26
(18.6, 27.9]     22
dtype: int64

Решение 2: bin1 содержит только 0s

mx = np.ma.masked_equal(arr, 0, copy=True)
bins = algos.quantile(arr[~mx.mask], np.linspace(0, 1, 11))
bins = np.insert(bins, 0, 0)
bins[1] = bins[1]-(bins[1]/2)
result = pd.tools.tile._bins_to_cuts(arr, bins, include_lowest=True)

Результат:

In[133]: result.value_counts()
Out[133]: 
[0, 0.5]        300
(0.5, 11]        32
(11, 18.8]       28
(18.8, 29.7]     30
(29.7, 39]       35
(39, 50]         26
(50, 59]         31
(59, 71]         31
(71, 79.2]       27
(79.2, 90.2]     30
(90.2, 99]       30
dtype: int64

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

Ответ 2

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

a = pd.Series(range(100) + ([0]*20))

def jitter(a_series, noise_reduction=1000000):
    return (np.random.random(len(a_series))*a_series.std()/noise_reduction)-(a_series.std()/(2*noise_reduction))

# and now this works by adding a little noise
a_deciles = pd.qcut(a + jitter(a), 10, labels=False)

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

a_deciles = pd.qcut(a, 10, labels=False)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/local/lib/python2.7/site-packages/pandas/tools/tile.py", line 173, in qcut
    precision=precision, include_lowest=True)
  File "/usr/local/lib/python2.7/site-packages/pandas/tools/tile.py", line 192, in _bins_to_cuts
    raise ValueError('Bin edges must be unique: %s' % repr(bins))
ValueError: Bin edges must be unique: array([  0.        ,   0.        ,   0.        ,   3.8       ,
        11.73333333,  19.66666667,  27.6       ,  35.53333333,
        43.46666667,  51.4       ,  59.33333333,  67.26666667,
        75.2       ,  83.13333333,  91.06666667,  99.        ])

Ответ 3

Проблема pandas.qcut выбирает ячейки, чтобы иметь одинаковое количество записей в каждом бункере/квантиле, но одно и то же значение не может попадать в несколько бункеров/квантов. pandas. p >

Решения:

1 - Используйте pandas >= 0.20.0, у которого это исправление. Они добавили опцию duplicates='raise'|'drop', чтобы контролировать, нужно ли поднимать дублированные ребра или бросать их, что приведет к меньшему количеству ящиков, чем указано, и к некоторым большим (с большим количеством элементов), чем другие.

2 - используйте pandas.cut, который выбирает ячейки для равномерного распределения в соответствии с самими значениями, тогда как pandas.qcut выбирает ячейки, чтобы иметь одинаковое количество записей в каждом бункере

3 - Уменьшить количество квантилей. Меньше квантилей означает больше элементов на квантиль.

4 - Укажите диапазон пользовательских квантилей, например. [0,.50,.75, 1.], чтобы получить неравное количество элементов на квантиль.

5 - ранжируйте свои данные с помощью DataFrame.rank(method = 'first') и передайте эти данные в pd.qcut. Таким образом, вы можете иметь одинаковые значения в разных квантилях, которые могут быть правильными или нет в зависимости от ваших намерений.

если следующее генерирует "ValueError: края бина должны быть уникальными"

pd.qcut(df, nbins) <-- this generates "ValueError: Bin edges must be unique"

Вместо этого вы можете использовать это:

pd.qcut(df.rank(method='first'), nbins)

Ответ 4

У меня было много проблем с qcut, так что я использовал функцию Series.rank в сочетании с созданием собственных бункеров с использованием этих результатов. Мой код находится на Github:

https://gist.github.com/ashishsingal1/e1828ffd1a449513b8f8

Ответ 5

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

  • Оцените свои значения, используя метод = 'first', чтобы python присваивал уникальный рейтинг всем вашим записям. Если есть дублирующее значение (т.е. Привязка в ранге), этот метод выберет первую запись, в которую он входит, и ранг в этом порядке.

df['rank'] = df['value'].rank(method='first')

  1. Используйте qcut в ранге для определения квантов с равным размером. Ниже пример создает deciles (bins = 10).

df['decile'] = pd.qcut(df['rank'].values, 10).codes

Ответ 6

Как было сказано выше, ранжирование отлично работает с pd.qcut()

Ниже приведен пример использования ранжирования.

Ранее:

pd.qcut(Dataframe['any_categorical_feature'],no_of_bins) дает ошибку.

После ранжирования:

pd.qcut(Dataframe['any_categorical_feature'].rank(method='first'),no_of_bins)

будет работать без ошибок.