估计收入
我们将建立一个分类器, 根据14个属性来估计一个人的收入. 可能的输出类别高于50K或低于或等于50K. 在这个数据集中存在轻微的扭曲, 每个数据点是数字和字符串的混合. 数值数据是有价值的, 我们不能在这些情况下使用标签编码器. 我们需要设计一个可以同时处理数值和非数值数据的系统. 我们将使用https://archive.ics.uci.edu/ml/datasets/Census+Income上的普查收入数据集.
怎么做...?
- 我们将使用已经提供给您的income.py文件作为参考. 我们将使用朴素贝叶斯分类器来实现这一点. 让我们导入几个包:
import numpy as np
from sklearn import preprocessing
from sklearn.naive_bayes import GaussianNB
from sklearn.model_selection import (
train_test_split,
cross_val_score
)
- 载入数据
input_file = 'adult.data.txt'
# Reading the data
X = []
y = []
count_lessthan50k = 0
count_morethan50k = 0
num_images_threshold = 30000
with open(input_file, 'r') as f:
for line in f.readlines():
if '?' in line:
continue
data = line[:-1].split(', ')
if data[-1] == '<=50K' and count_lessthan50k < num_images_threshold:
X.append(data)
count_lessthan50k = count_lessthan50k + 1
elif data[-1] == '>50K' and count_morethan50k < num_images_threshold:
X.append(data)
count_morethan50k = count_morethan50k + 1
if (
count_lessthan50k >= num_images_threshold) and (
count_morethan50k >= num_images_threshold):
break
X = np.array(X)
我们将使用来自数据集的20,000个数据点 - 每个类10,000个数据点, 以避免类不平衡. 在训练期间, 如果您使用属于单个类的许多数据点, 分类器往往偏向于此类. 因此, 最好对每个类使用相同数量的数据点.
我们需要将字符串属性转换为数值数据, 同时省去原始的数值数据:
# Convert string data to numerical data
label_encoder = []
X_encoded = np.empty(X.shape)
for i, item in enumerate(X[0]):
if item.isdigit():
X_encoded[:, i] = X[:, i]
else:
label_encoder.append(preprocessing.LabelEncoder())
X_encoded[:, i] = label_encoder[-1].fit_transform(X[:, i])
X = X_encoded[:, :-1].astype(int)
y = X_encoded[:, -1].astype(int)
isdigit()函数帮助我们识别数值数据. 我们将字符串数据转换为数字数据, 并将所有标签编码器存储在列表中, 以便我们在对未知数据进行分类时使用它.
- 训练分类器:
classifier_gaussiannb = GaussianNB()
classifier_gaussiannb.fit(X, y)
- 让我们将数据分成训练和测试以提取性能指标:
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.25, random_state=5)
classifier_gaussiannb = GaussianNB()
classifier_gaussiannb.fit(X_train, y_train)
y_test_pred = classifier_gaussiannb.predict(X_test)
- 提取性能指标:
f1 = cross_val_score(
classifier_gaussiannb,
X, y,
scoring='f1_weighted', cv=5
)
print ("F1 score: " + str(round(100 * f1.mean(), 2)) + "%")
- 让我们看看如何分类单个数据点. 我们需要将数据点转换为我们的分类器可以理解的东西:
input_data = [
'39', 'State-gov',
'77516', 'Bachelors',
'13', 'Never-married',
'Adm-clerical', 'Not-in-family',
'White', 'Male',
'2174', '0',
'40', 'United-States']
count = 0
input_data_encoded = [-1] * len(input_data)
for i, item in enumerate(input_data):
if item.isdigit():
input_data_encoded[i] = int(input_data[i])
else:
input_data_encoded[i] = int(
label_encoder[count].transform(
np.array([input_data[i]]).ravel()))
count = count + 1
input_data_encoded = np.array(input_data_encoded).reshape(-1, 1)
- 现在估计数据点
output_class = classifier_gaussiannb.predict(input_data_encoded)
print (label_encoder[-1].inverse_transform(output_class)[0])
就像以前一样, 我们使用predict方法来获取输出类和inverse_transform方法来将此标签转换回其原始形式, 以在终端上打印出来.