假如你学习了新的分类算法并想进一步探索研究、尝试不同的超参数评估模型性能,但问题是你找不到好的数据集用于实验。幸运的是Scikit-Learn 提供的 make_classification() 方法可以创建不同类型的数据集,它可以生成不同类型的数据集:二分类、多分类、平衡或不平衡数据集、难以分类的数据集等。本文通过示例详细说明,并结合随机森林分类算法进行验证。
make_classification函数
首先我们介绍该函数参数,以及常用参数及默认值:
n_samples
: 生成多少条样本数据,缺省100条.n_features
: 有几个数值类型特征,缺省为20.n_informative
: 有用特征的个数,仅这些特征承载对分类信号.,缺省为2.n_classes
: 分类标签的数量,缺省为2.
该函数返回包含函数Numpy 数组的tuple,分别为特征X,以及标签y。其他参数用到时再作说明。
生成二分类数据集
下面生成二分类数据集,即标签仅有两个可能的值:0 、1.
因此需要设置n_classes参数为2。我们需要生成1000条样本,包括5个特征,其中三个为有用特征,另外两个为冗余特征。
python
from sklearn.datasets import make_classification
X, y = make_classification(
n_samples=1000, # 1000 observations
n_features=5, # 5 total features
n_informative=3, # 3 'useful' features
n_classes=2, # binary target/label
random_state=999 # if you want the same results as mine
)
下面需转换 make_classification 函数返回值为 padas 数据框。padas 数据框比Numpy数组更易分析。
python
import pandas as pd
# Create DataFrame with features as columns
dataset = pd.DataFrame(X)
# give custom names to the features
dataset.columns = ['X1', 'X2', 'X3', 'X4', 'X5']
# Now add the label as a column
dataset['y'] = y
dataset.info()
输出结果:
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 1000 entries, 0 to 999
Data columns (total 6 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 X1 1000 non-null float64
1 X2 1000 non-null float64
2 X3 1000 non-null float64
3 X4 1000 non-null float64
4 X5 1000 non-null float64
5 y 1000 non-null int64
dtypes: float64(5), int64(1)
memory usage: 47.0 KB
和我们期望一致,该数据集包括1000个样本,包括5个特征,以及对应的响应目标标签。我们设置**n_informative
** 为3,因此,仅 (X1 , X2 , X3 )是重要的,另外两个 X4 和 X5, 是多余的。
现状我们检查标签y的基数和总数:
python
dataset['y'].value_counts()
1 502
0 498
Name: y, dtype: int64
标签仅包括两个可能的值,因此属于二分类数据集。而且两者数量大致相当,因此标签分类相对平衡。下面查看前5条样本值:
python
dataset.head()
X1 | X2 | X3 | X4 | X5 | y | |
---|---|---|---|---|---|---|
0 | 2.501284 | -0.159155 | 0.672438 | 3.469991 | 0.949268 | 0 |
1 | 2.203247 | -0.331271 | 0.794319 | 3.259963 | 0.832451 | 0 |
2 | -1.524573 | -0.870737 | 1.004304 | -1.028624 | -0.717383 | 1 |
3 | 1.801498 | 3.106336 | 1.490633 | -0.297404 | -0.607484 | 0 |
4 | -0.125146 | 0.987915 | 0.880293 | -0.937299 | -0.626822 | 0 |
分类示例
生成数据集看上去不错,下面利用缺省超参数创建随机森林分类器。我们使用交叉验证衡量模型性能:
python
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import cross_validate
# initialize classifier
classifier = RandomForestClassifier()
# Run cross validation with 10 folds
scores = cross_validate(
classifier, X, y, cv=10,
# measure score for a list of classification metrics
scoring=['accuracy', 'precision', 'recall', 'f1']
)
scores = pd.DataFrame(scores)
scores.mean().round(4)
输出结果如下, 模型的 Accuracy, Precision, Recall, 和 F1 Score接近88%. 没有调整任何超参数情况下,表现尚可。
text
fit_time 0.1201
score_time 0.0072
test_accuracy 0.8820
test_precision 0.8829
test_recall 0.8844
test_f1 0.8827
dtype: float64
不易分类数据集
下面尝试创建要给不容易分类的数据集。我们可以使用下面**make_classification()**函数参数控制数据集的难度级别:
flip_y
: 通过反转少量标签增加噪声数据 . 举例,改变少量标签值0的值为1,返回改变1为0. 该值越大噪声越多,缺省值为 0.01.class_sep
: 类别之间的距离,默认值为1.0,表示原始特征空间中的类别之间的平均距离. 值越小分类越难.
下面代码使用flip_y
较高的值与class_sep
较低的值创建有挑战性的数据集:
python
X, y = make_classification(
# same as the previous section
n_samples=1000, n_features=5, n_informative=3, n_classes=2,
# flip_y - high value to add more noise
flip_y=0.1,
# class_sep - low value to reduce space between classes
class_sep=0.5
)
# Check label class distribution
pd.DataFrame(y).value_counts()
1 508
0 492
dtype: int64
0 和 1 标签对应的样本量几乎相当。因此分类相对平衡。
分类较难数据集
我们再次构建随机森林模型,并使用默认超参数。这次使用较难的数据集:
python
classifier = RandomForestClassifier()
scores = cross_validate(
classifier, X, y, cv=10,
scoring=['accuracy', 'precision', 'recall', 'f1']
)
scores = pd.DataFrame(scores)
scores.mean()
fit_time 0.138662
score_time 0.007333
test_accuracy 0.756000
test_precision 0.764619
test_recall 0.760196
test_f1 0.759281
dtype: float64
模型的Accuracy , Precision , Recall , 和F1 Score 参数值大约在75~76%.相对前面88%有了明显下降。
flip_y
和**class_sep
** 参数值起作用了,它们创建的数据集确实较难分类。
不平衡数据集
前面我们创建的数据集,每个分类对应样本大致相等。但有时我们需要不平衡数据集,即其中一个标签分类样本数据比较稀少。
我们可以使用参数weights
去控制每个分类的比例。下面代码利用make_classification 函数给样本0值标签分配比例97%, 剩下了的分类值1占3%:
python
X, y = make_classification(
# the usual parameters
n_samples=1000, n_features=5, n_informative=3, n_classes=2,
# Set label 0 for 97% and 1 for rest 3% of observations
weights=[0.97],
)
pd.DataFrame(y).value_counts()
0 964
1 36
dtype: int64
从结果看,**make_classification()**函数分配了3%比例给标签值为1的样本,确实生成了不平衡数据集。
分类不平衡数据集
与前节一样,仍使用缺省超参数的随机森林模型训练不平衡数据集:
python
classifier = RandomForestClassifier()
scores = cross_validate(
classifier, X, y, cv=10,
scoring=['accuracy', 'precision', 'recall', 'f1']
)
scores = pd.DataFrame(scores)
scores.mean()
fit_time 0.101848
score_time 0.006896
test_accuracy 0.964000
test_precision 0.250000
test_recall 0.083333
test_f1 0.123333
dtype: float64
我们看到有趣的现象,我们的模型准确率很高(96%),但精确率和召回率很低(25% 和 8%)。这是典型的准确率悖论,当处理不平衡数据经常会发生。
多分类数据集
到目前为止,我们生成的标签仅有两种可能。如果你需要多分类数据做实验,则标签需要超过2个值。n_classes
参数可以实现:
python
X, y = make_classification(
# same parameters as usual
n_samples=1000, n_features=5, n_informative=3,
# create target label with 3 classes
n_classes=3,
)
pd.DataFrame(y).value_counts()
1 334 2 333 0 333 dtype: int64
从结果看,三个分类样本大致相当,数据集分类较平衡。
多分类不平衡数据集
我们也可以很容易创建不平衡多分类数据集,只需要使用参数 n_classes 和 weights :
python
X, y = make_classification(
# same parameters as usual
n_samples=1000, n_features=5, n_informative=3,
# create target label with 3 classes
n_classes=3,
# assign 4% of rows to class 0, 48% to class 1
# and the rest to class 2
weights=[0.04, 0.48]
)
pd.DataFrame(y).value_counts()
0 值分类占 4%, 1 值占 48%, 剩下的给值 2 标签。查看结果:
2 479 1 477 0 44 dtype: int64
1000个样本中 0 值标签仅有44个,和预期一致。
总结
现在你学会了使用scikit-learn的make_classification函数生成不同类型数据集了吧。包括二分类或多分类、不平衡数据集、挑战性难分类的数据集等。更多参数可以查看官方文档,本文参考:How to Generate Datasets Using make_classification | Proclus Academy。