使用“pandas.cut()”,我如何获得整数分箱并避免获得负的最低限度?
With `pandas.cut()`, how do I get integer bins and avoid getting a negative lowest bound?
我的数据框的最低值为零。我正在尝试使用 pandas.cut()
的 precision
和 include_lowest
参数,但我无法获得由整数而不是带一位小数的浮点数组成的间隔。我也无法让最左边的间隔停在零。
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')
有没有办法不用numpy直接用pandas.cut()
获取非负整数作为区间边界?
编辑: 我刚刚注意到指定 right=False
会使最低间隔变为 0 而不是 -0.4。它似乎优先于 include_lowest
,因为改变后者与 right=False
结合没有任何可见的效果。以下区间仍指定一位小数。
你应该专门设置 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)
@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)
None 的其他答案(包括 OP 的 np.histogram
解决方法)似乎不再有效。他们有赞成票,所以我不确定这些年来是否发生了一些变化。
IntervalIndex
要求所有间隔完全相同,因此 [0, 53]
不能与 (322, 376]
.
共存
这里有两个基于重新标记方法的可行解决方案:
没有 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]
使用 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')
我的数据框的最低值为零。我正在尝试使用 pandas.cut()
的 precision
和 include_lowest
参数,但我无法获得由整数而不是带一位小数的浮点数组成的间隔。我也无法让最左边的间隔停在零。
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')
有没有办法不用numpy直接用pandas.cut()
获取非负整数作为区间边界?
编辑: 我刚刚注意到指定 right=False
会使最低间隔变为 0 而不是 -0.4。它似乎优先于 include_lowest
,因为改变后者与 right=False
结合没有任何可见的效果。以下区间仍指定一位小数。
你应该专门设置 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)
@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)
None 的其他答案(包括 OP 的 np.histogram
解决方法)似乎不再有效。他们有赞成票,所以我不确定这些年来是否发生了一些变化。
IntervalIndex
要求所有间隔完全相同,因此 [0, 53]
不能与 (322, 376]
.
这里有两个基于重新标记方法的可行解决方案:
没有 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]
使用 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')