如何使用pandas cut()和qcut()
Pandas是一个开源的库,主要是为了方便和直观地处理关系型或标签型数据。它提供了各种数据结构和操作来处理数字数据和时间序列。
在本教程中,我们将看看pandas的智能剪切和qcut函数。基本上,我们使用cut和qcut将数字列转换为分类列,也许是为了使其更适合机器学习模型(如果是一个相当倾斜的数字列),或者只是为了更好地分析手头的数据。现在,与其大声说出cut和qcut的技术定义,我们还不如看看这两个函数有什么用处,以及如何使用它们。
我们首先要导入必要的数据操作库。
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
我们将使用CarDekho的数据集,其中包含平台上列出的二手车数据。你可以在这里找到该数据集。
- ‘年’是指购买汽车的年份。
- ‘Selling_Price’是车主想卖的价格。
- Present_Price “是汽车目前的展厅售价。
- 车主 “定义了在这辆车被放到平台上之前,这辆车以前有多少个车主。
其余的栏目都是不言自明的。
df = pd.read_csv('cardekho.csv')
df.head()
输出:
# no missing values in the dataset
df.info()
我们将注入一个缺失值,以更好地展示切割和qcut将如何处理一个 “不完美 “的数据集。
df.loc[0, 'Year'] = np.nan
# these are the 'unique' years in
# the data
np.array(sorted(df.Year.unique()))
输出:
pd.cut()
我们可以通过2种方式使用’cut’函数:直接指定bin的数量,让pandas为我们计算等大小的bin,或者我们可以按照自己的意愿手动指定bin的边缘。
# right = True, by default
pd.cut(df.Year, bins=3, right=True).head()
输出:
当我们指定bins=3时,pandas看到数据中的年份范围是2003年到2018年,因此适当地把它切成3个等宽的bins,每个bins5年。[(2002.985, 2008.0] < (2008.0, 2013.0]< (2013.0, 2018.0].请注意,pandas自动将第一类的下限值(2002.985)比 “年份 “一栏中的最小值(2003)少了一部分,以便将2003年也包括在结果中,因为你看到,这些分类的下限是开放的,而上限是封闭的(因为right=True)。
注意: __你是否注意到,在输出结果中,NaN值也被保留为NaN?当我们指定right=False时,左边的边界现在是封闭的,而右边的边界是开放的。
pd.cut(df.Year, bins=3, right=False).head()
输出:
我们可以将’标签’参数指定为一个列表,而不是获得间隔,以便更好地分析。
pd.cut(df.Year, bins=3,
labels=['old', 'medium', 'new']).head()
输出:
我们将把这个系列分配回原始数据框架。
df['Yr_cut'] = pd.cut(df.Year, bins=3,
labels=['old', 'medium', 'new'])
df.head()
输出:
如果我们指定labels=False,而不是bin标签,我们将得到bin的数字表示:这里,0代表旧的,1是中等的,2是新的。
pd.cut(df.Year, bins=3, labels=False).head()
输出:
只是为了看看有多少值落在每个仓里。
df['Yr_cut'].value_counts()
输出:
就因为画图取悦了更多的人,而不是冒犯了。
df['Yr_cut'].value_counts().plot(kind='barh')
plt.show()
输出:
现在,如果我们需要一次性获得bin区间和离散的序列,我们可以指定retbins=True。Pandas会给我们一个包含两个元素的元组:系列和bin区间。我们将使用元组解包来获取两个输出。
cut_series, cut_intervals = pd.cut(df.Year,
bins=3,
retbins=True)
print("Cut series:")
print(cut_series.head())
print()
print("Cut intervals: ", cut_intervals)
输出:
如前所述,我们也可以通过传入一个列表来手动指定bin边缘。
pd.cut(df.Year, bins=[2003,
2007,
2010,
2015,
2018],
include_lowest=True).head()
输出:
在这里,我们不得不提到include_lowest=True。你能猜到为什么吗?因为默认情况下,’include_lowest’参数被设置为False,因此当pandas看到我们传递的列表时,它将把2003排除在计算之外。对于老眼昏花的人来说,我们也可以使用任何小于2003的值,比如1999或2002或2002.255等,然后继续使用默认设置include_lowest=False。
pd.qcut()
Qcut(quantile-cut)与cut的区别在于,在qcut中,每个bin中的元素数量将大致相同,但这将以不同大小的区间宽度为代价。另一方面,在cut中,bin边缘的大小是相等的(当我们指定bins=3时),每个bin或组中的元素数量不均匀。另外,当你确定知道区间范围和bin的时候,cut是很有用的。
例如,如果对 “年龄 “列进行分档,我们知道婴儿在0到1岁之间,1-12岁是孩子,13-19岁是青少年,20-60岁是工作阶层的成年人,60岁以上是老年人。所以我们可以适当地设置bins=[0, 1, 12, 19, 60, 140]和labels=[‘infant’, ‘kid’, ‘teenager’, ‘grownup’, ‘senior citizen’]。在qcut中,当我们指定q=5时,我们告诉pandas将Year列切成5个相等的量级,即0-20%,20-40%,40-60%,60-80%和80-100%桶/箱。
pd.qcut(df.Year, q=5).head(7)
输出:
我们将把这个系列分配给数据框架。
df['Yr_qcut'] = pd.qcut(df.Year, q=5,
labels=['oldest',
'not so old',
'medium',
'newer',
'latest'])
df.head()
df['Yr_qcut'].value_counts().plot(kind='barh')
plt.show()
qcut_series, qcut_intervals = pd.qcut(df.Year, q=5,
labels=['oldest',
'not so old',
'medium',
'newer',
'latest'],
retbins=True)
qcut_series.value_counts()
输出:
现在,为了强调q=5确实意味着将数值分成5个相等的量级,每个量级20%,我们将手动指定量级,并得到与上面相同的bin分布。
pd.qcut(df.Year,
q=[0, 0.2, 0.4,
0.6, 0.8, 1.0],
labels=['oldest',
'not so old',
'medium',
'newer',
'latest']).value_counts()
输出:
我们现在来看看我们用元组解包得到的qcut间隔数组。
qcut_intervals
输出:
你看到了吗?在qcut中,仓的边缘是不等宽的,因为它要容纳每个桶中20%的值,因此它要自己计算仓的宽度来实现这一目标。
# demonstrating with some random quantiles
pd.qcut(df.Year, q=[0,0.15,0.35,
0.51,0.78,1]).head()
输出:
现在,它正在将数据分到我们定制的0-15%、15-35%、35-51%、51-78%和78-100%的量级列表中。
通过qcut,我们要回答 “哪些数据点位于数据的前15%,或者在51-78的百分位数范围内 “的问题。此外,我们还可以使用pandas的interval_range,或者numpy的linspace和range来生成一个区间范围的列表,并将其分别作为bin和q参数送入cut和qcut。
pd.cut(df.Year,
bins=pd.interval_range(start=2002.99,
end=2018,
periods=3)).head()
输出:
Using linspace:
# basically dividing data into 3
# quantiles
pd.qcut(df.Kms_Driven,
q=np.linspace(0,1,4)).head()
输出:
Using arange:
pd.qcut(df.Selling_Price,
q=np.arange(0, 1.01, 0.25),
labels=['inexpensive',
'average',
'high cost',
'over budget']).head()
输出:
有时,当我们要求pandas为我们计算bin edges时,你可能会遇到一个错误,看起来像。
ValueError。仓边必须是唯一的错误。这意味着在计算bin区间的时候,pandas发现有些bin边两端是一样的,比如(2014,2014)的区间,因此它引发了这个错误。这通常发生在bin的数量很大,而特定列的值范围很小的时候。你可以通过传递 duplicates=’drop’的参数来消除这个错误。