1200字范文,内容丰富有趣,写作的好帮手!
1200字范文 > python非数值型数据_Python机器学习实战:如何处理非数值特征

python非数值型数据_Python机器学习实战:如何处理非数值特征

时间:2024-04-24 11:48:20

相关推荐

python非数值型数据_Python机器学习实战:如何处理非数值特征

机器学习实战:这里没有艰深晦涩的数学理论,我们将用简单的案例和大量的示例代码,向大家介绍机器学习的核心概念。我们的目标是教会大家用Python构建机器学习模型,解决现实世界的难题。

本文来自《数据黑客》,登录官网可精彩资讯和文章。数据黑客 - 专注金融大数据的内容聚合和数据聚合平台​

机器学习模型要求输入为数值变量,特征必须是大小为(n_samples, n_features)的数值矩阵,目标是(n_samples, 1)的数值向量。但现实世界的数据集有可能包含非数值数据,例如分类变量,文本数据和图像。

这时候需要进行数据预处理(data preprocessing),即采用一些技巧将非数值变量转换为数值变量。

1. 分类变量

分类变量通常分为两种:有序和无序。有序:类别可以相互比较,有大小之分,可以直接转化为数值变量。假设代表收入的变量'income'有3个类别,'low','medium','high',分别代表低收入,中等收入,高收入,类别是可以直接比较的,并且可以排序,'low' < 'medium' < 'high'。

无序:类别不可以比较,需要引入虚拟变量(dummy variable),常用编码技术是独热编码(one-hot encoding)。例如代表性别的变量'gender'有两个类别,'male'和'female',但'male' < 'female'的关系并不成立。

将分类变量转化为数值变量有两种常用方法:标签编码和独热编码。

1.1 标签编码

标签编码(label encoding): 将分类变量的类别编码为数字。

用sklearn.preprocessing.LabelEncoder实现,将包含k个类别的分类变量编码为$0,1,2,...(k-1)$

标签编码一般不用于特征,而是用于目标变量。

假设一个代表性别的特征'gender',包含两个类别:'male','female'。标签编码将类别编码为整数,0代表男性,1代表女性。但这不符合模型背后的假设,因为机器学习模型认为数据有算数含义,例如0 < 1,这意味着男性 < 女性,但这种关系不成立。一般会使用独热编码处理分类特征,标签编码仅用于分类目标。

接下来说明如何使用标签编码,假设目标变量代表股票价格趋势,有3种可能的类别,'up','down','range'.

from sklearn.preprocessing import LabelEncoder

# 目标变量

y = ["up", "up", "down", "range", "up", "down", "range", "range", "down"]

# 创建LabelEncoder对象

le = LabelEncoder()

# 拟合数据

le.fit(y)

# 查看包含哪些类别

print("classes: ", le.classes_)

# 编码为数字

print("encoded labels: ", le.transform(y))

# 调用inverse_transform实现反向操作

print("inverse encoding: ", le.inverse_transform([0, 1, 2]))

classes: ['down' 'range' 'up']

encoded labels: [2 2 0 1 2 0 1 1 0]

inverse encoding: ['down' 'range' 'up']

1.2 独热编码

独热编码(one hot encoding): 将包含m个类别的分类变量转化为$n*m$的二元矩阵,n是观测值数量,m是类别数量。

假设分类变量'car_type',表示汽车类型,包含类别(BMW, Tesla, Audi),独热编码将产生下图的结果,每一个类别都成为一个新的变量/特征,1表示观测值包含该类别,0表示不包含。

sklearn提供OneHotEncoder类实现独热编码。

import numpy as np

import pandas as pd

from sklearn.preprocessing import OneHotEncoder

# 分类特征

car_types = np.array(["BMW", "Tesla", "Audi", "BMW", "Audi"])

# 创建编码器

oe = OneHotEncoder()

# OneHotEncoder要求输入为二维数组,用reshape重排结构

oe.fit(car_types.reshape(-1, 1))

# 查看类别

print("classes: ", oe.categories_)

# 调用transform获得编码结果

# transform默认返回稀疏矩阵,当分类变量包含很多类别时非常有用,进一步调用toarray可获得熟悉的numpy二维数组

# 创建OneHotEncoder实例时,如果设置sparse=False,调用transform会得到二维数组

encoded_labels = oe.transform(car_types.reshape(-1, 1)).toarray()

print(encoded_labels)

# 用数据框展现最终的结果,便于理解

encoded_labels_df = pd.DataFrame(encoded_labels, columns=oe.categories_)

print(encoded_labels_df)

