0.数据预处理
数据清洗:
数据清洗是指发现并纠正数据文件中可识别的错误的最后一道程序,包括检查数据一致性,处理无效值和缺失值等。
将训练集(单独清洗),测试集、correct_ans(合并后清洗)
washdata函数要做的几件事:
0.将测试数据与correct_ans合并(行拼接,以下简称合并集),并将合并后的列名‘label’改为‘income’,将训练集的‘income’列赋予布尔值
1.删除训练集与合并集中的‘?’行,并将它们的性别列赋予布尔值
2.单独取出income列(将原有数据income列删除)
3.特征缩放
0.0将测试数据与correct_ans合并(行拼接,以下简称合并集),并将合并后的列名‘label’改为‘income’,将训练集的‘income’列赋予布尔值
import csv
import numpy as np
import pandas as pd
def washData(datapath1, datapath2='nothing'):
df_x = pd.read_csv(datapath1) # 读取训练集/测试集
if datapath2 != 'nothing':
# 输入的文件包括测试集和correct_ans时,进行合并之后再清洗:washData('test.csv', 'correct_answer.csv')
df_correct_ans = pd.read_csv(datapath2) # 读取correct_ans.csv
df_x = pd.concat([df_x, df_correct_ans['label']],
axis=1) # 将训练集与correct_ans进行行连接,注意correct_ans的index不能用数字(df_x为字典形式)
# 测试集中为14列(没有income列)
df_x.rename(columns={'label': 'income'},
inplace=True) # 由于训练集中标签名为‘income’,correct_ans中标签为'label',因此需要转换:label→income
# df_x: age,workclass,fnlwgt ... hours_per_week,native_country,income [16281 rows x 15 columns](14+1)
else:
# 输入的文件只有训练集时,进行单独清洗:washData(‘train.csv')
df_x['income'] = (df_x['income'] == ' >50K') # 将训练集中income列赋予布尔值(>50K赋予1,否则为0)注意‘ >50k’中有空格
# 将训练集/测试集与corret——ans合并后的数据进行清洗
注意:‘ >50k’,’ male’中有空格,否则结果有误
0.1.删除训练集与合并集中的‘?’行,并将它们的性别列赋予布尔值
df_x = df_x.replace('?', np.nan) # 将‘?’换成nan
df_x = df_x.dropna() # 删除带有空值的行,只要有一个空值,就删除整行
# 这里要将测试集与correct_ans合并后的数据进行数据清洗,否则它们的数据将不再对应
df_x['sex'] = (df_x['sex'] == 'Male') # 将df_x中的性别赋予布尔值
# da_x是一个dataframe,有行标签列标签,而series只有行标签
0.2.单独取出income项并将原数据中的income删除
data_y = df_x[['income']].astype(
np.int64) # 这里df_[[]]双重括号保证data_y仍是dataframe类型,单括号则转为series类型,int64是numpy特有的数据类型,不同于python的int
del df_x['income']
# 将数据分为数字和非数字
object_columns = [col for col in df_x.columns if
df_x[col].dtypes == 'object'] # 列表解析式。提取出非数字的列名称:判断每一列的数据中是否全为object类型,是则提取列名
no_object_columns = [col for col in df_x.columns if df_x[col].dtypes == 'int64'] # 提取数字类型列名(有一个不为数字则不提取)
object_data = df_x[object_columns] # object_data包含df_x的所有object_columns列
no_object_data = df_x[no_object_columns]
object_data = pd.get_dummies(object_data) # 将非文字转换为虚拟变量
# 合并数据集
data_x = pd.concat([no_object_data, object_data], axis=1)
data_x = data_x.astype(np.int64)
补充:one-hot encoding(独热编码)与pd.get_dummies(data,prefix)
独热码,在英文文献中称做 one-hot code, 直观来说就是有多少个状态就有多少比特,而且只有一个比特为1,其他全为0的一种码制。
pd.get_dummies(data,prefix)是pandas实现独热编码的函数。
其中data是要转换的文件
prefix是表头前缀
具体参考官网说明
如一个dataframe:
A B C
a b 1
b a 2
a c 3
特征A有2种不同的值:[‘a’,‘b’]
特征B有3种不同的值[‘b’,‘a’,‘c’]
特征C有3种不同的值[1,2,3]#此处为数字
独热编码后
A中的
‘a’:[1 0]
‘b’:[0 1]
B中的
‘b’:[1 0 0]
‘a’:[0 1 0]
‘c’:[0 0 1]
由于C已经为数字,所以不再转化,直接输出
即利用线性无关的单位向量来表示不同的值(类似线性方程组中的基础解系)
由此原dataframe可转化为
10 100 1
01 010 2
10 001 3
代码实现
df=pd.DataFrame({'a':['5',5,2],'b':[7,4,1],'c':['a','v','s']})
print(df)
a b c
0 5 7 a
1 5 4 v
2 2 1 s
df_1=pd.get_dummies(df)
print(df_1)
b a_2 a_5 a_5 c_a c_s c_v
0 7 0 0 1 1 0 0
1 4 0 1 0 0 0 1
2 1 1 0 0 0 1 0
注意:除非某种特征值全为数字(如b列),不会进行转化,只要有一个值不是数字就要进行转化(a列中的 ‘5’)
查看训练集:
print(data_x)
age fnlwgt ... native_country_ Vietnam native_country_ Yugoslavia
0 39 77516 ... 0 0
1 50 83311 ... 0 0
2 38 215646 ... 0 0
... ... ... ... ... ...
32560 52 287927 ... 0 0
[32561 rows x 106 columns]
查看train.csv
text = open('b.csv', 'w+')
my_writer = csv.writer(text, delimiter=',', lineterminator='\n')
for i in data_x.T: # i为data_x的每一个列名,键的类型为string
my_writer.writerow(data_x.T[i])#这里为转置
text.close()
查看合并集
age fnlwgt ... native_country_ Vietnam native_country_ Yugoslavia
# # 0 25 226802 ... 0 0
# # 1 38 89814 ... 0 0
# # ... ... ... ... ... ...
# # [16281 rows x 105 columns]
0.3特征缩放
可以看到不同特征数据的取值范围差异很大,这样会导致梯度下降很慢(如对二维特征向量来说loss(w1,w2)的图像扁长,最优情况下图像应为近似圆形),因此要将特征进行归一化处理——特征缩放(feature scaling)。常用方法有:
1.均值归一化
2.方差归一化
3.标准归一化
其中标准归一化即正态分布标准化:
x=(x-μ)/σ
是较为常用的特征缩放方法
# feature scaling
data_x=(data_x-data_x.mean())/data_x.std()
小问题
训练集:[32561 rows x 106 columns]
合并集:[16281 rows x 105 columns]
打印后发现训练集与合并集列数并不相同,如下图:
native_country_holand-netherland多出来了,对其进行删除