将分类数据和顺序数据转换为标志变量
分类数据和顺序数据是常见的数据类型,这些值主要集中在围绕数据实体的属性和描述的相关字段和变量中。
1.分类数据和顺序数据是什么
1-1 在数据建模过程中,很多算法无法直接处理非数值型的变量。例如KMeans算法用于基于距离的相似度计算,而字符串则无法直接计算距离.另外,即使算法本身支持,很多算法实现包也无法直接基于字符串做矩阵运算,例如Numpy以及基于Numpy的sklearn,虽然这些库允许直接使用和存储字符串型变量,但却无法发挥矩阵计算的优势。这些类型的数据可以分为两类:
1-1-1 分类数据:
指某些数据属性只能归于某一类别的非数值型数据,例如性别中的男、女就是分类数据.没有明显的高、低、大、小等包含等级、顺序、排序、好坏等逻辑的划分,只是用来区分两个或多个具有相同或相当价值的属性。例如:性别中的男和女,颜色中的红、黄和蓝,它们都是相同衡量维度上的不同属性分类而已。
1-1-2 顺序数据:
只能归于某一有序类别的非数值型数据,例如用户的价值度分为高、中、低,学历分为博士、研究生、学士。有明显的排序规律和逻辑层次的划分。例如:高价值的用户就是比低价值的用户价值高(业务定义该分类时已经赋予了这样的价值含义)。
2.运用标志方法处理分类和顺序数据
2-1 运用标志方法处理分类和顺序数据
分类数据和顺序数据要参与模型计算,通常都会转化为数值型数据。当然,某些算法是允许这些数据直接参与计算的,例如分类算法中的决策树、关联规则等。
将非数值型数据转换为数值型数据的最佳方法是:将所有分类或顺序变量的值域从一列多值的形态转换为多列只包含真值的形态,其中的真值可通过True、False或0、1的方式来表示。这种标志转换的方法有时候也称为真值转换。以用户性别变量为例,原有的
用户数据。
原有用户数据:
标志转换后的用户数据
为什么不能直接用数字来表示不同的分类和顺序数据,而一定要做标志转换?
这是因为在用数字直接表示分类和顺序变量的过程中,无法准确还原不同类别信息之间的差异和相互关联性。例如:
·针对分类数据:性别变量的属性值是男和女,无论用什么值来表示都无法表达出两个值的价值相等且带有区分的含义。如果用1和2区分,那么1和2本身已经带有距离为1的差异,但实际上二者是不具有这种差异性的,其他任意数字都是如此;如果用相同的数字来表示,则无法达到区分的目的。
针对顺序数据:历变量的属性值是博士、研究生和学士,可以用3-2-1来表示顺序和排列关系,那么如何表示三个值之间的差异是3-2-1而不是30-20-10或者1000-100-2呢?因此,任何一个有序数字的排序也都无法准确表达出顺序数据的差异性。
3.代码实操:Python标志转换
将模拟有两列数据分别出现分类数据和顺序数据的情况,并通过自定义代码以及sklearn代码分别进行标志转换。
import pandas as pd # 导入pandas库
from sklearn.preprocessing import OneHotEncoder # 导入OneHotEncoder库
#生成测试数据
df = pd.DataFrame({'id': [3566123, 6541277, 8998121],
'sex': ['male', 'Female', 'Female'],
'level': ['high', 'low', 'middle']})
print(df) # 打印输出原始数据框
---------------------------------------------------------
结果:
id sex level
0 3566123 male high
1 6541277 Female low
2 8998121 Female middle
# 自定义转换主过程
df_new = df.copy() # 复制一份新的数据框用来存储转换结果
for col_num, col_name in enumerate(df): # 循环读出每个列的索引值和列名
col_data = df[col_name] #获取每列数据
col_dtype = col_data.dtype # 获得每列dtype类型
if col_dtype == 'object': #如果dtype类型是object(非数值型),执行条件
df_new = df_new.drop(col_name, 1) # 删除df数据框中要进行标志转换的列
value_sets = col_data.unique() # 获取分类和顺序变量的唯一值域
for value_unique in value_sets: # 读取分类和顺序变量中的每个值
col_name_new = col_name + '_' + value_unique # 创建新的列名,使用“原标题+值”的方式命名
col_tmp = df.iloc[:, col_num] # 获取原始数据列
new_col = (col_tmp == value_unique) # 将原始数据列与每个值进行比较,相同为True,否则为False
df_new[col_name_new] = new_col # 为最终结果集增加新列值
print(df_new) # 打印输出转换后的数据框
---------------------------------------------------------
结果:
id sex_male sex_Female level_high level_low level_middle
0 3566123 True False True False False
1 6541277 False True False True False
2 8998121 False True False False True
# 使用sklearn进行标志转换
df2 = pd.DataFrame({'id': [3566123, 6541277, 8998121],
'sex': [1, 2, 2],
'level': [3, 1, 2]})
id_data = df2.values[:, :1] #获取id列
transform_data = df2.values[:, 1:] #指定要转换的列
enc = OneHotEncoder() #建立模型对象
df2_new = enc.fit_transform(transform_data).toarray() #标志转换
df2_all = pd.concat((pd.DataFrame(id_data),pd.DataFrame(df2_new)), axis=1) #合为数据框
print(df2_all) # 打印输出转换后的数据框
---------------------------------------------------------
结果:
0 0 1 2 3 4
0 3566123 1.0 0.0 0.0 0.0 1.0
1 6541277 0.0 1.0 1.0 0.0 0.0
2 8998121 0.0 1.0 0.0 1.0 0.0
完整代码,可在pycharm或其他工具上运行
import pandas as pd # 导入pandas库
from sklearn.preprocessing import OneHotEncoder # 导入OneHotEncoder库
#生成测试数据
df = pd.DataFrame({'id': [3566123, 6541277, 8998121],
'sex': ['male', 'Female', 'Female'],
'level': ['high', 'low', 'middle']})
print(df) # 打印输出原始数据框
# 自定义转换主过程
df_new = df.copy() # 复制一份新的数据框用来存储转换结果
for col_num, col_name in enumerate(df): # 循环读出每个列的索引值和列名
col_data = df[col_name] #获取每列数据
col_dtype = col_data.dtype # 获得每列dtype类型
if col_dtype == 'object': #如果dtype类型是object(非数值型),执行条件
df_new = df_new.drop(col_name, 1) # 删除df数据框中要进行标志转换的列
value_sets = col_data.unique() # 获取分类和顺序变量的唯一值域
for value_unique in value_sets: # 读取分类和顺序变量中的每个值
col_name_new = col_name + '_' + value_unique # 创建新的列名,使用“原标题+值”的方式命名
col_tmp = df.iloc[:, col_num] # 获取原始数据列
new_col = (col_tmp == value_unique) # 将原始数据列与每个值进行比较,相同为True,否则为False
df_new[col_name_new] = new_col # 为最终结果集增加新列值
print(df_new) # 打印输出转换后的数据框
# 使用sklearn进行标志转换
df2 = pd.DataFrame({'id': [3566123, 6541277, 8998121],
'sex': [1, 2, 2],
'level': [3, 1, 2]})
id_data = df2.values[:, :1] #获取id列
transform_data = df2.values[:, 1:] #指定要转换的列
enc = OneHotEncoder() #建立模型对象
df2_new = enc.fit_transform(transform_data).toarray() #标志转换
df2_all = pd.concat((pd.DataFrame(id_data),pd.DataFrame(df2_new)), axis=1) #合为数据框
print(df2_all) # 打印输出转换后的数据框