优秀的编程知识分享平台

网站首页 > 技术文章 正文

探索性数据分析:如何在数据中找到见解

nanyue 2024-08-05 20:11:44 技术文章 5 ℃

当我开始学习机器学习时,我遇到的第一件事就是EDA,即探索性数据分析。本文是探索性数据分析的基本快速入门指南,它将帮助您启动EDA。本指南将为您提供有关探索性数据分析的基础知识。

EDA的目标可归纳如下:

  • 最大限度地洞察数据/理解数据结构;
  • 可视化暴露变量和结果变量之间的潜在关系(方向和幅度);
  • 检测异常值和异常(与其他观察结果显著不同的值);
  • 开发简约模型(预测或解释机器学习模型,尽可能少地暴露变量)或初步选择合适的机器学习模型;
  • 提取并创建临床(示例使用)相关变量。

在开始我们的旅程之前,让我们了解一些用于分析的基本术语。

基本术语:

数据是关于组织成变量的个体的信息片段。个体,我们指的是一个特定的人或对象。所谓变量,我们指的是个体的一个特定特征。

机器学习数据集是根据特定情况确定的数据集合。数据集以表的形式显示,其中行是记录或个体,列是变量或个体的特定特征。

每个变量分为两种类型

  • 定量变量
  • 定性/分类变量

定量变量用数字量化数据,我们可以比较两个不同的值。它又分为两个子类型。

  • 1)离散变量
  • 2)连续变量

离散变量只取整数值,不取任何分数,如1,2,3…n

连续变量的取值范围以分数的形式表示,如1.1、2.4、3.6。等等,直到n。

定性变量描述数据的质量或类别。它也被称为分类变量。它又分为4种类型。

  • 标称
  • 序数
  • 间隔
  • 比率

我将使用python进行分析,使用Habersmankeggle数据集(https://www.kaggle.com/gilsousa/habermans-survival-data-set)作为示例。

背景:

该数据集包含1958年至1970年间在芝加哥大学比林斯医院进行的一项研究案例,该研究涉及接受过乳腺癌手术的患者的生存情况。

淋巴结有助于保护身体免受感染,并用于过滤淋巴系统中的异物。

淋巴是一种清晰的液体,围绕着身体细胞,通过淋巴通道排入淋巴结。当感染存在时,淋巴结检测到它并帮助发起一系列事件以对抗感染。癌细胞可能脱离主要肿瘤并通过淋巴系统或通过血管循环。当某些类型的癌细胞停留在淋巴结中时,癌症就会增长。在治疗某些癌症时,重要的是要知道淋巴结是否含有癌细胞以确定癌症是否已经扩散到全身。

乳腺癌经常扩散到腋窝(腋窝)淋巴结。传统上,当移除乳腺癌时,进行称为腋窝淋巴结清扫的手术以移除腋窝中的大部分淋巴结。由于淋巴结清扫会导致疼痛和手臂肿胀等问题,因此最好尽可能避免手术。

现在我们对乳腺癌和什么是腋窝淋巴结有了基本的了解。

现在让我们尝试找到我们想要处理的目标。

主要目标是找到有助于我们建立预测结果的机器学习模型的特征,患者是否存活或不超过五年。

可以从数据中构建许多不同的问题。以下是我为此创建的问题列表。

  • Q)手术后幸存者的百分比是多少?
  • Q)乳腺癌影响最大的年龄组范围是多少?
  • Q)哪一年手术最多也没有最少?
  • Q)腋窝淋巴结与年龄之间是否有任何关系?
  • Q)腋窝淋巴结与手术年度之间是否有任何关系?
  • Q)是否有任何特征可以帮助我们区分死亡和幸存的人。

这些问题现在已经足够了,请花点时间和自己提出问题。

开始分析

导入我们用于数据分析的所有重要的python库。

# Load all important libraries
import numpy as np
import pandas as pd
from mpl_toolkits import 
import matplotlib.pyplot as plt
import seaborn as sns
sns.set()

现在将数据加载到pandas数据框中,pandas是一个非常强大的数据分析工具。加载数据后,我们使用head()和tail()方法来检查数据。

file_name = 'haberman.csv'
df = pd.read_csv(file_name, names= ['age', 'opr_year', 'axil_nodes_det', 'surv_status'])
df.head()
df.tail()

在这里我们可以检查两件事。

  • 借助head()和tail()函数正确加载所有数据。
  • 在开始或结束时是否有任何缺失值,我们可以通过指定要在panda中查看的行数来处理日期。head(n)显示前n条记录,tail(n)显示最后n条记录。

一旦我们验证了数据,我们就可以检查什么是目标(结果)变量。在机器学习数据集的情况下,surv_status是目标变量。

