如何将连续变量转换为分类变量?

Posted

技术标签:

【中文标题】如何将连续变量转换为分类变量?【英文标题】:How to convert a continuous variable to a categorical variable? 【发布时间】:2019-11-24 14:38:16 【问题描述】:

请用这个为我指明正确的方向。如何将包含连续变量的列转换为离散变量?我有一些金融工具的价格,我正试图将其转换为某种分类价值。我想我可以做到以下几点。

labels = df['PRICE'].astype('category').cat.categories.tolist()
replace_map_comp = 'PRICE' : k: v for k,v in zip(labels,list(range(1,len(labels)+1)))
print(replace_map_comp)

但是,当我尝试对数据子集运行 RandomForestClassifier 时,我遇到了错误。

from sklearn.ensemble import RandomForestClassifier
features = np.array(['INTEREST',
'SPREAD',
'BID',
'ASK',
'DAYS'])
clf = RandomForestClassifier()
clf.fit(df[features], df1['PRICE'])

错误信息为:ValueError: Unknown label type: 'continuous'

我很确定这很接近,但这里肯定有什么问题。

以下代码更新:

# copy only numerics to new DF
df1 = df.select_dtypes(include=[np.number])

from sklearn import linear_model
features = np.array(['INTEREST',
'SPREAD',
'BID',
'ASK',
'DAYS'])
reg = linear_model.LinearRegression()
reg.fit(df1[features], df1['PRICE'])

# problems start here...
importances = clf.feature_importances_
sorted_idx = np.argsort(importances)

padding = np.arange(len(features)) + 0.5
plt.barh(padding, importances[sorted_idx], align='center')
plt.yticks(padding, features[sorted_idx])
plt.xlabel("Relative Importance")
plt.title("Variable Importance")
plt.show()

错误:AttributeError:“LinearRegression”对象没有属性“feature_importances_”

从这里开始遵循概念:

http://blog.yhat.com/tutorials/5-Feature-Engineering.html

仅供参考,我尝试了 one-hot 编码,但代码转换使列变得太大,并且出现错误。也许处理这个问题的方法是获取一小部分数据。对于 250k 行,我猜可能 100k 行应该相当代表整个数据集。也许这就是要走的路。只是在这里大声思考。

【问题讨论】:

为什么要使用分类器?为什么不尝试回归量? 你有多少种不同的价格?您尝试将数据转换为分类数据的原因是什么? 【参考方案1】:

Pandas 有一个 cut 函数,可以用于您想要做的事情:

import pandas as pd
import numpy as np
from scipy.stats import norm
from sklearn.ensemble import RandomForestClassifier
from sklearn.preprocessing import LabelEncoder

label_encoder = LabelEncoder()
n_bins = 5
df = pd.DataFrame(data=norm.rvs(loc=500, scale=50, size=100),
                  columns=['PRICE'])
y = label_encoder.fit_transform(pd.cut(df['PRICE'], n_bins, retbins=True)[0])
rfc = RandomForestClassifier(n_estimators=100, verbose=2)
rfc.fit(df[['PRICE']], y)

这是一个示例。首先要知道有一百种不同的方式可以做到这一点,所以这不一定是“正确”的方式;这只是一种方式。

主要思想:使用 Pandas cut 函数为连续数据创建桶。桶的数量由您决定。在本例中,我选择了n_bins 作为5

在你拥有这些 bin 之后,可以使用 sklearn 的LabelEncoder() 将它们转换为类。这样,您可以以更简单的方式引用这些类。它就像您的班级的存储系统,因此您可以跟踪它们。使用label_encoder.classes_ 查看课程。

完成这些步骤后,y 将如下所示:

array([1, 2, 2, 0, 2, 2, 0, 1, 3, 1, 1, 2, 1, 4, 4, 2, 3, 1, 1, 3, 2, 3,
       2, 2, 2, 0, 2, 2, 4, 1, 3, 2, 1, 3, 3, 2, 1, 4, 3, 1, 1, 4, 2, 3,
       3, 2, 1, 1, 3, 4, 3, 3, 3, 2, 1, 2, 3, 1, 3, 1, 2, 0, 1, 1, 2, 4,
       1, 2, 2, 2, 0, 1, 0, 3, 3, 4, 2, 3, 3, 2, 3, 1, 3, 4, 2, 2, 2, 0,
       0, 0, 2, 2, 0, 4, 2, 3, 2, 2, 2, 2])

