特征工程

写在前面

以下算法实例均取自sklearn库,使用python编写

可使用以下指令快速安装sklearn

$ pip install sklearn

下文有时会使用./SelfTools/Tool.py中的内容

Tool.py

def separate(self=None):
print("---------------------------------------------------------------------------------------------------" * 2)
return None

常用算法

字典特征值抽取

从原始数据中提取有意义的特征,然后创建一个字典来存储提取的特征,再将数据转换为字典形式,以便可以方便地进行分析或输入到机器学习模型中(向量化?),最后从提取的特征中选择最有用的特征,以提高模型的性能。有时还需要对特征进行标准化处理,以确保它们在相同的尺度上,避免大数”吞噬“小数。

demo

from sklearn.feature_extraction import DictVectorizer
from SelfTools import Tool


def dict_demo(flag=True):
"""
字典特征值抽取,抽取为one-hot编码
:return:
"""
data = [{'city': 'Beijing', 'temperature': 100}, {'city': 'Shanghai', 'temperature': 60},
{'city': 'Shenzhen', 'temperature': 30}]
# 实例化一个转换器类
transfer = DictVectorizer(sparse=flag)
# sparse默认为True,返回sparse矩阵的形式,想看到原来二维数组的形式需做还原: sparse=False
# sparse: 稀疏矩阵,第一列的元组给出了所有非零值在二维数组中的位置,其后为对应的非零值
# 使用稀疏矩阵的原因:数据规模足够大后,0很多,稀疏矩阵可以显著提高运行效率且节省内存

# 调用转换器的fit_transform方法
data_new = transfer.fit_transform(data)
print("data_new: \n", data_new)
print("feature_names: \n", transfer.get_feature_names())

return None


if __name__ == "__main__":
dict_demo()
Tool.separate()
dict_demo(False)

特征降维

目的是去除冗余数据,这里的维数应当指的是特征的种类,有时我们并不需要一个数据的全部维度,比如西瓜瓜皮颜色,对于大部分数据都具有相同的值,属于冗余特征。

一般采用低方差特征过滤法,其原理为:某个特征的方差小,意味着大部分样本该特征的值比较相近,为冗余数据,无需考虑。

demo

from sklearn.feature_selection import VarianceThreshold
import pandas as pd
from SelfTools import Tool
"""
VarianceThreshold(threshold=0.0)
删除所有低方差特征
Variance.fit_transform(X)
X: numpy array格式的数据 [n_samples, n_features]
return: 训练集差异小于等于threshold的特征被删除。默认值是保存所有非零方差特征(即threshold = 0.0), 即删除所有具有相同值的特征
"""


"""
卡方检验(Pearsonr检验):高中知识,反应相关性 r, r -> [-1, 1]; |r|越接近 1,相关性越强,大于0正相关
"""
from scipy.stats import pearsonr
"""
从scipy中引进pearsonr卡方检验
pearsonr(x, y)
x: (N,) array_like
y: (N,) array_like
return: Pearson's correlation coefficient(statistic), p-value(pvalue)
p-value衡量 r 的有效性,越小越可靠
"""


def variance_demo(std=0.0):
# 获取数据
data = pd.read_csv("factor_returns.csv")
print("data: \n", data)
Tool.separate()
data = data.iloc[:, 2:]
print("data: \n", data)
Tool.separate()
# 实例化转换器类
transfer = VarianceThreshold(std)
# 调用fit_transform()方法
data_new = transfer.fit_transform(data)
print("data_new: \n", data_new)
print("shape of data_new: \n", data_new.shape)
Tool.separate()

# 计算某两个变量之间的相关系数
r = pearsonr(data["Open"], data["Close"])
print("相关系数: \n", r)
Tool.separate()


return None


if __name__ == "__main__":
variance_demo()
variance_demo(13)
variance_demo(14)

特征值归一化

为防止一些很大的特征值在进行机器学习时对整个结果起支配作用,从而使计算机无法学习到其他特征值较小的特征。

对特征值 x 作归一化:
step1: X' = (x - min) / (max - min)
step2: X'' = x' * (mx - mi) + mi
注:mx, mi分别为指定区间值(标准化后值的范围,例如归一化一般采用(0, 1)),默认mx = 1, mi = 0 feature_range = (mi, mx)
X''为归一化后的 x

*缺点:*依赖于最大值与最小值,一旦最大值或最小值中出现异常值,归一化就会失效,只适合传统精确小数据场景

