2024.02前Python学习小结
1、Python数据分析:对饮食与健康数据的分析与可视化
2、Python机器学习:Scikit-learn简单使用
3、Python深度学习:Tensorflow简单使用
文章目录
前言
本文旨在对以往学习的相关内容进行总结回顾,通过Scikit-learn对饮食与健康数据进行处理,因此具备以下特点:
- 练习目的,类似问题尽量使用多种方法
- 以锻炼方法为目的,不求用法非常贴切
- 代码部分尽量详细说明
一、相关说明
1.Scikit-learn特点
选择Scikit-learn作为机器学习主要内容是因为:
- 相对简单,不需要过多设置
- 能很好和seaborn配合进行可视化
- 包含数据处理方法,归一化、标准化两行就行
- 内容多,聚类、分类、回归,监督、无监督都有
- 评估方法多,交叉验证尤其全能充分利用有限的数据,适合练习
2.本文任务
本文期望将几类方式都涉及,必然的每部分不会太详细、贴切。
- 分类:LogisticRegressionCV,作生活习惯方面分类。
- 降维:主成分分析,减少属性
- 线性回归:LinearRegression,设置假索引,对BMI指标进行拟合。
- 聚类/K-Means:Agglomerative Clustering
- 其他:归一化、标准化、评估
二、数据说明及预处理
1.引入库
代码如下:
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.linear_model import LogisticRegressionCV ## 分类、回归算法
from sklearn.model_selection import train_test_split ## 数据及划分、检验
from sklearn.neighbors import KNeighborsClassifier ## knn算法,一个直观的分类算法
from sklearn.preprocessing import MinMaxScaler, StandardScaler ## 归一化
import warnings ## Filter warnings
warnings.filterwarnings('ignore')
2.读入数据及清洗
先对数据进行去重和缺失值处理,同前文
#数据导入及处理
df_1 = pd.read_csv(r'D:\Pytharm\Practice\sjfenxilast\sti_sc.csv')
df_1.drop_duplicates(keep='first',inplace=True) #删除重复
df_1['Age'] = df_1['Age'].apply(int) #原数据年龄有太多小数
df = df_1[df_1['Age'] < 31] #原数据基本是30以下的,只选取小于30部分
为了使得预测、分类更准确,往往需要对取值范围过大数据标准化、对文本类数据转化为数字类。
以下部分进行几类处理:
- 将文本类指标转化为数字型
- 将数据间关系进行可视化展示
- 对列名太复杂的进行修改方便调用
#只保留饮食习惯属性和基础信息属性
df_diet = []
df_diet=df.loc[:,['Age','Weight','Height','FAVC','FCVC','NCP','CH2O','NObeyesdad']]
#将文本类型属性转换为数字类型
df_diet.loc[df_diet['FAVC'] == 'yes', 'FAVC_'] = 1
df_diet.loc[df_diet['FAVC'] == 'no', 'FAVC_'] = 0
df_diet.drop(['FAVC'], axis="columns", inplace=True)#删除列
#也可以使用map,replace,对最后的评价属性换不换都行,replace对未定义值会保留,map会换
dict = {
'Insufficient_Weight' : 0, 'Normal_Weight' : 1, 'Overweight_Level_I' : 2,
'Overweight_Level_II':3,'Obesity_Type_I' : 4,'Obesity_Type_II' : 5,'Obesity_Type_III':6}
#df_diet = df_diet.replace({"NObeyesdad": dict})#保留原值
df_diet["NObeyesdad"] = df_diet["NObeyesdad"].map(dict)#有空代表没换完
#修改部分列索引,方便调用,此次BMI评价直接使用给定值
df_diet.rename(columns={
'NObeyesdad': 'BMIex', 'FAVC_': 'FAVC'}, inplace=True)
#将BMIex放到最后,检测相关数据
df_diet=df_diet[['Age','Weight','Height','FAVC','FCVC','NCP','CH2O','BMIex']]
print("归一化前")
print(df_diet.head())
#print(df_diet.info()) ## 检查数据
## 将数据之间的关系进行可视化
sns.pairplot(df_diet, hue='BMIex')
plt.savefig('ten数据相关性',bbox_inches='tight')
plt.show()
其中,数据更换有多种方法。较好的是map,对给了替换规则的进行替换,其他为NAN。再通过info查看数据类型可以看到是否替换完全。
对各属性进行直观展示,可以明显看到有几组数据间相关性不大。
3.归一化及标准化
原数据体重(Weight)变化较大,容易影响分类效果。最好进行标准化或归一化,二者区别如下:
- 归一化:数据分布不明显偏离正态分布
- 标准化:数据分布明显偏离正态分布,或者有可能受到异常值的影响
本文数据都行,二者都进行示例
## 数据处理,归一化、标准化
min_max_scaler = MinMaxScaler()
df_diet_py = min_max_scaler.fit_transform(df_diet) ## 输出Numpy格式需要转化为Dataframe
df_min = pd.DataFrame(df_diet_py, columns=df_diet.columns)
print("归一化后")
print(df_min.head())
## 标准化
#standard_scaler = StandardScaler()
#standardized_data = standard_scaler.fit_transform(data)
# vvv体重单独标准化后,感觉自己的方法不太好,这是能用vvvvvvvvv
"""
## 对单列数据示例
# 转换为二维数组(单列数据需要变为二维数组形式)
Warray1 = df_diet['Weight'].values.flatten() ## 将Dataframe单列转化为一维数组
Warray2 = Warray1.reshape(-1, 1) ## 一维转二维度
# 创建 StandardScaler 对象
standard_scaler = StandardScaler()
df_Weight = standard_scaler.fit_transform(Warray2) ## 二维标准化
print("标准化后体重数组")
print(df_Weight) ## 得到标准化后体重为数组类型
df_diet['New_Weight'] = df_Weight
print("将体重单独标准化后加入")
print(df_diet.head())
"""
# ^^^^^^^^^^体重单独标准化后^^^^^^^^^
其中注意:
- fit处理后得到数组类型数据
- Dataframe取单列得到的是数组类型,标准化需要二维数组就得再转化。
三、PCA降维
1.简介
为实现多类方法,用降维减少属性。
降维是通过减少特征的数量来简化数据表示的过程,目的是在保留关键信息的同时减少冗余和噪音。常见的降维方法包括主成分分析和 t-分布邻域嵌入等。
本文使用主成分分析(PCA)方法,其基本无需调参,只需给出需要降维到的维度,或者希望降维后的主成分的方差和占原始维度所有特征方差和的比例阈值。
原理: PCA是一种通过线性变换将数据投影到新的坐标系中的方法,目标是最大化数据的方差。通过选择最大方差的方向,可以获得最重要的主成分。PCA将数据映射到主成分上,实现了将原始高维数据集映射到较低维度的新空间。
应用: PCA广泛用于数据压缩、特征提取、可视化等领域。
2.具体内容
#尝试降维,实际上特征不多作用不大df_min
from sklearn.decomposition import PCA
# PCA步骤:对原始数据零均值化,求协方差矩阵,对协方差矩阵求特征向量和特征值,特征向量组成了新的特征空间
pca = PCA(n_components=4) # 降为n维
newdf = pca.fit_transform(df_min) # 返回降维后的数据newdf
invdf = pca.inverse_transform(newdf) # 将降维后的数据转换成原始数据
df_inv = pd.DataFrame(invdf, columns=df_diet.columns) # 将数组转化为Dataframe
print("原数据")
print(df_min)
#print(newdf)
print("降维后数据")
print(df_inv.head())
print("Explained Variance Ratio for each Principal Component:")
print(pca.explained_variance_ratio_) # 各成分方差贡献比
PCA 的目标是通过线性变换将数据投影到一个新的正交坐标系中,以保留尽可能多的方差。本例投影到4维。
列数不会变化,只是减少特征的数量。每一列仍然对应一个特征,只是经过降维后,这些特征可能是原始特征的线性或非线性组合,或者是经过其他变换得到的新特征。
方差贡献比用于表示每个主成分所解释的方差的比例。它返回一个数组,表示对应主成分解释的方差占总方差的比例,反映各成分对数据信息贡献大小。
四、分类和回归
1.分类
代码如下:
# 数据
x = df_diet.values[:, :7]
# 标签值
y = df_diet.values[:, 7]
# 将数据集划分为训练集和测试集
train_X, test_X, train_y, test_y = train_test_split(x, y, train_size=0.5, test_size=0.5, random_state=0)
# 实例化分类器
lr = LogisticRegressionCV()
# 训练
rf = lr.fit(train_X, train_y)
# 计算准确率并进行打印
print("Accuracy = {:.2f}".format(lr.score(test_X, test_y)))
准确率为0.72。用的是原数据如果要用降维后数据得加入:
df_inv['BMIex'] = df_diet['BMIex']
因为分类问题需要的是离散的类别标签,而不是连续的数值。
2.回归
# 数据
X = df_inv.values[:, :7]
# 标签值
y = df_inv.values[:, 7]
# 将数据集划分为训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=10)
# 创建随机森林回归模型
rf_regressor = RandomForestRegressor(n_estimators=100, random_state=42)
# 在训练集上拟合模型
rf_regressor.fit(X_train, y_train.ravel())
# 在测试集上进行预测
y_pred = rf_regressor.predict(X_test)
# 计算均方误差(Mean Squared Error)
mse = mean_squared_error(y_test, y_pred)
print(f"Mean Squared Error: {
mse}")
index = range(537) ## 是由预测集数量决定的,可以运行后由警告得到
# 绘制散点图
sns.scatterplot(x = index, y=y_test,color='blue', alpha= 0.7, label='Actual')
sns.scatterplot(x = index, y=y_pred, color='red', alpha= 0.7, label='Predicted')
plt.title('Scatter Plot')
plt.xlabel('X')
plt.ylabel('BMIex')
plt.legend()
plt.savefig('随机森林',bbox_inches='tight')
plt.show()
预测方差0.00017253880100446858可以说非常好了。该部分用的回归,但实际上X取的无意义索引index,仅仅是练习,这也是算法的神奇地方。对实际索引,应该取事件,年龄等变量。离散型属性得用分类。
本文使用随机森林算法,核心思想是通过多个弱学习器的集体决策来获得强大的模型。真有点山坡撒种子自然选择的感觉。
对RandomForestRegressor模型由criterion参数,用于衡量分裂质量的标准。对于回归问题,默认是 ‘mse’(均方误差),也可以选择使用 ‘mae’(平均绝对误差)。n_estimators是树数量越多越准确。
- 均方误差:因为平方操作放大了差异,对较大的错误更加敏感
- 平均绝对误差:不对大误差和小误差做特殊处理
可以看到拟合效果很好,x轴是0到样本数量的索引,y轴是BMIex评价指标(降维后)。
三、聚类
1.数据处理
为了聚类首先需要对数据指定标签(簇)。将原数据最后以列BMIex指定为簇,对其他数据进行聚类。
## 将原Dataframe转化为以最后一列BMIex分类(簇)的数组,提取特征列BMIex
features = df_diet.iloc[:, :-1].values ## 除最后以列,作为样本
labels = df_diet.iloc[:, -1].values ## 最后一列
# 绘制带簇数组
plt.title('分类数据',color='#8B5A2B', weight='medium', fontsize=5,fontproperties="SimHei")
sns.scatterplot(x=features[:, 0], y=features[:, 1], hue=labels, data=df_diet,
palette='viridis', edgecolor='k')
plt.legend()
plt.savefig('分类后数据',bbox_inches='tight')
plt.show()
该方法常用,得到
2.具体内容
进行聚类分析
# 聚类
X,_ = features,labels
X, _ = make_blobs(n_samples=300, centers=4, random_state=42)
# 使用K均值聚类
kmeans = KMeans(n_clusters=4, random_state=42)
kmeans.fit(X)
# 获取聚类结果和簇中心
labels = kmeans.labels_
centers = kmeans.cluster_centers_
plt.title('聚合数据',color='#8B5A2B', weight='medium', fontsize=5,fontproperties="SimHei")
sns.scatterplot(x=X[:, 0], y=X[:, 1], hue=labels,
palette='viridis', edgecolor='k')
sns.scatterplot(x=centers[:, 0], y=centers[:, 1], color='red',
palette='viridis', edgecolor='k',marker='X', s=200, label='Center')
plt.legend()
plt.savefig('聚合数据',bbox_inches='tight')
plt.show()
使用K均值聚类法,对异常值不太敏感,胜在简单好理解,计算快。
总结
笔者非常喜欢Scikit-learn,是个很好的工具箱。本文包含了几类基本操作,虽然用的方法可能不太贴切,但使用技术上还是准确的。写文过程中也发现了自己对几类算法原理的不清晰,对各函数只能做到使用而不能很贴切的理解。还需更多学习。
一直期望用好计算机。最初大一在材料专业学习solidworks,折腾了一些零件图,大二转入电气遂放弃。申请实验室要写个贪吃蛇,又学编程,也算入了编程的门。
随着C、C++的课程算是了解了几类语言。大二建模比赛,发现了Latex这个神奇的东西,那才是第一次折腾了几个大文件(字数多)。电气专业啊实在是啥都沾点,Matlab、汇编算是必学。22年后AI实在火热又入了Python怀抱。兜兜转转几年间竟尝试了这么多。
算是努力,但今却成了个无业游民。从不相信关一扇门就开一扇窗的零和给予,只是尽量在自己的节奏里保持学习吧。智慧,总是美的。