医学数据分析实训 项目二 数据预处理作业
文章目录
- 项目二 数据预处理
- 一、实践目的
- 二、实践平台
- 三、实践内容
- 任务一:合并数据集
- 任务二:独热编码
- 任务三:数据预处理
- 任务四:针对“项目一 医学数据采集”中“3. 通过 UCI 机器学习库下载数据集”任务所下载的数据集进行预处理。
- (一)检测与处理缺失值
- (二)检测与处理重复值
- (三)检测与处理异常值
- (四)标准化数据
- (五)离散化连续型数据
- (六)数据规约
- 四、结果提交
项目二 数据预处理
一、实践目的
- 熟悉数据预处理的流程;
- 掌握使用 pandas 库合并数据、清洗数据、标准化数据和转换数据的常用方法;
二、实践平台
- 操作系统:Windows10 及以上
- Python 版本:3.8.x 及以上
- PyCharm 或 Anoconda 集成环境
三、实践内容
任务一:合并数据集
合并数据集 “healthcare-dataset-stroke.csv” 和 “healthcare-dataset-age_abs.csv”,合并之后的数据集以 “healthcare” 命名。
import pandas as pd
# 读取两个CSV文件
df1 = pd.read_csv('input/healthcare-dataset-stroke.csv')
df2 = pd.read_csv('input/healthcare-dataset-age_abs.csv')
# 将两个数据集按列合并
healthcare = pd.concat([df1, df2], axis=1)
# 去重复的列
healthcare = healthcare.loc[:, ~healthcare.columns.duplicated()]
# 保存合并后的数据集到CSV文件
healthcare.to_csv('output/healthcare.csv', index=False)
# 打印合并后的数据集的前几行
print("数据集已成功合并并保存为 'healthcare.csv'")
print(healthcare.head())
任务二:独热编码
机器学习算法通常只能处理数值特征,因此需要将类别特征转换为数值。请采用独热编码对数据集 “healthcare” 中的数据进行特征数字化处理。
# 检查缺失值
print(healthcare.isnull().sum())
# 处理体重指数缺失值
bmi_mean = healthcare['体重指数'].mean()
healthcare['体重指数'] = healthcare['体重指数'].fillna(bmi_mean)
# 再次检查缺失值
print(healthcare.isnull().sum())
# 检查重复值
print(healthcare.duplicated().sum())
from sklearn.preprocessing import OneHotEncoder
# 选择需要进行独热编码的列
categorical_columns = healthcare.select_dtypes(include=['object']).columns
# 打印独热编码的列
print("独热编码的列:", categorical_columns)
print("独热编码前的特征形状:", healthcare[categorical_columns].shape)
# 创建OneHotEncoder对象
encoder = OneHotEncoder(categories='auto')
# 对数据集进行独热编码
encoded_features = encoder.fit_transform(healthcare[categorical_columns])
# 打印独热编码后的特征形状
print("独热编码后的特征形状:", encoded_features.shape)
# 将编码后的特征转化成DataFrame
encoded_df = pd.DataFrame(encoded_features.toarray(), columns=encoder.get_feature_names_out(categorical_columns))
print(encoded_df.head())
# 将编码后的特征与原始数据集合并
healthcare_encoded = pd.concat([healthcare.drop(categorical_columns, axis=1), encoded_df], axis=1)
# 保存处理后的数据集到CSV文件
healthcare_encoded.to_csv('output/healthcare_encoded.csv', index=False)
# 打印处理后的数据集的前几行
print("数据集已成功进行独热编码并保存为 'healthcare_encoded.csv'")
print(healthcare_encoded.head())
任务三:数据预处理
- 使用 StandardScaler 对数据集 “data_expert_temp.xlsx” 进行均值方差标准化处理。并通过散点图对比原始数据和处理后的数据(可选择任一特征)。
# 1. 使用 StandardScaler 对数据集“data_expert_temp.xlsx”进行均值方差标准化处理。并通过散点图对比原始数据和处理后的数据(可选择任一特征);
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['SimHei'] # 显示中文
plt.rcParams['axes.unicode_minus'] = False # 显示负号
from sklearn.preprocessing import StandardScaler, MinMaxScaler
# 读取数据集
data = pd.read_excel("input/data_expert_temp.xlsx")
# 选择一个特征进行标准化处理
# 检查缺失值
print('检查缺失值',data.isnull().sum())
# 处理缺失值
data = data.fillna(data.mean())
# 再次检查缺失值
print('再次检查缺失值:',data.isnull().sum())
# 特征
feature = '血红蛋白' # 替换为实际的特征名称
# 原始数据
original_data = data[feature]
# 标准化处理
scaler = StandardScaler()
scaled_data = scaler.fit_transform(data[[feature]])
# 绘制散点图
plt.figure(figsize=(12, 6))
plt.subplot(1, 2, 1)
plt.scatter(range(len(original_data)), original_data)
plt.title('原始数据')
plt.xlabel('样本索引')
plt.ylabel(feature)
plt.plot(xlabel='样本索引', ylabel=feature, label=feature)
plt.subplot(1, 2, 2)
plt.scatter(range(len(scaled_data)), scaled_data)
plt.title('标准化后的数据')
plt.xlabel('样本索引')
plt.ylabel('标准化后的数据')
plt.plot(xlabel='样本索引', ylabel='标准化后的数据', label='标准化后的数据')
plt.show()
- 使用 MinMaxScaler 对数据集 “data_expert_temp.xlsx” 进行离差标准化处理。并绘制处理之后的数据散点图。
# 2. 使用 MinMaxScaler 对数据集“data_expert_temp.xlsx”进行离差标准化处理。并绘制处理之后的数据散点图;
from sklearn.preprocessing import MinMaxScaler
feature = '血红蛋白' # 替换为实际的特征名称
original_data = data[feature]
scaler = MinMaxScaler()
scaled_data = scaler.fit_transform(data[[feature]])
plt.figure(figsize=(6, 6))
plt.scatter(range(len(scaled_data)), scaled_data, label='离差标准化后的数据')
plt.title('离差标准化后的数据')
plt.xlabel('样本索引')
plt.ylabel(feature)
plt.legend()
plt.show()
- 使用 Binarizer 对数据集 “data_expert_temp.xlsx” 中的 “血小板计数” 进行特征二值化处理,设置阈值为 100。
# 3. 使用 Binarizer 对数据集“data_expert_temp.xlsx”中的“血小板计数”进行特征二值化处理,设置阈值为 100;
from sklearn.preprocessing import Binarizer
feature='血小板计数'
# 二值化处理
binarizer = Binarizer(threshold=100)
binarized_data = binarizer.fit_transform(data[[feature]])
# 打印二值化后的数据
print(binarized_data)
- 对数据集 “data_expert_temp.xlsx” 进行 PCA 降维,保留特征数 8。
# 4. 对数据集“data_expert_temp.xlsx”进行 PCA 降维,保留特征数 8;
from sklearn.decomposition import PCA
pca = PCA(n_components=8)
pca_data = pca.fit_transform(data)
pca_df = pd.DataFrame(pca_data, columns=[f'PC{i+1}' for i in range(8)])
print(pca_df.head())
任务四:针对“项目一 医学数据采集”中“3. 通过 UCI 机器学习库下载数据集”任务所下载的数据集进行预处理。
(一)检测与处理缺失值
- 项目任务
- 检测并处理数据集中的缺失值,删除所有数据均为缺失值的列,其他列中的缺失值用该列的均值、中位数或众数等替换;
- 利用 isnull 或 notnull 找到缺失值。
- 数据中的某个或某些特征的值是不完整的,这些值称为缺失值。
- pandas 提供了识别缺失值的方法
isnull
以及识别非缺失值的方法notnull
,这两种方法在使用时返回的都是布尔值 True 和 False。 - 结合
sum
函数和isnull
、notnull
函数,可以检测数据中缺失值的分布以及数据中一共含有多少缺失值。
- 实现方法
- 删除法
- 删除法分为删除观测记录和删除特征两种,它属于利用减少样本量来换取信息完整度的一种方法,是一种最简单的缺失值处理方法。
- pandas 中提供了简便的删除缺失值的方法
dropna
,该方法既可以删除观测记录,亦可以删除特征。 - 方法签名:
pandas.DataFrame.dropna(self, axis=0, how='any', thresh=None, subset=None, inplace=False)
- 替换法
- 用一个特定的值替换缺失值。
- 特征可分为数值型和类别型,两者出现缺失值时的处理方法也是不同的。
- 缺失值所在特征为数值型时,通常利用其均值、中位数和众数等描述其集中趋势的统计量来代替缺失值。
- 缺失值所在特征为类别型时,则选择使用众数来替换缺失值。
- pandas 库中提供了缺失值替换的方法
fillna
,其基本语法如下。- 方法签名:
pandas.DataFrame.fillna(value=None, method=None, axis=None, inplace=False, limit=None)
- 方法签名:
- 插值法
- 删除法简单易行,但是会引起数据结构变动,样本减少;替换法使用难度较低,但是会影响数据的标准差,导致信息量变动。在面对数据缺失问题时,除了这两种方法之外,还有一种常用的方法—插值法。
- 线性插值 是一种较为简单的插值方法,它针对已知的值求出线性方程,通过求解线性方程得到缺失值。
- 多项式插值 是利用已知的值拟合一个多项式,使得现有的数据满足这个多项式,再利用这个多项式求解缺失值,常见的多项式插值法有拉格朗日插值和牛顿插值等。
- 样条插值 是以可变样条来作出一条经过一系列点的光滑曲线的插值方法,插值样条由一些多项式组成,每一个多项式都是由相邻两个数据点决定,这样可以保证两个相邻多项式及其导数在连接处连续。
- SciPy 库中的
interpolate
模块提供了多种插值方法,如重心坐标插值(Barycentric Interpolator)等。在实际应用中,需要根据不同的场景,选择合适的插值方法。
- 删除法
任务四
Class复发情况: no-recurrence-events 表示没有复发事件。
age年龄段: 比如 30-39,表示患者的年龄在 30 到 39 岁之间。
menopause绝经状态: premeno 表示绝经前,ge40 表示绝经后(超过40岁),lt40 表示40岁以下。
tumor-size肿瘤大小: 比如 30-34 表示肿瘤的大小范围在 30 到 34 mm 之间。
inv-nodes淋巴结受累情况: 0-2 表示受累淋巴结的数量在 0 到 2 个之间。
node-caps淋巴结包膜破裂: no 表示淋巴结包膜未破裂,yes 表示包膜破裂。
deg-malig恶性程度: 1, 2, 3 表示恶性程度的分级。
breast乳房位置: left 或 right,表示肿瘤发生在左乳房或右乳房。
breast-quad乳房四象限: left_low、right_up 等表示肿瘤所在的乳房区域,分别对应左乳房下象限、右乳房上象限等。
irradiat是否进行了放射治疗: no 表示未进行,yes 表示进行了放射治疗。
# 读取数据集
data=pd.read_csv('./breast_cancer/breast-cancer.csv')
print(data.head())
# 检查缺失值
missing_value=data.isnull().sum()
print(missing_value)
# 无缺失值,不需要删除所有数据均为缺失值的列
(二)检测与处理重复值
- 项目任务
- 检测数据集中是否存在重复数据,并删除重复数据行;
- 相关知识
- pandas 提供了一个名为
drop_duplicates
的去重方法。该方法只对 DataFrame 或者 Series 类型有效。这种方法不会改变数据原始排列,并且兼具代码简洁和运行稳定的特点。该方法不仅支持单一特征的数据去重,还能够依据 DataFrame 的其中一个或者几个特征进行去重操作。 - 方法签名:
pandas.DataFrame(Series).drop_duplicates(self, subset=None, keep='first', inplace=False)
subset
:接收 string 或 sequence。表示进行去重的列。默认为 None,表示全部列。keep
:接收特定 string。表示重复时保留第几个数据。First:保留第一个;Last:保留最后一个;False:只要有重复都不保留。默认为 first。inplace
:接收 boolean。表示是否在原表上进行操作。默认为 False。- 特征重复:结合相关的数学和统计学知识,去除连续型特征重复可以利用特征间的相似度将两个相似度为 1 的特征去除一个。在 pandas 中相似度的计算方法为
corr
,使用该方法计算相似度时,默认为“pearson”法,可以通过“method”参数调节,目前还支持“spearman”法和“kendall”法。 - 除了使用相似度矩阵进行特征去重之外,可以通过
DataFrame.equals
的方法进行特征去重。
- pandas 提供了一个名为
# 检测重复行
print('重复行:',data.duplicated().sum())
# 删除重复行
data.drop_duplicates(inplace=True)
print('重复行:',data.duplicated().sum())
print('输出处理后数据的形状',data.shape)
(三)检测与处理异常值
- 项目任务
- 采用箱型图检测是否存在异常值,并将异常值设置为缺失值,再进行填充。
- 相关知识点
- 异常值
- 异常值是指数据中个别值的数值明显偏离其余的数值,有时也称为离群点,检测异常值就是检验数据中是否有录入错误以及是否含有不合理的数据。
- 异常值的存在对数据分析十分危险,如果计算分析过程的数据有异常值,那么会对结果会产生不良影响,从而导致分析结果产生偏差乃至错误。
- 3σ原则
- 3σ原则又称为拉依达法则。该法则就是先假设一组检测数据只含有随机误差,对原始数据进行计算处理得到标准差,然后按一定的概率确定一个区间,认为误差超过这个区间的就属于异常值。
- 这种判别处理方法仅适用于对正态或近似正态分布的样本数据进行处理,如下表所示,其中σ代表标准差,μ代表均值,x=μ为图形的对称轴。
- 数据的数值分布几乎全部集中在区间 (μ-3σ, μ+3σ) 内,超出这个范围的数据仅占不到 0.3%。故根据小概率原理,可以认为超出 3σ 的部分数据为异常数据。
- 箱型图
- 箱型图提供了识别异常值的一个标准,即异常值通常被定义为小于 QL-1.5IQR 或大于 QU+1.5IQR 的值。
- QL 称为下四分位数,表示全部观察值中有四分之一的数据取值比它小。
- QU 称为上四分位数,表示全部观察值中有四分之一的数据取值比它大。
- IQR 称为四分位数间距,是上四分位数 QU 与下四分位数 QL 之差,其间包含了全部观察值的一半。
- 箱线图依据实际数据绘制,真实、直观地表现出了数据分布的本来面貌,且没有对数据做任何限制性要求,其判断异常值的标准以四分位数和四分位数间距为基础。
- 异常值
# 定义一个函数来计算区间的中间值
def calculate_midpoint(interval):
if isinstance(interval, str):
lower, upper = map(int, interval.split('-'))
return (lower + upper) / 2
else:
return np.nan
# 定义一个函数来计算区间的中间值
def calculate_midpoint(interval):
try:
if isinstance(interval, str):
lower, upper = map(int, interval.split('-'))
return (lower + upper) / 2
else:
return np.nan
except ValueError:
return np.nan
# 将 tumor-size 列转换为中间值
data['tumor-size-midpoint'] = data['tumor-size'].apply(calculate_midpoint)
print(data['tumor-size-midpoint'])
feature = 'tumor-size-midpoint'
# 绘制原始数据的直方图
plt.figure(figsize=(12, 6))
plt.subplot(1, 2, 1)
plt.hist(original_data, bins=30, color='blue', alpha=0.7)
plt.title(f'{feature} 的原始数据直方图')
plt.xlabel(feature)
plt.ylabel('频数')
# 选择一个特征进行异常值检测
feature = 'tumor-size-midpoint'
# 绘制箱型图
plt.figure(figsize=(8, 6))
plt.boxplot(data[feature], vert=False)
plt.title(f'{feature} 的箱型图')
plt.xlabel(feature)
plt.show()
# 计算四分位数和四分位数间距
Q1 = data[feature].quantile(0.25)
Q3 = data[feature].quantile(0.75)
IQR = Q3 - Q1
# 定义异常值的范围
lower_bound = Q1 - 1.5 * IQR
upper_bound = Q3 + 1.5 * IQR
# 检测异常值并设置为缺失值
data.loc[(data[feature] < lower_bound) | (data[feature] > upper_bound), feature] = np.nan
# 使用众数填充缺失值
data[feature] = data[feature].fillna(data[feature].mode()[0])
# 打印处理后的数据
print(data.head())
(四)标准化数据
- 项目任务
- 结合数据集的实际情况,使用离差标准化、标准差标准化或小数定标标准化对数据集进行标准化处理。
- 离差标准化
- 数据的整体分布情况并不会随离差标准化而发生改变,原先取值较大的数据,在做完离差标准化后的值依旧较大。
- 当数据和最小值相等的时候,通过离差标准化可以发现数据变为 0。
- 若数据极差过大就会出现数据在离差标准化后数据之间的差值非常小的情况。
- 同时,还可以看出离差标准化的缺点:若数据集中某个数值很大,则离差标准化的值就会接近于 0,并且相互之间差别不大。
- 标准差标准化
- 标准化是依照特征矩阵的列处理数据,其通过求 z-score 的方法,将样本的特征值转换到同一量纲下。
- 简而言之,标准化将连续性变量转变为均值 0、标准差 1 的变量,标准化需要计算特征的均值和标准差。
- 常用于基于正态分布的算法,比如回归。
- 使用
preprocessing
库的StandardScaler
(基于特征矩阵的列,将属性值转换至服从正态分布)类对数据进行标准化。
- 小数定标标准化
- 通过移动属性值的小数位数,将属性值映射到 [-1,1] 之间,移动的小数位数取决于属性值绝对值的最大值。
### (四)标准化数据
from sklearn.preprocessing import MinMaxScaler
# 选择一个特征进行标准化处理
feature = 'tumor-size-midpoint'
# 原始数据
# original_data = data[feature]
# 离差标准化处理
scaler = MinMaxScaler()
scaled_data = scaler.fit_transform(data[[feature]])
# # 绘制原始数据的直方图
# plt.figure(figsize=(12, 6))
#
# plt.subplot(1, 2, 1)
# plt.hist(original_data, bins=30, color='blue', alpha=0.7)
# plt.title(f'{feature} 的原始数据直方图')
# plt.xlabel(feature)
# plt.ylabel('频数')
# 绘制离差标准化后的数据直方图
plt.subplot(1, 2, 2)
plt.hist(scaled_data, bins=30, color='green', alpha=0.7)
plt.title(f'{feature} 的离差标准化后数据直方图')
plt.xlabel('标准化后的数据')
plt.ylabel('频数')
plt.show()
# 打印处理后的数据
print(data.head())
(五)离散化连续型数据
- 项目任务
- 结合数据集的实际情况,进行离散化处理,划分区域可自行设定。
- 相关知识点
- 某些模型算法,特别是某些分类算法如 ID3 决策树算法和 Apriori 算法等,要求数据是离散的,此时就需要将连续型特征(数值型)变换成离散型特征(类别型)。
- 连续特征的离散化就是在数据的取值范围内设定若干个离散的划分点,将取值范围划分为一些离散化的区间,最后用不同的符号或整数值代表落在每个子区间中的数据值。
- 因此离散化涉及两个子任务,即确定分类数以及如何将连续型数据映射到这些类别型数据上。
- 等宽法
- 将数据的值域分成具有相同宽度的区间,区间的个数由数据本身的特点决定或者用户指定,与制作频率分布表类似。
- pandas 提供了
cut
函数,可以进行连续型数据的等宽离散化,其基础语法格式如下。- 方法签名:
pandas.cut(x, bins, right=True, labels=None, retbins=False, precision=3, include_lowest=False)
- 方法签名:
- 使用等宽法离散化的缺陷为:等宽法离散化对数据分布具有较高要求,若数据分布不均匀,那么各个类的数目也会变得非常不均匀,有些区间包含许多数据,而另外一些区间的数据极少,这会严重损坏所建立的模型。
- 等频法
cut
函数虽然不能够直接实现等频离散化,但是可以通过定义将相同数量的记录放进每个区间。- 等频法离散化的方法相比较于等宽法离散化而言,避免了类分布不均匀的问题,但同时却也有可能将数值非常接近的两个值分到不同的区间以满足每个区间中固定的数据个数。
- 基于聚类分析的方法
- 一维聚类的方法包括两个步骤:将连续型数据用聚类算法(如 K-Means 算法等)进行聚类。
- 聚类分析的离散化方法需要用户指定簇的个数,用来决定产生的区间数。
- K-Means 聚类分析的离散化方法可以很好地根据现有特征的数据分布状况进行聚类,但是由于 K-Means 算法本身的缺陷,用该方法进行离散化时依旧需要指定离散化后类别的数目。此时需要配合聚类算法评价方法,找出最优的聚类簇数目。
from sklearn.cluster import KMeans
# 等宽法
feature = 'tumor-size-midpoint' # 替换为实际的特征名称
# 等宽法离散化
bins = 5 # 设定区间数
data['tumor-size-midpoint-discretized-equal-width'] = pd.cut(data[feature], bins=bins, labels=False)
# 打印处理后的数据
print(data.head())
(六)数据规约
- 项目任务
- 结合数据集的实际情况,进行属性规约或数值规约,从而获得一个比原数据集的小得多的规约表示。
- 相关知识点
- 维度规约(属性规约):通过删除不相干的属性和维数减少数据量。向前选择,向后删除,决策树,PCA;
- 数值规约:通过选择替代的、较小的数据表示形式来减少数据量。有参方法(回归法,对数线性模型),无参法(直方图,聚类,抽样)。
numeric_features = data.select_dtypes(include=[np.number])
print(numeric_features)
# 使用 PCA 进行维度规约
pca = PCA(n_components=2) # 设定主成分数量
pca_data = pca.fit_transform(numeric_features)
# 将 PCA 结果转换为 DataFrame
pca_df = pd.DataFrame(pca_data, columns=['PC1', 'PC2'])
# 打印 PCA 结果
print(pca_df.head())
四、结果提交
- 提交所有任务的数据预处理实现代码;
- 提交任务四的原始数据集及预处理之后的数据集;