demo

from sklearn.preprocessing import MinMaxScaler
import pandas as pd
from SelfTools import Tool
"""
MinMaxScaler(feature_range=(0,1)...)
MinMaxScaler.fit_transform(X)
X: numpy array格式的数据[n_samples, n_features] (二维数组,行数为样本数,列数为特征的个数)
return: 转换后的形状相同的array
"""


def minmax_scaler():
"""
归一化
:return:
"""
# 获取数据
data = pd.read_csv("dating.txt")
print("data: \n", data)
Tool.separate()
# 只处理数据前三列
data = data.iloc[:, 0:3]
print("data: \n", data)
Tool.separate()
# 实例化转换器类
transfer = MinMaxScaler()
# 调用fit_transform()方法
data_new = transfer.fit_transform(data)
print("data_new: \n", data_new)
Tool.separate()
return None


if __name__ == "__main__":
minmax_scaler()

特征值标准化

解决归一化的不足,通过对原始数据进行变换,把数据变换到均值为 0,标准差为 1 的范围内

对 x 标准化: X' = (x - mean) / std
mean: 均值
std: 标准差

关于异常值,标准化对于异常值的敏感度低于归一化;对于大量的大数据而言,少量异常点对于均值和标准差的影响都不会很大。

demo

from sklearn.preprocessing import StandardScaler
import pandas as pd
from SelfTools import Tool
"""
StandardScaler()
处理之后,对每列来说,所有数据都聚集在均值 0 附近,标准差为 1
StandardScaler.fit_transform(X)
X: numpy array格式的数据 [n_samples, n_features] (同样为二维数组,行数为样本数,列数为特征的个数)
return: 转换后形状相同的array
"""


def std_scaler():
"""
标准化
:return:
"""
data = pd.read_csv("dating.txt")
data = data.iloc[:, :3]
print("dara: \n", data)
Tool.separate()
transfer = StandardScaler()
data_new = transfer.fit_transform(data)
print("data_new: \n", data_new)
return None


if __name__ == "__main__":
std_scaler()

主成分分析 PCA

又称PCA降维,是一种常用的数据降维技术,它通过将原始数据集中的特征线性组合,提取一组新的特征(称为主成分),这些新特征具有最大的方差,并且彼此正交。这样,我们就可以用尽可能少的主成分来保留原始数据集的大部分信息。

往往需要数据标准化,计算协方差矩阵,计算特征值和特征向量,选择主成分,降维…

万幸,python什么都有

demo

from sklearn.decomposition import PCA
from SelfTools import Tool
"""
PCA(n_components=None)
将数据分解为较低维数空间
n_components:
小数:表示保留百分之多少的信息
整数:减少到多少特征
PCA.fit_transform(X)
X: numpy array格式的数据 [n_samples, n_features]
return: 转换后指定维度的array
"""


def pca_demo():
data = [[2, 8, 4, 5], [6, 3, 0, 8], [5, 4, 9, 1]]
transfer = PCA(n_components=0.95)
data_new = transfer.fit_transform(data)
print("data_new:\n", data_new)
Tool.separate()
return None


if __name__ == "__main__":
pca_demo()

下面介绍一些和文本内容相关的数据分析算法

文本特征值提取

单词作为特征进行提取,sklearn提供了一个**CountVectorizer**统计特征值出现的个数

demo

