使用`pandas.cut()`,如何获得整数箱并避免获得负的最低界限?

问题描述 投票:0回答:4

我的数据框的最低值为零。我正在尝试使用

precision
include_lowest
pandas.cut()
参数,但我无法获得由整数组成的间隔,而不是带有一位小数的浮点数。我也无法让最左边的间隔停在零。

import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt

sns.set(style='white', font_scale=1.3)

df = pd.DataFrame(range(0,389,8)[:-1], columns=['value'])
df['binned_df_pd'] = pd.cut(df.value, bins=7, precision=0, include_lowest=True)
sns.pointplot(x='binned_df_pd', y='value', data=df)
plt.xticks(rotation=30, ha='right')

我尝试将

precision
设置为-1、0和1,但它们都输出一位十进制浮点数。
pandas.cut()
帮助确实提到 x-min 和 x-max 值扩展了 x-范围的 0.1%,但我认为
include_lowest
可能会以某种方式抑制这种行为。我当前的解决方法包括导入 numpy:

import numpy as np

bin_counts, edges = np.histogram(df.value, bins=7)
edges = [int(x) for x in edges]
df['binned_df_np'] = pd.cut(df.value, bins=edges, include_lowest=True)

sns.pointplot(x='binned_df_np', y='value', data=df)
plt.xticks(rotation=30, ha='right')

有没有办法直接用

pandas.cut()
获取非负整数作为区间边界而不使用numpy?

编辑:我刚刚注意到指定

right=False
会使最低间隔移动到0而不是-0.4。它似乎优先于
include_lowest
,因为更改后者与
right=False
结合使用不会产生任何明显的效果。以下间隔仍指定一位小数。

python pandas intervals bins
4个回答
5
投票

您应该专门设置

labels
参数

准备工作:

lower, higher = df['value'].min(), df['value'].max()
n_bins = 7

建立标签:

edges = range(lower, higher, (higher - lower)/n_bins) # the number of edges is 8
lbs = ['(%d, %d]'%(edges[i], edges[i+1]) for i in range(len(edges)-1)]

设置标签:

df['binned_df_pd'] = pd.cut(df.value, bins=n_bins, labels=lbs, include_lowest=True)

3
投票

其他答案(包括OP的

np.histogram
解决方法)似乎都不再有效。他们有投票,所以我不确定这些年来是否发生了变化。

IntervalIndex
要求所有区间都同样闭合,因此
[0, 53]
不能与
(322, 376]
共存。


以下是基于重新标记方法的两种可行解决方案:

  1. 没有numpy,重用

    pd.cut
    边缘作为
    pd.cut
    标签

    bins = 7
    
    _, edges = pd.cut(df.value, bins=bins, retbins=True)
    labels = [f'({abs(edges[i]):.0f}, {edges[i+1]:.0f}]' for i in range(bins)]
    
    df['bin'] = pd.cut(df.value, bins=bins, labels=labels)
    
    #     value         bin
    # 1       8     (0, 53]
    # 2      16     (0, 53]
    # ..    ...         ...
    # 45    360  (322, 376]
    # 46    368  (322, 376]
    
  2. 使用 numpy,

    np.linspace
    边转换为
    pd.cut
    标签

    bins = 7
    
    edges = np.linspace(df.value.min(), df.value.max(), bins+1).astype(int)
    labels = [f'({edges[i]}, {edges[i+1]}]' for i in range(bins)]
    
    df['bin'] = pd.cut(df.value, bins=bins, labels=labels)
    
    #     value         bin
    # 1       8     (0, 53]
    # 2      16     (0, 53]
    # ..    ...         ...
    # 45    360  (322, 376]
    # 46    368  (322, 376]
    

注意:仅更改标签,因此基础分箱仍将以 0.1% 的边距发生。


pointplot()
输出(从pandas 1.2.4开始):

sns.pointplot(x='bin', y='value', data=df)
plt.xticks(rotation=30, ha='right')


3
投票

@joelostblom,你已经完成了大部分工作,而不是使用 numpy, 只需使用 pandas 已经提供的功能,即返回垃圾箱。

_, edges = pd.cut(df.value, bins=7, retbins=True)
edges = [int(x) for x in edges]
df['binned_df_np'] = pd.cut(df.value, bins=edges, include_lowest=True)

0
投票

您也可以拥有闭整数区间。让

nbins = 7

  1. 找到要切割的边缘(Pandas 或 Numpy)。

    # NumPy
    edges = np.linspace(df.value.min(), df.value.max(), nbins + 1)
    edges[-1] += 1
    
    # Pandas
    float_binned, edges = pd.cut(df.value, bins=nbins, right=False, retbins=True)
    edges[-1] = df.values.max() + 1
    

    对于您的数据,这是:

    [  0.  ,  53.71, 107.43, 161.14, 214.86, 268.57, 322.29, 377.  ]

  2. 从边缘开始形成闭合整数区间。

    edges = edges.round()  # optional, for more uniform length of intervals
    intervals = [pd.Interval(int(left), int(right) - 1, 'both')
                 for left, right in zip(edges[:-1], edges[1:])]
    

    对于您的数据,这是:

    [[0, 53], [54, 106], [107, 160], [161, 214], [215, 268], [269, 321], [322, 376]]

  3. 使用间隔切割数据。

    int_binned = pd.cut(df.value, intervals)
    

    对于您的数据,这是:

    0        [0, 53]
    1        [0, 53]
    2        [0, 53]
    ...
    45    [322, 376]
    46    [322, 376]
    47    [322, 376]
    Name: value, dtype: category
    Categories (7, interval[int64, both]): [[0, 53] < [54, 106] < [107, 160] < [161, 214] < [215, 268] < [269, 321] < [322, 376]]
    

然后你就可以制作你的情节了:

df['binned_value'] = int_binned
sns.pointplot(x='binned_value', y='value', data=df)
plt.xticks(rotation=30, ha='right')

© www.soinside.com 2019 - 2024. All rights reserved.