交叉表
交叉表(cross-tabulation, 简称crosstab)是一种用于计算分组频率的特殊透视表:
# 按照class_id分组,针对不同的gender,统计数量 print(pd.crosstab(data.class_id, data.gender, margins=True))
c.汇总数据描述
describe()函数
可以计算有关Series或DataFrame列的各种汇总统计信息(当然不包括NaN)
import numpy as np import pandas ad pd series = pd.Series(np.random.randn(1000)) series[::2] = np.nan series.describe()
您可以选择特定的百分位数以包含在输出中,默认情况下,始终包含中位数。
series.describe(percentiles=[.05, .25, .75, .95])
请注意,在混合类型的DataFrame对象上,describe()会将摘要限制为仅包括数字列,如果没有,则仅包括分类列:
frame = pd.DataFrame({'a': ['Yes', 'Yes', 'No', 'No'], 'b': range(4)}) frame.describe()
可以通过提供类型列表作为include/ exclude 参数来控制此行为。
frame.describe(include=['object']) frame.describe(include=['number'])
d.最小值/最大值的索引
Series和DataFrame上的idxmin()和idxmax()函数使用最小和最大对应值计算索引标签
s1 = pd.Series(np.random.randn(5)) s1.idxmin(), s1.idxmax() df1 = pd.DataFrame(np.random.randn(5, 3), columns=['A', 'B', 'C']) df1.idxmin(axis=0) df1.idxmax(axis=1)
当有多个行(或列)的最小值或最大值的匹配,idxmin()并idxmax()返回第一匹配指数
df3 = pd.DataFrame([2, 1, 1, 3, np.nan], columns=['A'],index=list('edcba')) df3 df3['A'].idxmin()
idxmin和idxmax被称为NumPy里的argmin和argmax。
e.数值型特征的描述性统计
方法 | 描述 |
count() |
非空值数目 |
sum() |
价值总和 |
mean() |
均值 |
median() |
算术值中位数 |
min() |
最小值 |
max() |
最大值 |
std() |
样本标准偏差 |
var() |
样本方差 |
skew() |
样品偏斜 |
kurt() |
峰度样本 |
quantile() |
样本分位数(%的值) |
cov() |
样本协方差 |
corr() |
样本相关性 |
ptp() |
极差 |
sem() |
标准误差 |
mad() |
平均绝对离差 |
f.类别型特征的描述性统计
描述类别型特征的分布状况,可以使用频数统计表。pandas库中实现频数统计的方法为 value_counts。
语法:
Series.value_counts(normalize = False,sort = True,升序= False,bins = None,dropna = True) DataFrame.value_counts(subset=None, normalize=False, sort=True, ascending=False)
参数 | 说明 |
normalize | 布尔值,默认为False。如果为True,则返回的对象将包含唯一值的相对频率。 |
sort | 布尔值,默认为True。按频率排序 |
ascending | 布尔值,默认为False。升序排列 |
bins | int,默认为None |
dropna | bool,默认为True |
subset | list-like, 计算唯一组合时要使用的列 |
data = np.random.randint(0, 7, size=50) data s = pd.Series(data) s.value_counts() pd.value_counts(data)
g.方法摘要
data.head()
查看数据前5行
data.tail()
查看数据倒数5行
data.info()
查看数据信息详情
pandas.Series.rename()
重命名
7.数据加载
pandas支持许多不同的文件格式或数据源(csv,excel,sql,json,parquet等),每种格式都有前缀[read_*]。[read_*]函数用来读取数据到熊猫,所述 [to_*]方法被用于存储数据,[to_excel()]方法将数据存储为excel文件。
a.读取csv文件
读取csv文件:
pandas.read_csv(filepath_or_buffer, sep=’,’, header=’infer’, names=None, index_col=None, dtype=None, engine=None, nrows=None)
方法参数 | 参数解释 |
filepath_or_buffer | 接收string,代表文件路径,无默认,该字符串可以是一个URL,有效的URL方案包括http, ftp,s3和file |
sep | 接收string。代表分隔符。read_csv默认为“ , ” ,read_table默认为制表符“[Tab]” 。 |
header | 接收int或sequence。表示是否将某行数据作为列名。默认为infer,表示自动识别。 |
names | header=None 时设置此字段使用列表初始化列名。 |
index_col | 接收int、sequence或False。表示选择哪列作为行索引,取值为sequence则代表多重索引。默 认为None。 |
usecols | 选择读取文件中的某些列。设置为为相应列的索引列表。 |
skiprows | 跳过行。可选择跳过前n行或给出跳过的行索引列表。 |
encoding | 编码。encoding代表文件的编码格式,常用的编码有utf-8、utf-16、gbk、gb2312、gb18030等。如果编 码指定错误数据将无法读取,IPython解释器会报解析错误。 |
写入文本:
DataFrame.to_csv(path_or_buf=None, sep=’,’, na_rep=”, columns=None, header=True,index=True,index_label=None,mode=’w’,encoding=None)
参数名称 | 说明 |
path_or_buf | 接收string。代表文件路径。无默认。 |
sep | 接收string。代表分隔符。默认为“ , ” 。 |
na_rep | 接收string。代表缺失值。默认为“” 。 |
columns | 接收list。代表写出的列名。默认为None。 |
header | 接收boolean,代表是否将列名写出。默认为 True。 |
index | 接收boolean,代表是否将行名(索引)写 出。默认为True。 |
index_labels | 接收sequence。表示索引名。默认为None。 |
mode | 接收特定string。代表数据写入模式。默认 为w。 |
encoding | 接收特定string。代表存储文件的编码格式。 默认为None。 |
b.处理JSON
读取json:
pd.read_json('Filename.json')
方法参数 | 参数解释 |
filepath_or_buffer | 文件路径 |
encoding | 编码。 |
写入json:to_json()
方法参数 | 参数解释 |
filepath_or_buffer | 文件路径; 若设置为None,则返回json字符串 |
orient | 设置面向输出格式:[‘records’, ‘index’, ‘columns’, ‘values’] |
data = {'Name':['Tom', 'Jack', 'Steve', 'Ricky'],'Age':[28,34,29,42]} df = pd.DataFrame(data, index=['s1','s2','s3','s4']) df.to_json(orient='records')
c.文本文件读取
使用read_table来读取文本文件
pandas.read_table(filepath_or_buffer, sep=’\t’, header=’infer’, names=None, index_col=None, dtype=None, engine=None, nrows=None)
方法参数 | 参数解释 |
filepath_or_buffer | 接收string,代表文件路径,无默认,该字符串可以是一个URL,有效的URL方案包括http, ftp,s3和file |
sep | 接收string。代表分隔符。read_csv默认为“ , ” ,read_table默认为制表符“[Tab]” 。 |
header | 接收int或sequence。表示是否将某行数据作为列名。默认为infer,表示自动识别。 |
names | header=None 时设置此字段使用列表初始化列名。 |
index_col | 接收int、sequence或False。表示选择哪列作为行索引,取值为sequence则代表多重索引。默 认为None。 |
usecols | 选择读取文件中的某些列。设置为为相应列的索引列表。 |
skiprows | 跳过行。可选择跳过前n行或给出跳过的行索引列表。 |
encoding | 编码。encoding代表文件的编码格式,常用的编码有utf-8、utf-16、gbk、gb2312、gb18030等。如果编 码指定错误数据将无法读取,IPython解释器会报解析错误。 |
读取Excel文件
pandas.read_excel(io, sheet_name=0, header=0, names=None, index_col=None, usecols=None, squeeze=False, dtype=None)
读取excel文件需要先安装xlrd库
pip install xlrd
8.数据清洗
a.检测与处理重复值
duplicated()函数
数据量较大,可以用duplicated()函数来查询重复的内容:
# 查询重复的内容 data[data.duplicated()] # 统计重复行的数量 data.duplicated.sum() # 发现有重复行时,可以用drop_duplicates()函数删除重复行 data = data.drop_duplicates()
pandas提供了一个名为drop_duplicates的去重方法。该方法只对DataFrame或者Series类型有效。这种方法不会改变数据原始排列,并且兼具代码简洁和运行稳定的特点。该方法不仅支持单一特征的数据去重,还能够依据DataFrame的其中一个或者几个特征进行去重操作。
DataFrame.drop_duplicates(subset=None, keep='first', inplace=False, ignore_index=False)
参数名 | 说明 |
subset | 接收string或sequence。表示进行去重的列。默认为None,表示全部列。 |
keep | 接收特定string。表示重复时保留第几个数据。first:保留第一个。last:保留最后一个。false:只要有重复都不保留。默认为first。 |
inplace | 接收boolean。表示是否在原表上进行操作。默认为False。 |
示例:
import pandas as pd data=pd.DataFrame( {'A':[1,1,2,2],'B':['a','b','a','b']}) data.drop_duplicates('A', 'first', inplace=True) data
b.检测与处理缺失值
数据中的某个或某些特征的值是不完整的,这些值称为缺失值。
pandas提供了识别缺失值的方法isnull()函数或isna()函数(两者作用类似)以及识别非缺失值的方法notnull(),这两种方法在使用时返回的都是布尔值True和False。
isnull()函数的作用是判断是否是空值,若是空值就赋予True,否则赋予False。
结合sum函数和isnull、notnull函数,可以检测数据中缺失值的分布以及数据中一共含有多少缺失值。isnull和notnull之间结果正好相反,因此使用其中任意一个都可以判断出数据中缺失值的位置。
data.isnull() # 或者写成data.isna() data.isnull().sum() # 共有多少各缺失值
1)删除法
删除法分为删除观测记录和删除特征两种,pandas中提供了简便的删除缺失值的方法dropna,该方法既可以删除观测记录,亦可以删除特征。
pandas.DataFrame.dropna( self, axis=0, how='any', thresh=None, subset=None, inplace=False)
参数名 | 说明 |
axis | 接收0或1。表示轴向,0为删除记录(行),1为删除特征(列)。默认为0。 |
how | 接收特定string。表示删除的形式。any表示只要有缺失值存在就执行删除操作。all表示当且仅当全部为缺失值时执行删除操作。默认为any。 |
subset | 接收类array数据。表示进行去重的列∕行。默认为None,表示所有列/行。 |
inplace | 接收boolean。表示是否在原表上进行操作。默认为False。 |
示例:
dates = pd.date_range('20130101', periods=6) df = pd.DataFrame(np.arange(24).reshape((6,4)),index=dates, columns=['A','B','C','D']) df.iloc[0,1] = np.nan df.iloc[1,2] = np.nan # df1接收,判断是否有缺失数据 NaN, 为 True 表示缺失数据: df1=df.isnull() df1 #每一列的缺失数据 df2=df.isnull().sum() df2 #整个表的缺失数据 df2.sum() # df1接收,去掉有 NaN 的行, 可以使用 dropna 一旦出现NaN就去除整行 df3=df.dropna(axis=0,how='any') df3
2)替换法
替换法是指用一个特定的值替换缺失值。
特征可分为离散型和连续型,两者出现缺失值时的处理方法也是不同的。
缺失值所在特征为连续型时,通常利用其均值、中位数和众数等描述其集中趋势的统计量来代替缺失值。缺失值所在特征为离散型时,则经常选择使用众数来替换缺失值。
插补方法 | 方法描述 |
均值/中位数/众数插补 | 根据属性值的类型用该属性取值的平均数/中位数/众数进行插补 |
使用固定值 | 将缺失的属性值用一个常量替换。 |
最近临插补 | 在记录中找到与缺失样本最接近的样本的该属性值插补 |
回归方法 | 对带有缺失值的变量,根据已有数据和与其有关的其他变量(因变量)的数据建立拟合模型来预测缺失的属性值 |
插值法 | 插值法是利用已知点建立合适的插值函数f(x),未知值由对应点x求出的函数值f(x)近似代替 |
data = data.fillna(data.mean()) data = data.fillna(data.median())
pandas库中提供了缺失值替换的方法名为fillna,其基本语法如下:
pandas.DataFrame.fillna(value=None, method=None, axis=None, inplace=False, limit=None)
常用参数及其说明如下:
参数名 | 说明 |
value | 接收scalar,dict,Series或者DataFrame。表示用来替换缺失值的值。无默认。 |
method | 接收特定string。backfill或bfill表示使用下一个非缺失值填补缺失值。pad或ffill表示使用上一个非缺失值填补缺失值。默认为None。 |
axis | 接收0或1。表示轴向。默认为1。 |
inplace | 接收boolean。表示是否在原表上进行操作。默认为False。 |
limit | 接收int。表示填补缺失值个数上限,超过则不进行填补。默认为None。 |
案例:
# df2接收,如果是将 NaN 的值用其他值代替, 比如代替成 0: dates = pd.date_range('20130101', periods=6) df = pd.DataFrame(np.arange(24).reshape((6,4)),index=dates, columns=['A','B','C','D']) df.iloc[0,1] = np.nan df.iloc[1,2] = np.nan # 固定值填补 df2=df.fillna(value=0) df2 # 相似值填补 df3=df.fillna(method='pad', axis=1) df3 # 还可以设置method='backfill'或method='bfill',表示用空值下方的值来替换空值,如果下方的值不# 存在或也为空值,则不替换。
3)插值法
删除法简单易行,但是会引起数据结构变动,样本减少;替换法使用难度较低,但是会影响数据的标准差,导致信息量变动。在面对数据缺失问题时,除了这两种方法之外,还有一种常用的方法—插值法。
scipy提供了插值算法可以通过一组散点得到一个符合一定规律插值器函数。这样当我们给插值器函数更多未知x,插值函数将会返回相应的y用于填补缺失值。
需求:统计各小区彩民买彩票的情况:
彩民数量 | 彩票购买量 |
30 | 100注 |
40 | 120注 |
50 | 135注 |
60 | 155注 |
45 | - |
65 | 170注 |
scipy提供的插值方法如下:
import scipy.interpolate as si func = si.interp1d( 离散水平坐标, 离散垂直坐标, kind=插值算法(缺省为线性插值) )
案例:
import numpy as np import matplotlib.pyplot as mp import scipy.interpolate as si x = [30, 40, 50, 60, 65] y = [100, 120, 135, 155, 170] mp.scatter(x, y) xs = np.linspace(min(x), max(x), 200) # 通过这些散点,构建一个线性插值函数 linear = si.interp1d(x, y, kind='cubic') print(linear(45)) ys = linear(xs) mp.plot(xs, ys) mp.show()
c.检测与处理异常值
异常值是远离大部分样本数据的数据值,异常值产生的原因可能是录入错误或偶然因素。通常情况下,数据样本中的异常值属于需要清理的数据,但在某些特定的情况下,异常值也有它存在的意义。
异常值:是指数据中个别值的数值明显偏离其余的数值,有时也称为离群点,检测异常值就是检验数据中是否有录入错误以及是否含有不合理的数据。
异常值是指一组数据中偏离平均值两倍标准差的数据,而偏离平均值3倍标准差以上的数据则成为高度异常值,我们通常对高度异常值更感兴趣。
异常值的存在对数据分析十分危险,如果计算分析过程的数据有异常值,那么会对结果会产生不良影响,从而导致分析结果产生偏差乃至错误。
从广义上说,不仅存在数值型异常值,某些字符型数据中也同样存在异常值,如正常邮件中夹杂的垃圾邮件或正常交易中夹杂的欺诈交易等,都是异常的。
我们发现异常值后,武断地对其进行删除是绝对不理智的,聪明的数据分析师会谨慎地考虑其背后的含义。尽管一百个数据样本中未必能有一个样本中的异常值是具有特殊意义的,但谨慎总是没错的。
字符型异常值往往比数字型异常值更重要,实际生活中有很多侦测欺诈交易或辨别流失客户的问题。但遗憾的是,发现字符型异常值要比数字型异常值困难得多。
除却其自身的特殊含义外,异常值也是数据样本中不可或缺的一部分。过多的距离数据均值、过远的异常值可能提示我们数据样本的容量太小,难以代表整体数据;极个别的异常值则可能代表的只是偶然情况,不必挂怀。
真实世界是不完美的,从真实世界中收集的数据有许多疏漏和噪声,这也正是为什么我们要花费许多精力在数据预处理上。对于数据样本中的异常值我们没必要赶尽杀绝,在清洗数据时,正确的做法是剔除那些明显错误的数据,保留那些稍有瑕疵的数据,这个度应该根据数据本身的表现去掌握。这样做的好处是让模型尽可能地贴近现实,从而提高预测的精度,毕竟数学模型还是要用来解决现实世界中的实际问题的。
常用的异常值检测主要为3σ原则和箱线图分析两种方法。
1)简单统计量分析
先对变量做一个描述性统计,找出哪些数据是不合理的,最常用的统计量是求最大值和最小值,判断变量是否在这个区间。
2)3σ原则
3σ原则又称为拉依达法则。该法则就是先假设一组检测数据只含有随机误差,对原始数据进行计算处理得到标准差,然后按一定的概率确定一个区间,认为误差超过这个区间的就属于异常值。
这种判别处理方法仅适用于对正态或近似正态分布的样本数据进行处理。如果不符合正态分布,可以用远离平均值的多少倍标准差来表示。
3)箱线图分析
箱线图提供了识别异常值的一个标准,即异常值通常被定义为小于QL-1.5IQR或大于QU+1.5IQR的值。
QL称为下四分位数,表示全部观察值中有四分之一的数据取值比它小。
QU称为上四分位数,表示全部观察值中有四分之一的数据取值比它大。
IQR称为四分位数间距,是上四分位数QU与下四分
位数QL之差,其间包含了全部观察值的一半。
箱线图依据实际数据绘制,真实、直观地表现出了数据分布的本来面貌,且没有对数据做任何限制性要求,其判断异常值的标准以四分位数和四分位数间距为基础。
四分位数给出了数据分布的中心、散布和形状的某种指示,箱形图判断异常值的标准以四分位数和四分位距为基础,箱线图识别异常值的结果比较客观,因此在识别异常值方面具有一定的优越性。
箱线共由五个数值点构成,分别是最小观察值(下边缘),25%分位数(QL),中位数,75%分位数(QU),最大观察值(上边缘)。
特别说明:箱盒图里面的极大值(上边缘值)并非最大值,极小值(下边缘值)也不是最小值。
如果数据有存在离群点即异常值,他们超出最大或者最小观察值,此时将离群点以“圆点”形式进行展示。
异常值的处理方法:
异常值处理方法 | 方法描述 |
删除含有异常值的记录 | 直接删除含有异常值的记录 |
视为缺失值 | 将异常值视为缺失值,按照缺失值方法处理。 |
平均值修正 | 用前后两个观测值的均值进行修正。 |
不处理 | 直接在含有异常值的数据集上进行数据建模。 |
9.pandas可视化
a.基本绘图
Series数据可视化
Series提供了plot方法以index作为x,以value作为y,完成数据可视化:
ts = pd.Series(np.random.randn(10), index=pd.date_range('1/1/2000', periods=10)) ts.plot()
DataFrame数据可视化
DataFrame提供了plot方法可以指定某一列作为x,某一列作为y,完成数据可视化:
df3 = pd.DataFrame(np.random.randn(10, 2), columns=['B', 'C']) df3['A'] = np.arange(len(df3)) df3.plot(x='A', y=['B', 'C'])
b.高级绘图
plot()方法可以通过kind关键字参数提供不同的图像类型,包括:
类型 | 说明 |
bar or barh |
柱状图(条形图) |
hist |
直方图 |
box |
箱线图 |
scatter |
散点图 |
pie |
饼状图 |
line |
折线图 |
area |
面积图 |
kde |
密度估计图(主要对柱状图添加Kernel 概率密度线) |
相关API如下:
# 柱状图 series.plot.bar() dataFrame.plot.bar() dataFrame.plot.barh()
直方图
# 直方图 series.plot.hist(alpha=0.5, bins=5) dataFrame.plot.hist(alpha=0.5, bins=5) # 除了df.hist()函数,还可以使用pandas库中的通用绘图代码绘制图表 dataFrame.plot(kind='hist') dataFrame['column_name'].plot(kind='hist')
散点图
# 散点图 df.plot.scatter(x='a', y='b', c=col, colormap='');
饼状图
# 饼状图 series.plot.pie(figsize=(6, 6)) dataFrame.plot.pie(subplots=True, figsize=(6, 6), layout=(2, 2))
箱线图
# 箱线图 # 先找出一组数据的上边缘、下边缘、中位数和两个四分位数;然后, 连接两个四分位数画出箱体;再将上边缘和下边缘与箱体相连接,中位数在箱体中间 df.plot.box() # 分组箱线图 df.boxplot(by='X')
箱线图反应一组数据的集中趋势,四分位数的差可以反映一组数据的离散情况:
中位数高,表示平均水平较高;反之则表示平均水平较低。
箱子短,表示数据集中;箱子长,表示数据分散。