可能需要的指令,(如果import jieba报错

$ pip install jieba
from sklearn.feature_extraction.text import CountVectorizer
# jieba用于分词
import jieba
from SelfTools import Tool


def text_demo():
"""
文本特征抽取:CountVectorizer
:return:
"""
text = ["life is short, i like like python",
"life is too long, i dislike python"]
# 实例化转换器类
transfer = CountVectorizer()
# 调用fit_transform方法
txt_new = transfer.fit_transform(text)
print("features_names: \n", transfer.get_feature_names_out())
print("txt_new: \n", txt_new)
Tool.separate()
# 输出·txt_new的类型
print("type of txt_new: \n", type(txt_new))
# 发现fit_transform方法默认返回仍是sparse矩阵(对象)
# 该对象自带一个toarray()方法,可返回原始二维数组(类似于之前的将sparse设为False,但是文本特征值抽取没有sparse参数)
Tool.separate()
print("array of txt_new: \n", txt_new.toarray())

return None


def chn_txt_demo():
"""
中文文本特征值抽取
:return:
"""
text = ["这些新特征具有最大的方差,并且彼此正交。这样,我们就可以用尽可能少的主成分来保留原始数据集的大部分信息。", "牛魔大酬宾"]
# 中文不似英文,天生不带空格,所以抽取时会出现短语(按标点划分)
transfer = CountVectorizer()
txt_new = transfer.fit_transform(text)

print("features_names: \n", transfer.get_feature_names_out())
print("array of txt_new: \n", txt_new.toarray())

return None


def cut_words(text):
"""
对字符串进行中文分词
:param: text
:return: " ".join(list(jieba.cut(text)))
"""
tokenizer = jieba.cut(text)
# print(tokenizer)
# tokenizer: <generator object Tokenizer.cut
l_token = list(tokenizer)
# print(l_token)
text = " ".join(l_token)
return text


def chn_txt_sep():
"""
中文特征值抽取,自动分词
:return:
"""
text = ["我会在本学期认真自学课程内容,并按时上交课程作业",
"参加每一次课程考试。",
"如因未随堂上课迟交或错过提交作业、参加测试等影响本课程成绩,本人自行承担一切后果。"]
txt_new = []
for i in range(0, len(text)):
txt_new.append(cut_words(text[i]))
# print(txt_new)
transfer = CountVectorizer(stop_words=["本人", "我会"])
# stop_words为忽略的单词(往往没有实质作用)
txt_new = transfer.fit_transform(txt_new)

print("features_names: \n", transfer.get_feature_names_out())
print("array of txt_new: \n", txt_new.toarray())

return None


if __name__ == "__main__":
# text_demo()
# chn_txt_demo()

# cut_words("我爱北京天安门") # ['我', '爱', '北京', '天安门']
# print(cut_words("我爱北京天安门")) # 我 爱 北京 天安门

chn_txt_sep()

TF-IDF

tf: text frequency 词频 = 某单词出现次数 / 总单词数目
idf: inverse document frequency 逆向文档频率 = lg (总文档数目 / 包含某单词的文档数目)
tf-idf = tf * idf
tf-idf的值越高,代表该单词的重要性越高,作为关键词区分不同类型文章的价值越高
关键词:在某一个类别的文章中出现次数很多,而在其它类别的文章中出现次数较少

demo

# tf-idf十分重要,是分类机器算法进行文章分类中前期数据处理方式
from sklearn.feature_extraction.text import TfidfVectorizer
import jieba


def cut_words(text):
"""
对字符串进行中文分词
:param: text
:return: " ".join(list(jieba.cut(text)))
"""
tokenizer = jieba.cut(text)
# print(tokenizer)
# tokenizer: <generator object Tokenizer.cut
l_token = list(tokenizer)
# print(l_token)
text = " ".join(l_token)
return text


def tfidf_demo():
"""
用tf-idf方法进行文本特征抽取
:return:
"""
text = ["我会在本学期认真自学课程内容,并按时上交课程作业",
"参加每一次课程考试。",
"如因未随堂上课迟交或错过提交作业、参加测试等影响本课程成绩,本人自行承担一切后果。"]
txt_new = []
for i in range(0, len(text)):
txt_new.append(cut_words(text[i]))
transfer = TfidfVectorizer(stop_words=["本人", "我会"])
txt_new = transfer.fit_transform(txt_new)

print("feature_names: \n", transfer.get_feature_names())
print("txt_new: \n", txt_new.toarray())

return None


if __name__ == "__main__":
tfidf_demo()

综合运用实践

一个简单的数据集训练过程

from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split


def separate():
print("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<分隔符>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>")


def datasets_demo():
# 获取数据集
iris = load_iris()
# 查看数据集
print(iris)
separate()
# 查看键DESCR(数据集描述)的值
print(iris["DESCR"])
separate()
# 查看特征值名字
print(iris.feature_names)
separate()
# 查看特征值
print("特征值: \n", iris.data, "\n特征值维数: ", iris.data.shape)
separate()

# 数据集划分
x_train, x_test, y_train, y_test = train_test_split(iris.data, iris.target, test_size=0.2, random_state=22)
# 第一个参数特征值,第二个参数目标值,后面参数可选,为划分大小,默认测试集大小0.25; random_state随机数种子e
print("训练集的特征值: \n", x_train, "\n大小: ", x_train.shape)
separate()
return None


if __name__ == "__main__":
datasets_demo()

(•‿•)