classes: [array(['Audi', 'BMW', 'Tesla'], dtype='

[[0. 1. 0.]

[0. 0. 1.]

[1. 0. 0.]

[0. 1. 0.]

[1. 0. 0.]]

Audi BMW Tesla

0 0.0 1.0 0.0

1 0.0 0.0 1.0

2 1.0 0.0 0.0

3 0.0 1.0 0.0

4 1.0 0.0 0.0

调用pd.get_dummies实现独热编码,这比sklearn的接口更方便,因为它允许我们直接操作数据框。

pd.get_dummies默认将数据类型为'object'的变量视为分类变量,也可以提供要编码的变量名称。

import pandas as pd

car_types = pd.DataFrame({"car_type": ["BMW", "Tesla", "Audi", "BMW", "Audi"]})

print(car_types)

car_types_encoded = pd.get_dummies(car_types)

print(car_types_encoded)

car_type

0 BMW

1 Tesla

2 Audi

3 BMW

4 Audi

car_type_Audi car_type_BMW car_type_Tesla

0 0 1 0

1 0 0 1

2 1 0 0

3 0 1 0

4 1 0 0

1.3 虚拟变量陷阱

独热编码会引入K个新特征,分别表示分类变量的K个类别。但如果我们使用回归模型,则不能这么做,因为这会导致多重共线性。

首先我们要理解两个新的概念:虚拟变量陷阱和多重共线性。

虚拟变量陷阱:在回归模型中,虚拟变量(dummy variable)用于表示分类变量的类别,通常用1和0表示。例如性别变量'gender'有两个类别,分别是男性和女性,那么可以引入一个虚拟变量D,如果观测值是男性记为1,否则记为0。如果分类变量有$k$个类别,引入$(k-1)$个虚拟变量,有一个类别作为基准组/参照组。如果引入$k$个虚拟变量,会导致多重共线性。

多重共线性:如果1个自变量可以表示为其它自变量的线性组合,就是完全多重共线性,无法估计回归方程的斜率系数。简单理解就是预测变量(特征)之间高度相关。

假设变量$X$有3个类别,引入3个虚拟变量$X_a, X_b, X_c$,每个变量的取值都是1或0,则必然满足以下关系:$X_a + X_b + X_c = 1$,那么任何一个变量都可以表示为其余两个虚拟变量的线性组合,结果就是完全多重共线性。

使用OneHotEncoder创建(k-1)个虚拟变量。

car_types = np.array(["BMW", "Tesla", "Audi", "BMW", "Audi"])

# 将第一个类别作为参照组

oe = OneHotEncoder(drop="first")

# 拟合数据

oe.fit(car_types.reshape(-1, 1))

# 编码

encoded_labels = oe.transform(car_types.reshape(-1, 1)).toarray()

# 查看剔除的特征

# oe.categories_保存了所有的类别,包括剔除的类别

# oe.drop_idx_保存了categories_中被剔除类别的索引

features_drop = oe.categories_[0][oe.drop_idx_.astype(int)]

features_retain = np.delete(oe.categories_[0], oe.drop_idx_.astype(int))

print("features drop: ", features_drop)

print("features retain: ", features_retain)

# 查看结果

encoded_labels_df = pd.DataFrame(encoded_labels, columns=features_retain)

encoded_labels_df["class"] = car_types

print(encoded_labels_df)

features drop: ['Audi']

features retain: ['BMW' 'Tesla']

BMW Tesla class

0 1.0 0.0BMW

1 0.0 1.0 Tesla

2 0.0 0.0 Audi

3 1.0 0.0 BMW

4 0.0 0.0 Audi

使用pd.get_dummies创建(k-1)个虚拟变量。

car_types = pd.DataFrame({"car_type": ["BMW", "Tesla", "Audi", "BMW", "Audi"]})

# drop_first=True: 将第一个类别作为参照组

car_types_encode = pd.get_dummies(car_types, drop_first=True)

# 查看结果

car_types_join = pd.concat([car_types, car_types_encode], axis=1)

print(car_types_join)

car_type car_type_BMW car_type_Tesla

0 BMW 1 0

1 Tesla 0 1

2 Audi 0 0

3 BMW 1 0

4 Audi 0 0

2. 文本数据

有时候模型的输入是文本数据,例如新闻,社交媒体发言等,需要把文本转化为数值矩阵。

常用处理方法有两种:单词统计(word counts): 统计每个单词出现的次数。

TF-IDF(Term Frequency-Inverse Document Frequency): 统计单词出现的“频率”。

单词统计法的缺陷是当单词出现次数较多,模型会赋予更多的权重,Tfidf可以规避这个缺陷。

2.1 word counts

行代表观测值,列(特征)是所有文档中出现过的单词,特征值表示单词在当前文档中出现的次数。

from sklearn.feature_extraction.text import CountVectorizer

import pandas as pd

# 准备3个观测值,文本变量

sample = ['problem of evil',

'evil queen',

'horizon problem']

# 创建Vectorizer对象,调用fit_transform方法,返回稀疏矩阵(sparse matrix)

vec = CountVectorizer()

X = vec.fit_transform(sample)

# 将结果转化为数据框,以更直观的方式显示结果

df = pd.DataFrame(X.toarray(), columns=vec.get_feature_names())

df["text"] = sample

df

2.2 Tfidf

行代表观测值,列(特征)是所有文档出现过的单词,分数是文档中词的频率乘以所有文档的逆频率,分数越高显示单词在当前文档中使用越多,而在其它文档中使用得越少。

from sklearn.feature_extraction.text import TfidfVectorizer

vec = TfidfVectorizer()

X = vec.fit_transform(sample)

df = pd.DataFrame(X.toarray(), columns=vec.get_feature_names())

df["text"] = sample

df

数据黑客 - 专注金融大数据的内容聚合和数据聚合平台​

我们聚合全网最优秀的资讯和教程:金融大数据

机器学习/深度学习

量化交易

数据工程

编程语言,Python,R,Julia,Scala,SQL

我们提供开源数据接口:下载国内和国外海量金融数据

API接口,将数据整合到您的平台

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。