依赖加载:
import warningswarnings.filterwarnings('ignore') # 过滤各种不会影响正常运行的警告 import pandas as pdfrom pandas import DataFrame, Seriesimport missingno as msnoimport numpy as npimport scipy.stats as stimport seaborn as snsimport matplotlib.pyplot as plt 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 -> DataFrametrain = pd.DataFrame(np.array(train_list)) # 特征名构造 id + s_0 ~ s_205 + labeltrain.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() 仅返回 值的总数、唯一值数量、出现次数最多的值及其出现次数 (毕竟非数值型的特征可统计的内容不多)。如下自定义示例:
# 自定义示例 - 非数值型 Seriesobject_series = pd.Series(['c', 'c', 'c', 's', 's', np.nan, 'g', 'g', 'o', 'o'])object_series.describe()
另一方面,对于 数值-类别混合型 DataFrame 对象,describe() 仅返回 数值型特征列的汇总统计量;若 无数值型特征列,则只显示类别型特征列。如下自定义示例:
# 自定义示例 - 混合型 DataFramehybird_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 kurtosissns.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 分布的数据具有负峰度值。 汇总
pandas_profiling 基于 pandas 的 DataFrame 数据类型,可以快速简单地进行 EDA,例如:
import pandas_profiling pfr = pandas_profiling.ProfileReport(train) # 自动生成数据分析报告pfr.to_file("./example.html") # 指定生成的文件名和路径不一会儿,在保存的路径下点击生成的 HTML 格式报告,就可以在浏览器查看啦。
总的来说,学习新的知识、锻炼新的能力总比汲汲于调参更重要些。在我看来,这样的学习模式就很好,会引导我学习、思考和组织零碎知识,并作出小结。否则,偷懒成习惯后,学习也仅仅是走马观花,新的知识难免为过眼云烟。就好比上课仅看课本而不做笔记不做题,那么表面上看懂了学会了,其实大部分并没有真懂(小天才例外)。而做笔记的过程其实也是一个学习、思考和复盘的过程,是一个检验知识吸收和消化的步骤。学习过程很重要,但好的总结似乎更重要。
由于能力、精力有限,我的内容其实并不丰富,而且很可能我有错的,如有发现请不吝赐教啦 ^ 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/
免责声明:本文系网络转载或改编,未找到原创作者,版权归原作者所有。如涉及版权,请联系删