所有数据类型都是由panda根据列中可用的数据强制/推断的。现在检查数据集中出现的每个变量的数据类型,更新各自的数据类型。

pandas info()函数将为我们提供有关数据集中存在多少条记录的信息,包含列/变量名称的数据集的描述,条目的数量,列是否具有任何空值以及列/变量的数据类型。从机器学习数据集中我们可以看到我们在数据集中有306条记录,包括名为age,opr_year,axil_nodes_det和surv_status的四列,所有列都有完整的数据,数据类型为int64。

没有缺失值,如果任何列中存在任何缺失值,我们必须在更新列数据类型之前清理数据。

现在更正数据集的数据类型。

age — Quantitative variable

opt-year — Categorical variable.

axil_nodes_det — Quantitative variable

surv_status — Categorical variable.

pandas提供了astype()函数来更新列的数据类型。

df['opr_year'].astype(str)

我已将opr_year更新为相应的数据类型。

我按名称状态添加了一个新列,并在surv_status值上添加了一些有意义的文本值。

1 - 幸存5年或更长时间,2 - 在5年内死亡

df['status'] = np.where(df['surv_status'] == 1, 'survived', 'died')

现在检查机器学习数据集的数据类型,以验证列的数据类型是否已更新。

df.info()

列数据类型正确更新。

df.head()

EDA方法可以交叉分类为:

  • 图形或非图形方法
  • 单变量(仅一个变量,暴露或结果)或多变量(单独的几个暴露变量或结果变量)方法。

建议采用EDA技术,这取决于数据类型

最有用的EDA技术取决于目标

让我们先用Categorical变量开始分析数据。

一个分类变量可以回答什么样的问题。

  • Q)它是否是一个平衡的机器学习数据集,如果不是如何拆分数据。
  • Q)每种分类类型之间划分的数据百分比是多少?

我们使用诸如计数,百分比等描述性统计数据来查找上述问题的答案。

如果是分类变量,请始终选择目标变量进行分析,在这种情况下,状态是分类变量。

status: ( survival status ) : (Died / Survived)

首先,我将解释分析数据的非图形方法,然后将进入图形化。

让我们回答以下问题:

Q)有多少人存活超过5年并且在手术后5年内死亡?

共有306条记录,其中225人幸存,81人在手术后死亡。

Q)手术后存活的百分比是多少?

Q)手术后死亡的百分比是多少?

died_per = stats['died'] / len(df) * 100
26.47058823529412

Q)这个机器学习数据集是平衡的还是不平衡的?如何在两个类之间划分数据。

数据集是一个不平衡的数据集,它包括74%的幸存人员记录和26%的死亡人员记录。它存活患者行数比死亡患者行数更多。

现在,我将使用图表来更好地了解数据

我们可以使用条形图或饼图来了解分类数据。图表比描述性统计更能让人理解。

我将使用条形图,我将count作为y轴,因为数据集中出现的样本记录较少,而surv_status编码的值status作为x轴。

surv_status_table = pd.crosstab(index=df["status"], columns="count")
surv_status_table.plot(kind="bar",
 figsize=(8,8))

如果我们有更多的数据点,我们可以用百分比来画条形图。如果我们知道记录的总数,我们甚至可以从百分比中计算记录的数量。

对机器学习数据集目标变量进行了分析。

让我们分析年份列/变量,它也是一个分类变量。分析将以同样的方式进行。

这里我将使用双向表来总结数据。

df['opr_year'] = df['opr_year'].astype('str')
surv_status_df = pd.crosstab(index=df["status"], 
 columns=df["opr_year"])
surv_status_df.index= ["died","survived"]
surv_status_df

从双向表中可以看出,1958年和1965年有更多患者死亡。1958年有更多(36,12例死亡,24例存活)病例,而且非常少(11例死亡,7例死亡)在1969年幸存下来。我们可以使用比较条形图来显示存活和死亡之间的数据。

died, survived = surv_status_df.get_values()
# create plot
fig, ax = plt.subplots()
index = df['opr_year'].unique();
index = index.astype(int)
bar_width = 0.35
opacity = 0.8
 
rects1 = plt.bar(index, died, bar_width,
 alpha=opacity,
 color='b',
 label='Died')
 
rects2 = plt.bar(index + bar_width, survived, bar_width,
 alpha=opacity,
 color='g',
 label='Survived')
 
plt.xlabel('Year')
plt.ylabel('count')
plt.title('Survival by Year')
 
plt.tight_layout()
plt.show()

从比较条形图中我们可以看到死亡与存活率之间的比率。

特别是在65年,更多的人死亡。我们可以从数据中构造一个复杂而有趣的问题

  • Q)1958年和1965年死亡人群中检测到的腋窝淋巴结数量是多少?人们的年龄是多少?

