При использовании вырезания в фрейме данных pandas для его бинирования, почему биннинг не выполняется должным образом?

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

import pandas as pd
import numpy as np

data = pd.DataFrame(columns=['Score', 'Age'])
data.Score = [1, 1, 1, 1, 0, 1, 2, 1, 0, 1, 1, 0, 2, 1, 1, 2, 1, 0, 1, 1, -1, 1, 0, 1, 1, 0, 1, 0, -2, 1]
data.Age = [29, 59, 44, 52, 60, 53, 45, 47, 57, 54, 35, 32, 48, 31, 49, 43, 67, 32, 31, 42, 37, 45, 52, 59, 56, 57, 48, 45, 56, 31]

_, bins = np.histogram(data.Age, 10)
labels = ['{}-{}'.format(i + 1, j) for i, j in zip(bins[:-1], bins[1:])]
labels[0] = '{}-{}'.format(bins[0], bins[1])
binned = pd.cut(data.Age, bins=bins, labels=labels, include_lowest=True, precision=0)
df = data.groupby(binned)['Score'].mean().reset_index()
df

введите здесь описание изображения

Есть 2 проблемы с этим биннингом:

  1. существует разрыв 1 между верхней границей (n-1)th бина и нижней границей nth бина (это означает, что группирование не является непрерывным, и точки данных, лежащие в этом промежутке, пропускаются).
  2. последние несколько пределов бина имеют много цифр после запятой. Я использовал флаг precision=0 в cut, но, похоже, он бесполезен - независимо от того, какой x я использую в precision=x, он все равно создает ячейки с несколькими последними ячейками, имеющими много цифр после запятой.

Второй пункт вызывает проблемы, когда, например, я пытаюсь построить df, где он портит вид оси X:

import matplotlib.pyplot as plt
plt.plot([str(i) for i in df.Age], df.Score, 'o-')

введите здесь описание изображения

Почему это происходит, несмотря на флаг precision=0, который я поставил, чтобы указать, что я хочу использовать только целые числа в качестве пределов корзины, а не числа с плавающей запятой? И как мне это исправить?


Я временно решаю эту проблему, вручную конвертируя значения bin в ints:

_, bins = np.histogram(data.Age, 10)
for i in range(len(bins)): # my fix
    bins[i] = int(bins[i])
labels = ['{}-{}'.format(i + 1, j) for i, j in zip(bins[:-1], bins[1:])]
labels[0] = '{}-{}'.format(bins[0], bins[1])
binned = pd.cut(data.Age, bins=bins, labels=labels, include_lowest=True, precision=0)
df = data.groupby(binned)['Score'].mean().reset_index()
df

введите здесь описание изображения

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


person Kristada673    schedule 10.08.2018    source источник


Ответы (1)


Что касается двух проблем, которые вы упомянули в своем вопросе, обе они возникают из-за одной строки в вашем коде, которая

labels = ['{}-{}'.format(i + 1, j) for i, j in zip(bins[:-1], bins[1:])]

Болтовня возникла из-за i+1, а также из-за компьютерной аппроксимации цифр в той же строке.

Поэтому измените его на

labels = [f'{i:.1f}-{j:.1f}' for i, j in zip(bins[:-1], bins[1:])]

в котором мы делаем приближение к одной цифре.

и не надо labels[0] = '{}-{}'.format(bins[0], bins[1])

person Nour-Allah Hussein    schedule 17.01.2021