机器学习入门(二)
文章目录
特征工程
1 特征工程概念
特征工程:就是对特征进行相关的处理
一般使用pandas来进行数据清洗和数据处理、使用sklearn来进行特征工程
特征工程是将任意数据(如文本或图像)转换为可用于机器学习的数字特征,比如:字典特征提取(特征离散化)、文本特征提取、图像特征提取。
特征工程步骤为:
-
特征提取, 如果不是像dataframe那样的数据,要进行特征提取,比如字典特征提取,文本特征提取
-
无量纲化(预处理)
- 归一化
- 标准化
-
降维
-
底方差过滤特征选择
-
主成分分析-PCA降维
-
2 特征工程API
-
实例化转换器对象,转换器类有很多,都是Transformer的子类, 常用的子类有:
DictVectorizer 字典特征提取 CountVectorizer 文本特征提取 TfidfVectorizer TF-IDF文本特征词的重要程度特征提取 MinMaxScaler 归一化 StandardScaler 标准化 VarianceThreshold 底方差过滤降维 PCA 主成分分析降维
-
转换器对象调用fit_transform()进行转换, 其中fit用于计算数据,transform进行最终转换
fit_transform()可以使用fit()和transform()代替
data_new = transfer.fit_transform(data) 可写成 transfer.fit(data) data_new = transfer.transform(data)
3 DictVectorizer 字典列表特征提取
稀疏矩阵
稀疏矩阵是指一个矩阵中大部分元素为零,只有少数元素是非零的矩阵。在数学和计算机科学中,当一个矩阵的非零元素数量远小于总的元素数量,且非零元素分布没有明显的规律时,这样的矩阵就被认为是稀疏矩阵。例如,在一个1000 x 1000的矩阵中,如果只有1000个非零元素,那么这个矩阵就是稀疏的。
由于稀疏矩阵中零元素非常多,存储和处理稀疏矩阵时,通常会采用特殊的存储格式,以节省内存空间并提高计算效率。
三元组表 (Coordinate List, COO):三元组表就是一种稀疏矩阵类型数据,存储非零元素的行索引、列索引和值:
(行,列) 数据
(0,0) 10
(0,1) 20
(2,0) 90
(2,20) 8
(8,0) 70
表示除了列出的有值, 其余全是0
非稀疏矩阵(稠密矩阵)
非稀疏矩阵,或称稠密矩阵,是指矩阵中非零元素的数量与总元素数量相比接近或相等,也就是说矩阵中的大部分元素都是非零的。在这种情况下,矩阵的存储通常采用标准的二维数组形式,因为非零元素密集分布,不需要特殊的压缩或优化存储策略。
- 存储:稀疏矩阵使用特定的存储格式来节省空间,而稠密矩阵使用常规的数组存储所有元素,无论其是否为零。
- 计算:稀疏矩阵在进行计算时可以利用零元素的特性跳过不必要的计算,从而提高效率。而稠密矩阵在计算时需要处理所有元素,包括零元素。
- 应用领域:稀疏矩阵常见于大规模数据分析、图形学、自然语言处理、机器学习等领域,而稠密矩阵在数学计算、线性代数等通用计算领域更为常见。
在实际应用中,选择使用稀疏矩阵还是稠密矩阵取决于具体的问题场景和数据特性。
(1) api
-
创建转换器对象:
sklearn.feature_extraction.DictVectorizer(sparse=True)
参数:
sparse=True返回类型为csr_matrix的稀疏矩阵
sparse=False表示返回的是数组,数组可以调用.toarray()方法将稀疏矩阵转换为数组
-
转换器对象:
转换器对象调用fit_transform(data)函数,参数data为一维字典数组或一维字典列表,返回转化后的矩阵或数组
转换器对象get_feature_names_out()方法获取特征名
案例
from sklearn.feature_extraction import DictVectorizer #引入字典列表特征提取的工具
# 字典列表向量化
data=[{'city':'北京','temperature':40},
{'city':'上海','temperature':34},
{'city':'深圳','temperature':29},
{'city':'深圳','temperature':31}]
# 创建一个字典列表特征提取工具
tool=DictVectorizer(sparse=True)#sparse=True表示返回的是稀疏矩阵(三元组表)
# 字典列表特征提取
data=tool.fit_transform(data)
print(data)#三元组表
print(data.toarray())#三元组表转数组
print(tool.feature_names_)
(0, 1) 1.0
(0, 3) 40.0
(1, 0) 1.0
(1, 3) 34.0
(2, 2) 1.0
(2, 3) 29.0
(3, 2) 1.0
(3, 3) 31.0
[[ 0. 1. 0. 40.]
[ 1. 0. 0. 34.]
[ 0. 0. 1. 29.]
[ 0. 0. 1. 31.]]
[‘city=上海’, ‘city=北京’, ‘city=深圳’, ‘temperature’]
4 CountVectorizer 文本特征提取
(1)API
sklearn.feature_extraction.text.CountVectorizer
构造函数关键字参数stop_words,值为list,表示词的黑名单(不提取的词)
fit_transform函数的返回值为稀疏矩阵
(2) 英文文本提取
from sklearn.feature_extraction.text import CountVectorizer
# 词频特征提取
data=["stu is well, stu is great", "You like stu"]
cv=CountVectorizer()#创建词频特征提取器
data=cv.fit_transform(data)#特征提取(转换)
print(data.toarray())#三元组表转数组
print(cv.get_feature_names_out())#查看每一个特征的特征名
[[1 2 0 2 1 0]
[0 0 1 1 0 1]]
[‘great’ ‘is’ ‘like’ ‘stu’ ‘well’ ‘you’]
(3) 中文文本提取
a.中文文本不像英文文本,中文文本文字之间没有空格,所以要先分词,一般使用jieba分词.
b.下载jieba组件, (不要使用conda)
c.jieba的基础
import jieba
data = "在如今的互联网世界,正能量正成为澎湃时代的大流量"
data = jieba.cut(data)
data = list(data)
print(data) #['在', '如今', '的', '互联网', '世界', ',', '正', '能量', '正', '成为', '澎湃', '时代', '的', '大', '流量']
data = " ".join(data)
print(data) #"在 如今 的 互联网 世界 , 正 能量 正 成为 澎湃 时代 的 大 流量"
使用jieba封装一个函数,功能是把汉语字符串中进行分词(会忽略长度小于等于1的词语,因为它们往往缺乏语义信息,不能很好地表达文本的特征)
import jieba
def cut(text):
return " ".join(list(jieba.cut(text)))
data = "在如今的互联网世界,正能量正成为澎湃时代的大流量"
data = cut(data)
print(data) #"在 如今 的 互联网 世界 , 正 能量 正 成为 澎湃 时代 的 大 流量"
完整终合示例
import jieba
from sklearn.feature_extraction.text import CountVectorizer
def cut(text):
return " ".join(list(jieba.cut(text)))
data = ["教育学会会长期间坚定支持民办教育事业!","热忱关心、扶持民办学校发展","事业做出重大贡献!"]
data_new = [cut(v) for v in data]
transfer = CountVectorizer(stop_words=['期间', '做出'])
data_final = transfer.fit_transform(data_new)
print(data_final.toarray())#把非稀疏矩阵转变为稀疏矩阵
print(transfer.get_feature_names_out())#
import pandas as pd
pd.DataFrame(data_final.toarray(), columns=transfer.get_feature_names_out())
5 TfidfVectorizer TF-IDF文本特征词的重要程度特征提取
(1) 算法
词频(Term Frequency, TF), 表示一个词在当前篇文章中的重要性
逆文档频率(Inverse Document Frequency, IDF), 反映了词在整个文档集合中的稀有程度
# 稀有度(词语的重要程度)特征提取
from sklearn.feature_extraction.text import TfidfVectorizer
import jieba
def fenci(str1):
return " ".join(list(jieba.cut(str1)))
data=["教育学会会长期间坚定支持民办教育事业事业!","热忱关心扶持民办学校发展","事业做出重大贡献!"]
data=[fenci(el) for el in data]
# print(data)
tool=TfidfVectorizer()#创建工具
tf_idf=tool.fit_transform(data)#转换
print(tf_idf.toarray())
print(tool.get_feature_names_out())
(2) API
sklearn.feature_extraction.text.TfidfVectorizer()
构造函数关键字参数stop_words,表示词特征黑名单
fit_transform函数的返回值为稀疏矩阵
6 无量纲化-预处理
无量纲,即没有单位的数据
无量纲化包括"归一化"和"标准化", 为什么要进行无量纲化呢?
这是一个男士的数据表:
编号id | 身高 h | 收入 s | 体重 w |
---|---|---|---|
1 | 1.75(米) | 15000(元) | 120(斤) |
2 | 1.5(米) | 16000(元) | 140(斤) |
3 | 1.6(米) | 20000(元) | 100(斤) |
假设算法中需要求它们之间的欧式距离, 这里以编号1和编号2为示例:
L = ( 1.75 − 1.5 ) 2 + ( 15000 − 16000 ) 2 + ( 120 − 140 ) 2 L = \sqrt{(1.75-1.5)^2+(15000-16000)^2+(120-140)^2} L=(1.75−1.5)2+(15000−16000)2+(120−140)2
从计算上来看, 发现身高对计算结果没有什么影响, 基本主要由收入来决定了,但是现实生活中,身高是比较重要的判断标准. 所以需要无量纲化.
1. MinMaxScaler 归一化
1.1 归一化公式
将数据缩放到指定区间(默认为 [0,1]):
[ x_{\text{scaled}} = \frac{x - x_{\text{min}}}{x_{\text{max}} - x_{\text{min}}} ]
若缩放到其他区间(如 [-1,1]),则使用公式:
[ x = x_{\text{scaled}} \times (\text{max} - \text{min}) + \text{min} ]
1.2 API
from sklearn.preprocessing import MinMaxScaler
transfer = MinMaxScaler(feature_range=(0, 1)) # 可自定义归一化后的值域
data_new = transfer.fit_transform(data) # 返回值为 ndarray
- 支持的数据类型:list、DataFrame、ndarray
- 不支持稀疏矩阵
1.3 示例
示例 1:原始数据为 list
data = [[12, 22, 4], [22, 23, 1], [11, 23, 9]]
transfer = MinMaxScaler(feature_range=(0, 1))
data_new = transfer.fit_transform(data)
print(data_new)
输出:
[[0.09090909 0. 0.375 ]
[1. 1. 0. ]
[0. 1. 1. ]]
示例 2:原始数据为 DataFrame
data = pd.DataFrame(data=[[12, 22, 4], [22, 23, 1], [11, 23, 9]], index=["一", "二", "三"], columns=["一列", "二列", "三列"])
transfer = MinMaxScaler(feature_range=(0, 1))
data_new = transfer.fit_transform(data)
print(data_new)
示例 3:原始数据为 ndarray
data = [{'city':'成都', 'age':30, 'temperature':200}, {'city':'重庆','age':33, 'temperature':60}, {'city':'北京', 'age':42, 'temperature':80}]
transfer = DictVectorizer(sparse=False)
data = transfer.fit_transform(data) # 转换为 ndarray
transfer = MinMaxScaler(feature_range=(0, 1))
data = transfer.fit_transform(data)
print(data)
1.4 缺点
- 最大值和最小值容易受到异常点影响,鲁棒性较差。
- 常用标准化替代。
2. normalize 归一化
2.1 API
from sklearn.preprocessing import normalize
normalize(data, norm='l2', axis=1)
- 参数:
norm
:归一化方式,可选 “l1”、“l2”、“max”axis
:归一化维度,axis=0
对列操作,axis=1
对行操作
2.2 归一化方式
- L1 归一化:绝对值相加作为分母,特征值作为分子。
- L2 归一化:平方相加作为分母,特征值作为分子。
- max 归一化:最大值作为分母,特征值作为分子。
3. StandardScaler 标准化
3.1 标准化公式
Z-score 标准化(零均值标准化):
[ z = \frac{x - \mu}{\sigma} ]
其中,( \mu ) 是特征的均值,( \sigma ) 是特征的标准差。
3.2 API
from sklearn.preprocessing import StandardScaler
transfer = StandardScaler()
data_new = transfer.fit_transform(data) # 返回值为 ndarray
- 支持的数据类型:list、DataFrame、ndarray
3.3 示例
import pandas as pd
import numpy as np
from sklearn.preprocessing import StandardScaler
# 获取数据
df_data = pd.read_csv("src/dating.txt")
print(type(df_data)) # <class 'pandas.core.frame.DataFrame'>
print(df_data.shape) # (1000, 4)
# 实例化转换器
transfer = StandardScaler()
# 归一化
new_data = transfer.fit_transform(df_data) # DataFrame 数据归一化
print("DataFrame 数据被归一化后:\n", new_data[0:5])
nd_data = df_data.values # DataFrame 转为 ndarray
new_data = transfer.fit_transform(nd_data) # ndarray 数据归一化
print("ndarray 数据被归一化后:\n", new_data[0:5])
nd_data = df_data.values.tolist() # DataFrame 转为 list
new_data = transfer.fit_transform(nd_data) # list 数据归一化
print("list 数据被归一化后:\n", new_data[0:5])
3.4 自己实现标准化
import numpy as np
from sklearn.preprocessing import StandardScaler
# 数据
data = np.array([[5], [20], [40], [80], [100]])
# API 实现
scaler = StandardScaler()
data_news = scaler.fit_transform(data)
print("API 实现:\n", data_news)
# 自己实现
mu = np.mean(data)
sum = 0
for i in data:
sum += ((i[0] - mu) ** 2)
d = np.sqrt(sum / len(data))
print("自己实现:\n", (data[3] - mu) / d)
以下是关于特征降维的重点内容归纳,以简洁的 Markdown 格式输出:
7 特征降维总结
特征降维的目的
- 减少数据集的维度,同时尽可能保留重要信息。
- 降低计算成本,去除噪声,避免过拟合。
特征降维的方式
- 特征选择
- 从原始特征集中挑选最相关的特征。
- 主成分分析(PCA)
- 通过数学计算将多个特征转化为少量新的特征。
1. 特征选择
(a) VarianceThreshold(低方差过滤)
- 原理:方差小的特征包含信息量少,可被移除。
- 步骤:
- 计算每个特征的方差。
- 设定方差阈值。
- 移除方差低于阈值的特征。
- API:
from sklearn.feature_selection import VarianceThreshold transfer = VarianceThreshold(threshold=1) data_new = transfer.fit_transform(data)
- 示例:
data = pd.DataFrame([[10,1],[11,3],[11,1],[11,5],[11,9],[11,3],[11,2],[11,6]]) transfer = VarianceThreshold(threshold=1) data_new = transfer.fit_transform(data) print(data_new)
(b) 相关系数(Pearson)
- 理论:
- 正相关:两个变量同向变化。
- 负相关:两个变量反向变化。
- 不相关:无明显线性关系。
- 计算公式:
[
\rho = \frac{\sum_{i=1}^{n}(x_i - \bar{x})(y_i - \bar{y})}{\sqrt{\sum_{i=1}^{n}(x_i - \bar{x})^2} \cdot \sqrt{\sum_{i=1}^{n}(y_i - \bar{y})^2}}
]- (|\rho| < 0.4):低度相关。
- (0.4 \leq |\rho| < 0.7):显著相关。
- (0.7 \leq |\rho| < 1):高度相关。
- API:
from scipy.stats import pearsonr r = pearsonr(x, y)
- 示例:
data = pd.read_csv("src/factor_returns.csv") r1 = pearsonr(data["pe_ratio"], data["pb_ratio"]) print(r1.statistic) # 相关系数 print(r1.pvalue) # 相关性评估
2. 主成分分析(PCA)
- 原理:通过线性变换将数据投影到方差最大的方向上,减少维度。
- 步骤:
- 计算数据的协方差矩阵。
- 求解协方差矩阵的特征值和特征向量。
- 选择方差最大的前 (k) 个特征向量作为主成分。
- 将数据投影到主成分上。
- API:
from sklearn.decomposition import PCA transfer = PCA(n_components=0.95) # 保留 95% 的信息 data_new = transfer.fit_transform(data)
- 示例:
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)
总结
- 特征选择适用于去除冗余特征。
- PCA 适用于将多个特征降维为少数几个主成分。
- 根据需求选择合适的方法,以达到降维的目的。