这个问题我会留给你分析。

  • Q)哪一年手术最多,哪一年最少?

1958年,大多数手术都完成了,并且在1965年完成了最少的手术。

定量变量分析:

现在让我们继续进行定量变量分析。定量分析与分类分析略有不同。我们将使用数值统计和直方图,盒须图来分析数据。

一个定量变量分析: -

定量分析可以回答什么样的问题。

  • Q)数据是如何分布的?
  • Q)给定数量列的平均值是多少?
  • Q)大多数数据驻留在哪里?
  • Q)数据集中的范围,最小值和最大值是多少?
  • Q)数据集中的异常值是什么?

我们将从腋窝淋巴结(axil_nodes_det)开始,因为这是手术的主要原因。

axil_nodes_det是一个定量变量。

作为数据统计的术语:

Center, Spread and Shape

中心: -数据的中心是什么。我们应该采取什么指标来将其作为中心。测量中心有两种不同的技术。

  • 平均值
  • 中位数

平均值: - 平均值是所有数据点的平均值,它不稳健,对数据异常值敏感。

中位数:中位数是数据点的中心,按升序或降序排序。它很稳健,对异常值不敏感。

离散度/可变性: - 数据指向远离中心的距离(可能是平均值或中位数)。测量稀疏有两种技术。

  • 标准偏差
  • 四分位距(IQR)。

标准偏差是方差的平方根,当数据处于对称分布时将使用它,它将以标准偏差的形式给出距离,如1std,-1std。

IQR是75% - 25%之间的差值,这将给出中间50%的数据距离。它将帮助我们识别中间50%的数据的模式,以及它们与中间值之间的距离。当数据处于非对称分布时,将使用这种方法。

形状: - 我们如何知道数据是对称还是非对称分布。形状将为我们提供了解分布类型的信息。如果它是对称的,那么我们将获得钟形曲线,否则其他形状如左偏态或右偏态等。

五个数字汇总统计由列组成min,max,25百分位数(Q1),75百分位数(Q3),50百分位数(Q2)(中位数)。

这些统计数据将帮助我们更加了解数据位。

让我们检查axil_nodes_det的五个数字总和。

pandas describe()函数将给出给定列的五个数字summery统计信息。我们可以看到,均值和中值不是很接近数据点,所以它不是对称分布(均值和中值的差异会非常小),我们可以理解均值大于中值。这是不对称的(右偏态分布)

平均值受异常值影响,因此我们将使用中位数作为数据中心,使用IQR进行离散。

IQR = 75%-25%= 4 -0 = 4,IQR的值很小,我们可以得出结论,中间50%的数据非常接近度量中心,即中位数。大多数人有1个腋窝淋巴结。患者的淋巴结范围为52(最大 - 最小)。

在五个summery的帮助下。我们也可以识别异常值。

无论以下范围中出现的数据点是什么,都被视为异常值。

Q1 - 1.5 * IQR至Q3 + 1.5 * IQR

0 - 1.5 * 4 = - 6, 0之前不存在数据点,以0为最小值。

4 + 1.5 * 4 = 10,任何高于10的值都被视为异常值。

有时我们需要将数据包含到数据集中,即使summery统计数据显示它是一个异常值,但我们必须包含在机器学习数据集中。在这种情况下,haberman数据集有52个淋巴结作为summery统计数据的异常值,但它在乳腺癌中更为严重。所以我们应该在这种情况下包括异常值。此范围还可用于设置最小值和最大值集。

我们可以从图形中获得更多的见解。有许多图表来描述数据,但我们主要只使用两个图来理解数据。

  • 直方图
  • 箱形图

直方图是一种特殊形式的条形图,但这里的条形图表示的是数值范围的区间。

我们画一个axil_nodes_det的直方图

surv_df = df[df['status'] == 'survived']
died_df = df[df['status'] == 'died']
data = [df, surv_df, died_df]
for d in data:
 plt.close();
 sns.set_style('whitegrid')
 sns.FacetGrid(d, hue='status', size= 4)\
 .map(sns.distplot, 'axil_nodes_det')\
 .add_legend()
 plt.show()

从直方图中我们可以看到数据是右偏的,大多数数据点在0-5之间,很多点非常接近中值1。我已经按状态对数据进行了分离,以便更深入地了解存活和死亡患者之间的数据模式。都是右偏态,如果我们观察曲线下,我们可以分析,病人存活0 - 2淋巴结和病人去世有超过2 - 3淋巴结。

盒须图 :

该图基于五个summery汇总绘制,并且最好地可视化数据。它将提供比其他图更多的见解。如果目标变量由多个类组成,我们可以使用并排框图来分析对数据的更多见解。让我们为axil_nodes_det列绘制Box-Plot。

