简介
这个作业是根据一个人口普查的数据判断年收入是否>50K。
输入有:一个人的年龄、受教育程度、职业、国籍等14项参数共2w笔
输出:这个人年收入是否>50K
思路分析
这个作业是一个二分类问题。使用逻辑回归比较好使。实际就是在线性回归的基础上加sigmoid函数,将其转化为概率。
与线性回归的主要区别在于loss函数的计算上。逻辑回归采用交叉滴的方法;线性回归采用欧氏距离的方法。
数据预处理
源数据都是干净的数据,而且格式很好,省去的很多麻烦。
直接进行数值化、归一化即可。
- 数值化:它很多的项中是利用字符串表示的。比如国籍这一项,内容就像这样:
native-country: United-States, Cambodia, England, Puerto-Rico, Canada, Germany, Outlying-US(Guam-USVI-etc).
等。为了能够让计算机处理,就需要将其数值化。
数值化时我想到了两种解决方案,
1.用数值表示。比如:中国=1.0,美国=2.0,英国=3.0等等。
2.将国籍中的每个国家作为一个项,如果国籍是这个国家,则该项为1,否则是0。
如果用方案1的话,不同的国家之间,看起来就像有联系似的,但是实际并没有。所以在作业中使用了方案2.
ps:这里还可以用one-hot编码方式。这是我已经数据处理完之后才想到的,所以没有过多涉猎。 - 归一化:把数据范围尽量scale到同一个数量级上。(这里我不能肯定的给出为什么这么做。如果有小伙伴清楚,麻烦留个言Thanks♪(・ω・)ノ)。查看数据,发现实际只有6项需要归一化。
模型介绍
详见https://www.cnblogs.com/HL-space/p/10785225.html。这篇文章介绍的已经很详细了。
代码
对文件进行预处理 源文件是老师提供的官方文件,已在参考资料中提供下载
输出是两个文件。分别是answer.csv(结果)和data.csv(人口的各个数据)。
import pandas as pd
from pandas import DataFrame,Series
import numpy as np
import csv
rdf = pd.read_excel("C:/Users/帅哥/Desktop/普查数据 .xlsx")
#重写文件的列
name_list = []
name_list.append('age')
name_list.append('fnlwgt')
name_list.append('education-num')
name_list.append('capital-gain')
name_list.append('capital-loss')
name_list.append('hours-per-week')
all_array =np.array(rdf)
x,y = all_array.shape
data_array = all_array[:,:14]
#结果集
answer_list=[1 if i==[' >50K']else 0 for i in all_array[:,14:15]]
trans_array =np.transpose(data_array)#将数组翻转,用于找到项
for i in trans_array:
for j in i:
if type(j) is str and j not in name_list:
name_list.append(j)
name_list.remove(' ?')
#生成实际用的数据集
train_array = np.zeros((int(x),len(name_list)))
for i in range(x):
train_array[i][0] = data_array[i][0]
train_array[i][1] = data_array[i][2]
train_array[i][2] = data_array[i][4]
train_array[i][3] = data_array[i][10]
train_array[i][4] = data_array[i][11]
train_array[i][5] = data_array[i][12]
for j in range(14):
if data_array[i][j] in name_list:
train_array[i][name_list.index(data_array[i][j])] = 1
for j in range(6):
train_array[:,j]/=np.mean(train_array[:,j])
#将数据集写入文件
with open("C:/Users/帅哥/Desktop/data.csv","w",newline='') as csvfile:
writer = csv.writer(csvfile)
writer.writerow(name_list)
writer.writerows(train_array.tolist())
csvfile.close()
#将结果集写入文件
answer = {'answer':answer_list}
df1 = pd.DataFrame(answer)
df1.to_csv("C:/Users/帅哥/Desktop/answer.csv",index=None)
print("over")
模型训练和验证集验证
print("开始执行")
import pandas as pd
import numpy as np
import math
data=pd.read_csv("C:/Users/帅哥/Desktop/data.csv")
answer = pd.read_csv("C:/Users/帅哥/Desktop/answer.csv")
#数据切割为训练集和测试集
array = np.array(data)
array1 = np.array(answer)
x,y = array.shape
train_num = int(0.67*x)
test_num = x-int(train_num)
train_data = array[:train_num,:]
test_data = array[train_num:,:]
train_answer = array1[:train_num]
test_answer = array1[train_num:]
#更新参数、训练模型
bias = 0#偏置初始化
weights = np.ones(y)#权重初始化
learning_rate = 1
reg_rate = 0.0001
bg2_sum = 0#偏置值的梯度平方和
wg2_sum = np.zeros(y)#偏置的梯度平方和
#Pn = np.zeros(y)
print("开始循环处理")
epoches = 700
for times in range(epoches):
b_g = 0
w_g = np.zeros(y)
for i in range(train_num):
#计算b偏导和w偏导
# Pn = weights.dot(train_data[i,:])+bias
#Pn/=8
Pn = weights.dot(train_data[i, :]) + bias
sigmoid = 1/(1+np.exp(-Pn))#Pn
temp = -(train_answer[i] - sigmoid)
b_g += temp
w_g +=train_data[i,:]*temp#+2*reg_rate*weights# 这里可以加入正则项,防止过拟合
b_g/=train_num
w_g/=train_num
#adagrad
bg2_sum+=b_g**2
wg2_sum+=w_g**2
#更新权重和偏置
bias -= learning_rate * b_g / bg2_sum ** 0.5
weights -= learning_rate * w_g / wg2_sum ** 0.5
if times%10== 0:
#print("测试点2")
loss = 0
acc = 0
result = np.zeros(train_num)
for j in range(train_num):
#print("测试点3")
y_pre = weights.dot(train_data[j,:])+bias
#print("测试点4")
sig = 1/(1+np.exp(-y_pre))
if sig >= 0.5:
result[j] = 1
else:
result[j] = 0
if result[j] == train_answer[j]:
acc+=1.0
print("after {} epoches,the acc on train data:".format(times),acc/train_num)
# 验证模型效果
acc = 0
result = np.zeros(test_num)
for j in range(test_num):
y_pre = weights.dot(test_data[j, :]) + bias
sig = 1 / (1 + np.exp(-y_pre))
if sig >= 0.5:
result[j] = 1
else:
result[j] = 0
if result[j] == test_answer[j]:
acc += 1.0
print("after train,the acc on test data:",acc/test_num)
结果
- 利用自己做的数据得出的结果
- 基于秋沐霖博主的数据集,利用自己的代码进行训练得出的结果
- 同样都是数据预处理,咋就差距这么大。。。85%和92.5%的区别