您现在已经将连续数据转换为类,现在可以传递给RandomForestClassifier()

【讨论】:

我刚刚在我的原始帖子中添加了一个名为“以下代码更新:”的部分。这似乎是正确的方法,还是我离这里很远? 我显示norm.rvs 只是为了为价格变量生成一些虚假的连续数据。在您的情况下,price 等于 df1['PRICE']。这个想法是,df1['PRICE'] 中有连续数据,如果你想要 5 个 bin,你应该使用pd.cut(df1['PRICE'], 5)【参考方案2】:

分类器适用于您面对已解释变量的类别并且价格不是类别,除非您将总和精确到类别:

df['CLASS'] = np.where( df.PRICE > 1000, 1, 0) # Classify price above 1000 or less

在使用连续解释变量的情况下,回归方法是非常可取的。

from sklearn import linear_model
reg = linear_model()
reg.fit(df[features], df['CLASS'])

【讨论】:

好的,我得到了配件部分。现在,我收到以下错误: AttributeError: 'LinearRegression' object has no attribute 'feature_importances_' 我用我当前的更改更新了我的原始帖子。我正在尝试在数据框中找到最重要的功能,并绘制所有内容。这就是我的目标。 改用reg.coef_ 哦,开枪!这很有效,也很有意义!非常感谢,非常感谢!【参考方案3】:

单热编码是一种方法。

https://www.ritchieng.com/machinelearning-one-hot-encoding/

https://scikit-learn.org/stable/modules/generated/sklearn.preprocessing.OneHotEncoder.html

看起来像这样: 来源:https://towardsdatascience.com/natural-language-processing-count-vectorization-with-scikit-learn-e7804269bb5e

【讨论】:

【参考方案4】:
from sklearn.preprocessing import LabelEncoder
label_encoder = LabelEncoder()
n_bins = 10
dseries, return_bins = pd.qcut(train['price'], n_bins, retbins=True)

n_bins=n_bins+2
return_bins[0]=return_bins[0]*.99
return_bins[-1]=return_bins[-1]*0.99
return_bins_lst=[r for r  in return_bins]
return_bins_lst.insert(0,return_bins[0]*1000)
return_bins_lst.append(return_bins[-1]*1000)
return_bins=np.array(return_bins_lst)
 
train['label']=label_encoder.fit_transform(pd.cut(train['price'], return_bins, 
labels=range(n_bins)))
test['label']=label_encoder.transform(pd.cut(test['price'], return_bins, 
labels=range(n_bins)))

几乎使用了 Jarad 给出的示例,但进行了一些概括,以便您可以在训练/测试数据集之间保持编码一致

【讨论】:

【参考方案5】:

除了许多其他方法,实现分箱的简单方法是:按距离分箱或按频率分箱。

import pandas as pd
df = pd.read_csv('Tax_Calculation.csv')
min = df['Direct_Tax'].min()
max = df['Direct_Tax'].max()

假设所需的 bin 数量为:4,因此我们需要 5 个边(边 = number_of_bin + 1)。 edge1 Bin1 edge2 Bin2 edge3 Bin3 edge4 Bin4 edge5

import numpy as np
bins = np.linspace(min,max, 5)

按距离分箱(将值分组到箱数中):

df['bins_dist'] = pd.cut(df['Direct_Tax'], bins=bins, labels=[ExSmall, Small, Medium, Large], include_lowest=True)

按频率分箱(按观察次数分箱):每个分箱将包含几乎相同数量的观察

df['bin_freq'] = pd.qcut(df['Direct_Tax'], q=4, precision=1, labels=[ExSmall, Small, Medium, Large])

【讨论】:

以上是关于如何将连续变量转换为分类变量?的主要内容,如果未能解决你的问题,请参考以下文章

R语言笔记——将分类变量转换为连续变量

如何在 R 中将分类变量转换为连续变量?

是否有将分类变量转换为连续变量的 R 函数?

重新编码连续变量_summary

如何将 JAVa中的 String类变量嵌入SQL查询语句中...?

通过对连续变量进行分组来替换分类变量的 NaN