sns.boxplot(x='status',y='axile_nodes_det', data=df)
plt.show()

从box-plot中我们可以观察到大多数腋窝淋巴结为0 - 2的患者存活了下来在一些极端情况下腋窝淋巴结超过2个的患者存活了下来,同时,大多数腋窝淋巴结为1 - 11的患者死亡了。我们可以清楚地看到带有箱形图须的异常值。从box plot中我们可以看到,存活和死亡患者之间有很多数据重叠。我们不能仅在axil_nodes_det列上确定目标变量。

让我们分析Age,它也是定量变量,过程将与axil_nodes_det相同。

从五个summery的总和来看,Age是对称分布的。大多数数据大约在52岁左右。Age范围是83-30 = 53,大多数数据与平均值相差1个标准差。患者的最大年龄为83岁,患者的最小年龄为30岁。

让我们看看图表,以了解更多。

surv_df = df[df['status'] == 'survived']
died_df = df[df['status'] == 'died']
data = [df, surv_df, died_df]
for d in data:
 plt.close();
 sns.set_style('whitegrid')
 sns.FacetGrid(d, hue='status', size= 4)\
 .map(sns.distplot, 'age')\
 .add_legend()
 plt.show()
sns.boxplot(x='status',y='age', data=df)
plt.show()sns.boxplot(x='status',y='age', data=df)
plt.show()

从box plot中我们可以看到,大多数人在45岁之后死亡,而死亡和幸存的人的年龄之间有很多重叠。所以我们不能单独用年龄变量来分类。

我们甚至可以用年龄和axil_nodes_det来分析数据点,用排框图。

Q:乳腺癌对哪个年龄组的影响最大?

从图上看,它主要影响的是40-60岁的女性。

多变量分析:

多变量分析将使我们有机会用两个或多个变量的组合来分析变量,它们将帮助我们找到2个或更多变量之间的关系,是否有任何方法可以通过线或平面划分数据来对目标变量进行分类。有多种技术可以进行分析,但我们将重点关注pair plots,2D和3D散点图。

多变量分析可以回答什么样的问题?

  • Q)是否有任何变量集将数据划分为多个目标变量类。
  • Q)两个变量之间是否存在任何关系,如果是,那么关系是正面还是负面关系?
  • Q)两个变量如何相互关联?
  • Q)一个变量是否受另一个变量影响(因果关系)?

pair plots

pair plots是2D散点图,这将有助于我们一次在2D散点图上可视化多个变量。这将有助于我们分析多个定量变量。但是当我们有超过5列进行分析时,它会变得很痛苦,并且由于没有列增加,图表将变得非常小。我们只能根据定量变量绘制pair plots。

df_copy = df.copy()
del df_copy['opr_year']
del df_copy['surv_status']
df_copy.head()
plt.close();
sns.set_style("whitegrid");
sns.pairplot(df_copy, hue="status", size=3);
plt.show()

从Pair plots中我们可以观察到age和axil_nodes_det之间没有关系。数据点散布在整个地方,很难区分死亡和幸存的患者。我们不能单独使用age和axil_nodes_det对人进行分类。

2D散点图: -

我们将通过2D散点图获得的额外好处是我们可以绘制分类和定量变量之间的图。我绘制了三个2D散点图来识别数据集中不同数据点之间的关系。

columns = ['age', 'axil_nodes_det', 'opr_year']
for i, column in enumerate(columns):
 sns.set_style("whitegrid");
 sns.FacetGrid(df, hue="status", size=4) \
 .map(plt.scatter, column, columns[(i + 1) % len(columns)]) \
 .add_legend();
 plt.show();

从上图也可以看出,变量之间没有任何关系,所有变量都是在几何平面上散射的。很难通过两个变量的任意组合来区分目标变量。

  • Q)腋窝淋巴结与年龄之间是否有任何关系?

axil_nodes_det与来自第二2D散点图的年龄之间不存在关系。

  • Q)腋窝淋巴结与手术年度之间是否有任何关系?

axil_nodes_det和opr_year之间没有关系来自第二个2D散点图。

让我们更深层次,并分析3个类的数据。大多数情况下,我们只能通过2D散点图来了解。从上面的观察中我可以说它不可能对目标变量进行分类。但我们试着去理解3D图。

3D散点图:

3D散点图使用3个不同的变量对数据进行分类。使用以下网址播放交互式3D图表https://plot.ly/~sampath-karupakula/6/iris-dataset/。

即使从3D散射图中也无法正确分类数据点。

从单变量和多变量分析我们可以得出结论,很难实现一个预测新乳腺癌患者生存状态的模型。

Tags:

最近发表
标签列表