概述
目录
二、数据分析
2.1 EDA 目标
2.2 内容介绍
2.3 代码与理论学习
2.3.1 载入各种数据科学与可视化库
2.3.2 载入数据集并简单处理和查看
2.3.7 用 pandas_profiling 生成数据报告
2.4 后话
二、数据分析
2.1 EDA 目标
- EDA 的价值主要在于熟悉数据集,对数据集进行探索性分析,从而确定所获得数据集是否可用于、如何用于后续的 DL / ML 。
- 当了解了数据集之后我们下一步就是要去了解变量间的相互关系以及变量与预测值之间的存在关系。
- 引导数据科学从业者进行数据处理以及特征工程的步骤,使数据集的结构和特征集让接下来的预测问题更加可靠。
2.2 内容介绍
- 载入各数据科学库及可视化库
- 数据科学库 pandas、numpy、scipy;
- 可视化库 matplotlib、seabon;
- 载入数据集并简单处理和查看
- 载入训练-验证集和测试集;
- 简略处理和观察数据;
- 数据总览与选择性查看
- 通过 describe() 熟悉数据的相关统计量
- 通过 info() 熟悉数据类型
- 判断数据缺失和异常
- 查看每列的存在 NaN 情况
- 异常值检测
- 了解预测值的分布
- 查看总体分布概况与标签具体频数
- 查看 skewness 和 kurtosis 并学习其理论
- 用 pandas_profiling 自动生成数据报告
2.3 代码与理论学习
2.3.1 载入各种数据科学与可视化库
依赖加载:
import warnings
warnings.filterwarnings('ignore') # 过滤各种不会影响正常运行的警告
import pandas as pd
from pandas import DataFrame, Series
import missingno as msno
import numpy as np
import scipy.stats as st
import seaborn as sns
import matplotlib.pyplot as plt
2.3.2 载入数据集并简单处理和查看
1) 数据加载和简单预处理
数据加载:
train = pd.read_csv('./data/train.csv')
test = pd.read_csv('./data/testA.csv')
查看训练-验证集首尾各 5 条数据:
train.head().append(test.tail()) # [100000 rows x 3 columns]
查看测试集首尾各 5 条数据:
test.head().append(test.tail())
可见,需要预处理一下,把特征分离开,否则继续查看和分析是没有意义的;同时,还可以优化一下内存占用:
def reduce_mem_usage(df):
''' 数据精度量化压缩函数 '''
# 处理前 数据集总内存计算
start_mem = df.memory_usage().sum() / 1024**2
print('Memory usage of dataframe is {:.2f} MB'.format(start_mem))
# 遍历特征列
for col in df.columns:
# 当前特征类型
col_type = df[col].dtype
# 处理 numeric 型数据
if col_type != object:
c_min = df[col].min() # 最小值
c_max = df[col].max() # 最大值
# int 型数据 精度转换
if str(col_type)[:3] == 'int':
if c_min > np.iinfo(np.int8).min and c_max < np.iinfo(np.int8).max:
df[col] = df[col].astype(np.int8)
elif c_min > np.iinfo(np.int16).min and c_max < np.iinfo(np.int16).max:
df[col] = df[col].astype(np.int16)
elif c_min > np.iinfo(np.int32).min and c_max < np.iinfo(np.int32).max:
df[col] = df[col].astype(np.int32)
elif c_min > np.iinfo(np.int64).min and c_max < np.iinfo(np.int64).max:
df[col] = df[col].astype(np.int64)
# float 型数据 精度转换
else:
if c_min > np.finfo(np.float16).min and c_max < np.finfo(np.float16).max:
df[col] = df[col].astype(np.float16)
elif c_min > np.finfo(np.float32).min and c_max < np.finfo(np.float32).max:
df[col] = df[col].astype(np.float32)
else:
df[col] = df[col].astype(np.float64)
# 处理 object 型数据
else:
df[col] = df[col].astype('category') # object 转 category
# 处理后 数据集总内存计算
end_mem = df.memory_usage().sum() / 1024**2
print('Memory usage after optimization is: {:.2f} MB'.format(end_mem))
print('Decreased by {:.1f}%'.format(100 * (start_mem - end_mem) / start_mem))
return df
# 训练-验证集量化压缩
# 训练-验证集列表
train_list = []
# 遍历每一条样本,分离信号数据作为独立特征 (id + 205 beats + label)
for items in train.values:
train_list.append([items[0]] + [float(i) for i in items[1].split(',')] + [items[2]])
# 数据类型转换 list -> numpy -> DataFrame
train = pd.DataFrame(np.array(train_list))
# 特征名构造 id + s_0 ~ s_205 + label
train.columns = ['id'] + ['s_' + str(i) for i in range(len(train_list[0])-2)] + ['label']
# 内存优化
train = reduce_mem_usage(train)
# 查看
train.head()
# 同理,对测试集量化压缩
test_list=[]
for items in test.values:
test_list.append([items[0]] + [float(i) for i in items[1].split(',')])
test = pd.DataFrame(np.array(test_list))
test.columns = ['id'] + ['s_'+str(i) for i in range(len(test_list[0])-1)]
test = reduce_mem_usage(test)
test.head() # without labels
这下好了,可以正常查看和分析各类信息了。
此外,对 head() 和 tail() 方法赋予 Python-int 实参还可以 指定显示的样本数 (默认值 5)。以训练-验证集为例,显示首尾各 3 条:
# 首尾各显示 3 条
train.head(3).append(train.tail(3))
2) 观察信息
1. 使用 describe() 方法分别查看数据集的 统计信息 (主要适用于数值型变量):
train.describe()
test.describe()
可见,数据的最大最小值均已规范至 0~1,非常之理想,或意味着后续无需做归一化了。
此外,还可用 Python-list 赋予 percentiles 形参 (缺省值 [.25, .50, .75]) 以 指定输出结果包含的分位数,以训练-验证集为例:
# 显示训练-验证集 5%、25%、55%、75%、95% 分位数
train.describe(percentiles=[.05, .25, .55, .75, .95])
可见。结果显示了指定的 5%、25%、55%、75%、95% 分位数。
一方面,对于 非数值型 Series 对象, describe() 仅返回 值的总数、唯一值数量、出现次数最多的值及其出现次数 (毕竟非数值型的特征可统计的内容不多)。如下自定义示例:
# 自定义示例 - 非数值型 Series
object_series = pd.Series(['c', 'c', 'c', 's', 's', np.nan, 'g', 'g', 'o', 'o'])
object_series.describe()
另一方面,对于 数值-类别混合型 DataFrame 对象,describe() 仅返回 数值型特征列的汇总统计量;若 无数值型特征列,则只显示类别型特征列。如下自定义示例:
# 自定义示例 - 混合型 DataFrame
hybird_frame = pd.DataFrame({'obj': ['banana', 'orange', 'banana'], 'num': [0, 1, 2]})
hybird_frame.describe()
还可以通过 Python-list 或 特殊值 'all' 赋予 include / exclude 形参 以 控制包含或排除的数据类型,紧接上例:
# 自定义示例 - 混合型 DataFrame - 结果仅包含 'object' 特征列
hybird_frame.describe(include=['object'])
# 自定义示例 - 混合型 DataFrame - 结果仅包含数值型特征列
hybird_frame.describe(include=['number'])
# 自定义示例 - 混合型 DataFrame - 结果全部显示
hybird_frame.describe(include='all')
注意,以上仅使用了 describe() 方法的部分功能,其余强大功能详见:
- 英文文档:https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.describe.html
- 中文文档:https://www.pypandas.cn/docs/getting_started/basics.html#%E6%8F%8F%E8%BF%B0%E6%80%A7%E7%BB%9F%E8%AE%A1
2. 使用 info() 方法分别查看数据集的 数据类型:
train.info()
test.info()
可见,波形数据均已被量化为 float16 型,且没有类别型特征需要考虑。
注意,以上仅使用了 info() 方法的部分功能,其余强大功能详见:
- 英文文档:https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.info.html
3. 使用 .isna().any() 方法 判断各特征列是否存在缺失值 (如 None 或 numpy.NaN 等);用 isnull().sum() 方法 统计各特征列缺失值总数:
train.isna().any()
train.isnull().sum()
test.isna().any()
test.isnull().sum()
可见,训练-验证集 和 测试集均不存在缺失值,非常理想。
注意,若显示时 中间内容被省略,可以强制类型转换为 Python-list 再查看;而 isnull() 是 isna() 的别名,二者完全等同。
当然,若存在缺失值,还可以使用 .fillna() 方法填充。
更多 缺失值 相关方法及其链接
- isna():https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.isna.html
- isnull():https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.isnull.html
- fillna():https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.fillna.html
- notna():https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.notna.html
- notnull():https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.notnull.html
- dropna():https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.dropna.html
4. 使用 value_counts() 方法 统计各类别数:
train['label'].value_counts()
可见,训练-验证集的类别存在 类别不均衡 问题。
5. 使用 sns.distplot() 方法 绘制分布直方图:
# 1) 总体分布概况(无界约翰逊分布等)
y = train['label']
plt.figure(1); plt.title('Default')
sns.distplot(y, rug=True, bins=20)
plt.figure(2); plt.title('Normal')
sns.distplot(y, kde=False, fit=st.norm)
plt.figure(3); plt.title('Log Normal')
sns.distplot(y, kde=False, fit=st.lognorm)
6. 使用 skew() 方法查看 偏度 (skewness), 使用 kurt() 方法查看 峰度 (kurtosis):
# 2)查看skewness and kurtosis
sns.distplot(train['label']);
print(f"Skewness: {train['label'].skew()}")
print(f"Kurtosis: {train['label'].kurt()}")
综上可知,偏度 (skewness) 大于 0,表示数据分布倾向于右偏,长尾在右;峰度 (kurtosis) 小于 0,表示数据分布 与 正态分布相比,较为平坦,为平顶峰。
# 调用 skew() 和 kurt() 方法分别查看偏度和峰度
train.skew(), train.kurt()
# 绘制偏度直方图
sns.distplot(train.skew(), color='green', axlabel ='Skewness')
# 绘制峰度直方图
sns.distplot(train.kurt(), color='purple', axlabel ='Kurtness')
至于为什么要绘制峰度和偏度信息,我猜测,其中一个方面是可以观察数据分布是否服从或接近正态分布;若不服从正态分布但某些任务需要正态分布,则可通过对数变换等数据变换方式改善其正态性。此外,除了直方图,用 P-P 图 或 Q-Q 图 也能判别正态分布。当然,偏度和峰度的应用肯定不止这些,它们诸如量化交易等各种金融数据分析和预测中具有重要作用。
关于 偏度(skewness) 和 峰度(kurtosis) 的相关知识学习
偏度(Skewness)
- 定义
偏度是描述数据总体取值分布的对称性的特征统计量。
- 公式
定义上,偏度是样本的 标准三阶中心矩(standardized 3rd central moment):
其中,X 为样本,n 为样本数,μ 为均值,σ 为标准差。
例如,一组数据为 1、2、2、4、1,均值 μ = 2,标准差 σ≈1.22,则偏度 S 为:
- 性质
偏度需要与正态分布相比较:
偏度 =0 表示其数据分布形态与正态分布的偏斜程度 相同;
偏度 >0 表示其数据分布形态与正态分布相比为 正偏或右偏,即有一条长尾拖在右边,数据右端有较多的极端值,数据均值右侧的离散程度强;
偏度 <0 表示其数据分布形态与正态分布相比为 负偏或左偏,即有一条长尾拖在左边,数据左端有较多的极端值,数据均值左侧的离散程度强;
偏度的绝对值数值越大,代表其分布形态的偏斜程度越大。
- 示例
偏度衡量着数据的不对称程度,无论其值是 0、正数还是负数,都可以显示出有关数据分布形状的信息。
对称或非偏斜分布
数据分布越对称,偏度值越接近零。图 A 显示了正态分布的数据直方图,顾名思义,正态分布数据的偏度相对较小。通过沿正态数据直方图的中间绘制一条中轴线,可很容易地观察到两侧互相构成镜像。但是,没有偏度并不代表就具有正态性。在图 B 展示的分布中,两侧依然互相构成镜像,但这些数据完全不是正态分布。
向右偏斜或正偏斜分布 (positive skewness distribution)
正偏斜或右偏斜的数据之所以这样命名,是因为分布的 “长尾”向右延伸,且其偏度 >0。
偏度实际上是三阶标准中心矩,而一个数据距离“中心”越远,对中心矩的计算影响越大。因此数据长尾在右,即有更多正偏的离群值时,偏度 >0。
例如,薪金数据通常按这种方式偏斜:一家公司中许多员工的薪金相对较低,而少数人员的薪金则非常高。
向左偏斜或负偏斜分布 (negative skewness distribution)
左偏斜或负偏斜的数据之所以这样命名,是因为分布的 “长尾”向左延伸,且其偏度值 <0。
例如,极少数灯泡会立即就烧坏,但大部分灯泡都会持续相当长的时间。
汇总
峰度(Kurtosis / Peakness)
- 定义
峰度,又称峰态系数,表征概率密度分布曲线在平均值处峰值高低的特征数,是描述总体中所有取值分布形态陡缓程度的统计量,是衡量离群数据离群度的指标。直观地,峰度衡量了数据分布的平坦度,反映着峰部的尖度。该统计量需与正态分布对比,表示分布的尾部与正态分布的区别或差异。
- 公式
定义上,峰度是样本的 标准四阶中心矩(standardized 4rd central moment)。随机变量的峰度计算方法为:
其中,X 为样本,n 为样本数,μ 为均值,σ 为标准差。
- 性质
峰度需与正态分布相比较:
通常情况下,对正态分布的峰度值 减 3 得到 超值峰度 (excess kutyosis),以便于让正态分布的峰度为 0。
峰度 =0 表示 该总体数据分布 与 正态分布相比,陡缓程度相同;
峰度 >0 表示 该总体数据分布 与 正态分布相比,较为陡峭,为 尖顶峰;
峰度 <0 表示 该总体数据分布 与 正态分布相比,较为平坦,为 平顶峰。
可见,峰度的绝对值越大,分布形态的陡缓程度与正态分布的差异程度越大,意味着方差的增大是由低频度的大于或小于平均值的极端值引起的。
在实际环境中,若一个分部是 厚尾 的,则这个分布往往比正态分布的尾部 具有更大的 “质量”,即 含有更多的极端值。
- 示例
常峰度 / 基线 (峰度值 ≈0)
完全服从正态分布的数据,其峰度值为 0。正态分布的数据为峰度建立了基准。若样本的峰度值显著偏离 0,则表明数据不服从正态分布。
正峰度 (峰度值 >0)
如上图所示:蓝实线表示正态分布,红虚线表示具有正峰度值的分布。具有正峰度值的分布表明,其相比于正态分布有 “更厚重”的尾部。顾名思义,峰度值越大,分布越形同一座高峰、尖峰。
例如,服从 t 分布的数据具有正峰度值。
负峰度 (峰度值 <0)
如上图所示:蓝实线表示正态分布,红虚线表示具有负峰度值的分布。具有负峰度值的分布表明,其相比于正态分布有 “更轻薄”的尾部。顾名思义,峰度值越小,分布越形同一座矮山、平丘。
例如,服从 Beta 分布的数据具有负峰度值。
汇总
2.3.7 用 pandas_profiling 生成数据报告
pandas_profiling 基于 pandas 的 DataFrame 数据类型,可以快速简单地进行 EDA,例如:
import pandas_profiling
pfr = pandas_profiling.ProfileReport(train) # 自动生成数据分析报告
pfr.to_file("./example.html") # 指定生成的文件名和路径
不一会儿,在保存的路径下点击生成的 HTML 格式报告,就可以在浏览器查看啦。
2.4 后话
总的来说,学习新的知识、锻炼新的能力总比汲汲于调参更重要些。在我看来,这样的学习模式就很好,会引导我学习、思考和组织零碎知识,并作出小结。否则,偷懒成习惯后,学习也仅仅是走马观花,新的知识难免为过眼云烟。就好比上课仅看课本而不做笔记不做题,那么表面上看懂了学会了,其实大部分并没有真懂(小天才例外)。而做笔记的过程其实也是一个学习、思考和复盘的过程,是一个检验知识吸收和消化的步骤。学习过程很重要,但好的总结似乎更重要。
由于能力、精力有限,我的内容其实并不丰富,而且很可能我有错的,如有发现请不吝赐教啦 ^ o ^
参考文献:
https://github.com/datawhalechina/team-learning
https://zhuanlan.zhihu.com/p/84614017
https://www.sohu.com/a/125526669_609133
http://www.voidcn.com/article/p-eejzhhpb-bxr.html
https://support.minitab.com/zh-cn/minitab/18/help-and-how-to/statistics/basic-statistics/supporting-topics/data-concepts/how-skewness-and-kurtosis-affect-your-distribution/
最后
以上就是拼搏手链为你收集整理的【数据挖掘】心跳信号分类预测 之 数据分析 —— 学习笔记(二)二、数据分析的全部内容,希望文章能够帮你解决【数据挖掘】心跳信号分类预测 之 数据分析 —— 学习笔记(二)二、数据分析所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复