快速入门python数据分析
本篇文章将介绍数据分析常用的python库和常用的方法,快速入门数据分析
数据分析常用的第三方库为:
- matplotlib:绘图
- numpy:处理数值型数组
- pandas:在numpy基础上能够处理字符串、时间序列、列表、字典......
Matplotlib
一种将数据可视化的python底层绘图库
导库
1 | from matplotlib import pyplot as plt |
绘制折线图
1 | plt.plot(x, y, else) |
必选参数:
- x:传入x轴数据
- y:传入y轴数据
x和y必须一一对应
其他参数:
- marker = 'o' :折线中附带数据点
- color:颜色
- r:红色
- g:绿色
- b:蓝色
- w:白色
- c:青色
- m:洋红
- y:黄色
- k:黑色
- ‘#XXXXXX’:16进制颜色代码
- linestyle:线条
- '-':实线
- '--':虚线
- '-.':点划线
- ':':点虚线
- 无参数:无线条
- linewidth:粗细(数字)
- alpha:透明度(0~1)
图片操作
设置图片大小
1 | plt.figure(figsize=(x, y), dpi=?) |
参数:
- x:图片宽度
- y:图片高度
- dpi:填入数值,为每英寸像素个数,越高越清晰(一般常用80、160...)
保存图片
1 | plt.savefig("保存地址") |
图片后缀:
- png、jpg等
- svg:矢量图,放大无锯齿
图片保存必须放在绘图方法之后
设置坐标轴
1 | # x轴 |
参数
- 填入一个参数
- x:x轴的数据
- 填入两个参数
- x:x轴的数据
- _x:一般为字符串,用来替换x轴的数据(x 和 _x 要一一对应)
例如:
1 | # 画出的图形x轴为1,2,3 |
y同理
其他参数:
- rotation:坐标轴数值逆时针旋转的度数
设置中文
由于matplotlib不支持中文显示,需要设置中文
1 | import matplotlib |
将以上代码插入开头即可显示中文
参数:
- family:中文字体。有以下字体
- KaiTi:楷体
- SimSun:宋体
- SimHei:黑体
- Microsoft YaHei:微软雅黑
- FangSon:仿宋
还有更多字体请查看官方文档
其他参数:
- size:字体大小
- weight='bold':粗体
图表信息
1 | # 设置x轴标签 |
grid()参数:
- alpha:透明度(0~1)
- linestyle:线条种类
- '-':实线
- '--':虚线
- '-.':点划线
- ':':点虚线
- 无参数:无线条
绘制多个图
多写几个plt.plot()
图例
1 | plt.plot(x, y, label='内容1') |
legend()参数:
- loc:图例展示位置
- 0:默认,自动展示在合适的位置
- 1:右上角
- 2:左上角
- 3:左下角
- 4:右下角
- 5:右
- 6:左中
- 7:右中
- 8:中下
- 9:中上
- 10:正中
- fontsize:图例大小
其他图形
散点图:
1 | plt.scatter(x, y) |
条形图:
1 | # 竖着的条形图 |
条形图粗细参数:(默认0.8,范围:0~1;若为1,则条形图连到一起)
竖着的条形图:
- width:粗细
横着的条形图:
- height:粗细
直方图
1 | plt.hist(data, bins) |
参数:
- data:数据列表
- bins:分组
- 数字:分为几组
- 列表:按照列表分组(列表中的数字必须是严格递增)
其他参数:
- normed=1(true):改为频率分布直方图
直方图绘制注意点:
能够绘制的图形:原始的,未经过统计的数据
对于已经统计过的数据:使用条形图,将粗细改为1来cosplay直方图
参考网站
前端绘图网站:ECHARTS
图表网站:plotly
扩展库:seaborn
其他功能和注意事项
坐标轴数值限制
1 | x.lim(min, max) |
对于时间的处理
对带有时间的坐标轴格式化
1 | data.strftime('时间格式') |
注意
绘图时,Period类型的时间数据不能作为坐标轴使用
1 | # 使用以下方法转为datetime类型 |
对坐标轴进行缩放
在今后的数据统计中,常常遇到数值差异巨大的数据,这些数据往往会拔高坐标轴的数值,导致一些数值低的数据不太容易被观察
1 | # 将y轴变为log以10为底的数值,使得坐标轴成指数变化,可以缓解上述问题 |
快速画图
在pandas中,获取了Series数据后,不需要再取出数值和下标画图,可以在数据之后直接加上.plot()来快速画图
1 | # 假设这是Serise数据 |
参数:
- kind:图形种类
- 无参数:默认折线图
- hist:直方图
- bins:组数,同直方图
- bar:条形图
- scatter:散点图
- label:图例
一个画板上画多个图
1 | plt.subplot(三位数字) |
参数:三位数字
- 第一位:行
- 第二位:列
- 第三位:位置
例如:
1 | plt.subplot(221) |
其他图形
饼图
1 | plot.pie() |
参数:
- antopet:格式化比例
1 | # 例如:'%1.1f%%' 则饼图上的比例为 eg: 30.5% |
- explode:数值列表,表示饼的各个部分与其他部分的间隔距离
- 例如:[0.02,0.05,0.02] 列表长度就是饼图有几个部分,要一一对应
- wedgeprops={'linewidth':线宽, 'edgecolor':边沿颜色}
- shadow=true:开启阴影
面积图
1 | plot.area() |
可以将DataFrime作为数据直接绘制面积图
绘制直线
1 | # 水平线 |
附加内容
1 | plt.text(x, y, '内容', color='', fontsize=) |
热力图
需要导入seaborn
1 | import seaborn as sns |
一般结合corr相关系数来绘制
1 | sns.heatmap(data='相关系数', cmap='色值', annot='是否显示数值', vmax='最大值', vmin='最小值', linewidths='每个方格间距') |
如果设置过中文字体,会导致负号乱码,则需要进行局部字体设置
1 | plt.rcParams['font.family'] = 'Arial' |
Numpy
用于处理大型数组的python库
导库
1 | import numpy as np |
创建数组
1 | # 三种创建方式 |
创建之后的数据类型为:numpy.ndarray
存储类型:
整数:int64/int32(根据计算机的位数决定)
小数:float64
numpy的数据类型:
| 类型 | 类型代码 | 说明 |
|---|---|---|
| 整型 | ||
| int_ | i |
默认整数类型(通常为 int32 或 int64) |
| int8 | b |
8 位有符号整数 (-128 到 127) |
| int16 | h |
16 位有符号整数 |
| int32 | i |
32 位有符号整数 |
| int64 | l |
64 位有符号整数 |
| uint8 | B |
8 位无符号整数 (0 到 255) |
| uint16 | H |
16 位无符号整数 |
| uint32 | I |
32 位无符号整数 |
| uint64 | L |
64 位无符号整数 |
| 浮点型 | ||
| float_ | f |
默认浮点数类型(通常为 float64) |
| float16 | e |
半精度浮点数 |
| float32 | f |
单精度浮点数 |
| float64 | d |
双精度浮点数 |
| float128 | g |
扩展精度浮点数(非所有平台支持) |
| 复数 | ||
| complex_ | F |
默认复数类型(通常为 complex128) |
| complex64 | F |
单精度复数 |
| complex128 | D |
双精度复数 |
| complex256 | G |
扩展精度复数(非所有平台支持) |
| 布尔型 | ||
| bool_ | ? |
布尔值 (True 或 False) |
| 字符串 | ||
| str_ | U |
Unicode 字符串 |
| string_ | S |
固定长度的字节字符串 |
| 对象 | ||
| object_ | O |
Python 对象 |
| 时间间隔 | ||
| timedelta64 | m |
时间差值 |
| 日期时间 | ||
| datetime64 | M |
日期时间类型 |
| 用户定义 | ||
| void | V |
用户定义的复合类型 |
手动制定数据类型
1 | np.array(数据, dtype='类型') |
取小数
1 | # 取0~1的小数 |
数组形状(多维数组)
1 | # 输出维度 |
取出行列数
1 | shape[0] # 取出行数 |
形状重组
1 | 数组.reshape((num, num, .....)) |
有返回值,且不改变原值
展开数组
1 | 数组.flatten() |
将数组展开成一维形式
转置
1 | 数组.transpose() |
有返回值,且不改变原值
数值计算
异常值:
- nan:不是一个数
- inf:无穷,除零操作会出现这个数
异常值赋值
np.nan:float类型
数组与数字计算:
数组中每一个值都与数字进行计算
数组与数组计算:
两数组形状相同:两数组的对应位置计算
两数组形状不同,但是行/列相同:则行/列互相计算
行列都不相同则报错
广播原则
数组可以和末位维度的轴相同或者缺失为1的维度进行计算
例如:shape(3, 4, 5)的数组
从后往前看:分别是5,4,3
值为5的维度:
则能和shape(3, 4, 5)计算的是:
轴相同:shape(5, )
最低维度,不能缺失1
值为4的维度:
则能和shape(3, 4, 5)计算的是:
轴相同:shape(4, 5)
5缺失为1:shape(4, 1)
值为3的维度:
则能和shape(3, 4, 5)计算的是:
轴相同:shape(3, 4, 5) —— 相同图形
缺失为1:
- 5缺失为1:shape(3, 4, 1)
- 4缺失为1:shape(3, 1, 5)
- 4、5都缺失:shape(3, 1, 1)
轴(axis)
一维:axis=0
- 表示个数
二维:axis=0,axis=1
- 0:行
- 1:列
三维:axis=0,axis=1,axis=2
- 0:块/组
- 1:行
- 2:列
numpy读取数据
读取数据一般都是pandas来读取,但是了解一下numpy也有数据读取功能
1 | np.loadtxt(filename) |
参数:
- filename:文件位置
- dtype:读取为什么类型
- delimiter:以什么作为分隔
- skiprows:跳过多少行
- usecols:读取哪些列
- unpack:是否转置
numpy索引和切片
numpy取值
取行
1 | # 对于数据t |
取行切片
1 | t[start: end] |
取独立多行
1 | t[[行1, 行2, ....]] |
取列
1 | t[:, 列索引] |
取连续多列
1 | t[:, start: end] |
取独立多列
1 | t[:, [列1, 列2, ....]] |
取某个独立值
1 | t[2, 3] |
取多个独立值
1 | t[[0, 2], [3, 4]] |
numpy赋值
取出某个数据,某行/列数据赋值即可
在numpy取值的基础上,在后面进行赋值即可
布尔索引
使用数组索引进行逻辑判断
1 | # 对于数据t |
使用布尔索引赋值
1 | # 对于数据t |
三元运算
where
1 | np.where(t<10, 0, 10) |
裁剪
1 | t.clip(10, 18) |
数组操作
数组拼接
拼接前要先将数组内容改为统一类型
竖直拼接
1 | np.vstack((数据, 数据)) |
水平拼接
1 | np.hstack((数据, 数据)) |
数组行列交换
1 | # 行交换 |
特殊数组
全0数组
1 | np.zeros((行, 列)) |
全1数组
1 | np.ones((行, 列)) |
单位矩阵E(对角线全为1,其余全为0)
1 | # 单位矩阵是方阵,行列相同 |
统计非零数据的个数
1 | np.count_nonzero(数据) |
补充
获取最大值与最小值的位置
1 | np.argmax(数据, 轴) |
若不输入轴,则返回数组中的最大值
当axis=0时,找出每列的最大/小值,返回所在行的小标
由于返回值形状为一行,所以axis=0
当axis=1时,找出每行的最大/小值,返回所在列的小标
由于返回值形状为一列,所以axis=1
copy
1 | a = b # 或者 a = b[:] |
numpy生成随机数
| 函数 | 解释 |
|---|---|
np.random.rand(d0, d1, ..., dn) |
创建一个给定形状的数组,其中填充的是 [0, 1) 区间内的均匀分布随机数。 |
np.random.randn(d0, d1, ..., dn) |
创建一个给定形状的数组,其中填充的是标准正态分布(均值为 0,标准差为 1)的随机数。 |
np.random.randint(low, high=None, size=None, dtype=int) |
返回一个从低(包含)到高(不包含)的随机整数。如果 high
未提供,则返回从 0 到
low(不包含)的随机整数。 |
np.random.random_sample(size=None) |
返回一个或多个 [0, 1) 区间内的随机浮点数。 |
np.random.uniform(low=0.0, high=1.0, size=None) |
从均匀分布中抽取样本,范围是 [low, high)。 |
np.random.normal(loc=0.0, scale=1.0, size=None) |
从正态(高斯)分布中抽取样本,均值为 loc,标准差为
scale。 |
随机数种子
1 | np.seed(num) |
使用之后,重复执行程序,生成的随机数都是一样的
nan和inf
nan(not a number):np.nan
float类型,两个nan不相等
当读取本地文件为float时,若确实则为nan
无穷与无穷进行不适当的运算时
inf(infinity):np.inf
- float类型
- inf:+∞
- -inf:-∞
- 除零运算时出现
应用
取出不为nan的数
1 | # 利用两个nan不相等特性 |
统计nan个数
1 | # 利用两个nan不相等特性 |
判断是否为nan
1 | # 对于数据t |
任何数值和nan计算都等于nan
1 | # t中含有nan |
numpy统计函数
1 | # 假设有数据t |
上述函数都可指定轴
如:
1 | np.sum(t, axis=0) |
在数据统计时要酌情考虑nan对数值的影响
把nan赋值为0,会影响均值和其他值
可以将nan赋值为均值或中位数
Pandas
高性能数据分析工具,在Numpy的基础上,处理的数据类型更多
Numpy的方法也能和pandas一起使用
数据类型:
- Series:一维(带标签的数组,像字典)
- DataFrame:二维(类似Series容器)
导库
1 | import pandas as pd |
Series
创建Series
1 | pd.Series([....]) |
类型:pandas.core.series.Series
取值(尽量使用loc和iloc,后面会讲到)
1 | # 取一个 |
取下标
1 | t.index |
取值
1 | t.values |
ndarray中的很多方法也适用于Series,如:where,clip等
对下标重命名
1 | t.name = '新名称' |
DataFrame
文件读取
多列文件存储于DataFrame中
1 | # 读取csv文件,parse_dates可以指定对应的列,直接转为datetime类型 |
创建DataFrame
1 | pd.DataFrame(数据, index=[左索引(位置)], columns=[上索引(列名)]) |
index:不同行,axis=0
columns:不同列,axis=1
与Series的关系:DataFrame的每一行/列都是Series
DataFrame方法
1 | t.index # 行索引 |
排序
1 | # 有数据集df |
取值
1 | # 取行列 |
布尔索引
1 | t[t['列'] + 逻辑判断] # 产生条件筛选数据 |
Pandas字符串方法
用法:数据.str.方法
| 方法 | 说明 |
|---|---|
| cat | 实现元素级的字符串连接操作,可指定分隔符 |
| contains | 返回表示各字符串是否含有指定模式的布尔型数组 |
| count | 模式的出现次数 |
| endswith、startswith | 相当于对各个元素执行x.endswith(pattern)或x.startswith(pattern) |
| findall | 计算各字符串的模式列表 |
| get | 获取各元素的第i个字符 |
| join | 根据指定的分隔符将Series中各元素的字符串连接起来 |
| len | 计算各字符串的长度 |
| lower、upper | 转换大小写,相当于对各个元素执行x.lower()或x.upper() |
| match | 根据指定的正则表达式对各个元素执行re.match |
| pad | 在字符串的左边、右边或者左右两个添加空白符 |
| center | 相当于pad(side='both') |
| repeat | 重复值。例如:s.str.repeat(3)相当于对各个字符串执行x*3 |
| replace | 用指定字符串替换找到的模式 |
| slice | 对Series中的各个字符串进行子串截取 |
| split | 根据分隔符或正则表达式对字符串进行拆分 |
| strip、rstrip、Istrip | 去除空白符,包括换行符。相当于对各个元素执行x.strip()、x.rstrip()、x.Istrip() |
利用集合不重复的特性获取去重后的数据
1 | # 获取一维不重复 |
缺失值处理
所谓缺失值:空、None、NaN、NAT(日期类型缺失值)、'0'
判断是否为NAN
1 | pd.isnull(数据) / pd.notnull(数据) |
删除数据
使用bool索引删除
1 | # 数据t |
dropna
1 | pd.dropna(axis=?, how='?', inplace=?) |
参数:
- axis:选择行(0),选择列(1)
- how:删除方式
- all:只有某行/列全为NaN才删
- any:只要某行/列有一个NaN就删(默认)
- inplace:True表示原地修改,不需要自我赋值(默认False)
drop
与dropna的区别:drop可以自由选择删除某一列/行
1 | pd.drop('索引', axis=?, inplace=?) |
删除重复数据
1 | t.drop_duplicates(keep='first', inplace=) |
填充数据
1 | # 填充NaN |
数据合并
join
把行索引相同的合并到一起,列索引不能相同,否则报错
左.join(右):最后形状以左边为主,多的删除,少的补NaN
1 | ''' |
merge
把列索引及其内容相同的合并到一起(默认取交集inner)
左.merge(右)
pd.merge(left=左表, right=右表, on=/left_on=, right_on=, how=, suffixes=())
- left:左表
- right:右表
- on:若两表有相同的列索引则使用
- left_on, right_on:若两表都没有相同的列索引,则分别指定左右表的匹配字段
- how:匹配模式
- inner:交集(默认)
- outer:并集
- left:左补全
- right:右补全
- suffixes=('左表名称', '右表名称'):若除了指定列之外还有字段名称相同的字段,则自定义左右表的名称后缀,填入的内容为元组
1 | """ |
★分组★
将数据中的某个或某多个字段分组,分组后,被分组的字段自动去重
分组后的数据为长度为2的元组,元组内容为grouped=(分组名,DataFrame类型数据)
1 | # 数据t |
分组后的数据可以遍历
1 | # 遍历整个元组 |
常用组合:
1 | # 组合一: |
常用方法:
1 | .count() # 计数 |
多列分组:
1 | .groupby(by=['列1', '列2']) |
同一个数据,如何取出Series和DataFrame呢?
答案就是一个[]取出的是Series,两个[]取出来的就是DataFrame
原理:嵌套[]表示取多列
- type(t['a']) --> Series
- type(t[['a']]) --> DataFrame
agg()聚合
分组后聚合
1 | t.groupby('列').agg(['min', 'max']) |
索引和复合索引
1 | # 获取索引 |
若只有一列:
t[X]:默认行索引
若有多列:
t[X]:默认列索引,若要取行要用t.loc
复合索引展开
.unstack方法
1 | ''' |
若有多个符合索引,则会将最低维的索引作为列索引
Pandas时间序列
生成连续时间:
1 | pd.date_range(start='开始时间', end='结束时间', period=生成个数, freg='频率') |
- start和end:再开始时间和结束时间生成频率为freg的时间序列
- start和period:从开始时间生成period个的频率为freg的时间序列
- freg:频率,前面可以加数字,表示多少天/月
- D:天
- M:月
1 | # 例如 |
| 别名 | 偏移量类型 | 说明 |
|---|---|---|
| D | Day | 每日历日 |
| B | BuslnessDay | 没工作日 |
| H | Hour | 每小时 |
| T或min | Minute | 每份 |
| S | Second | 每秒 |
| L或ms | Milli | 每毫秒(千分之一秒) |
| U | Micro | 每微秒(百万分之一秒) |
| M | MonthEnd | 每月最后一个日历日 |
| BM | BusinessMonthEnd | 每月最后一个工作日 |
| MS | MonthBegin | 每月第一个日历日 |
| BMS | BusinessMonthBegin | 每月第一个工作日 |
时间格式:X年X月X日 X时X分X秒
时间类型转换
1 | pd.to_datetime(数据, format='') |
format:不填参数也可以,如果格式标准可以自动识别
- 例如:%Y-%m-%d %H%M%S %p
时间格式:
| 格式 | 说明 |
|---|---|
| %y | 两位数的年份表示(00-99) |
| %Y | 四位数的年份表示(0000-9999) |
| %m | 月份(01-12) |
| %d | 月内的一天(0-31) |
| %H | 24小时制(0-23) |
| %I | 12小时制(0-12) |
| %M | 分钟数(00-59) |
| %S | 秒(00-59) |
| %a | 本地简化星期名称 |
| %A | 本地完整星期名称 |
| %b | 本地简化月份名称 |
| %B | 本地完整月份名称 |
| %c | 本地相应的日期表示和时间表示 |
| %j | 年内的一天(001-366) |
| %p | 本地A.M. 或P.M.的等价符 |
| %U | 一年中的星期数(00-53)星期天为星期的开始 |
| %w | 星期(0-6)星期天为星期的开始 |
| %W | 一年中的星期数(00-53)星期一为星期的开始 |
| %x | 本地相应的日期表示 |
| %X | 本地相应的时间表示 |
| %Z | 当前时区的名称 |
| %% | %号本身 |
重采样
将时间序列从一个频率转为另一个频率处理的过程
高频-->低频:降采样(从秒-->天)
低频-->高频:升采样(从天-->秒)
被采样的对象必须是索引index,且类型为Datetime
resample方法
相当于时间上的groupby
1 | t.resample('字段') |
跟groupby一样,后面可以跟count和mean等进行聚合
时间格式化
1 | .strftime('format') |
分段时间合并为一个时间
有些数据时间数据不是写在一起,可能年放一列,月放一列,日期放一列
1 | pd.PeriodIndex.from_fields(year=t[列], month=t[列], dat=[列], ...., freg='频率') |
生成的数据类型为:PeriodIndex类型,一般转为datetime类型
Period转Datetime
1 | t.to_timestamp() |
时间转换
如何将 1998-01-01 ----> 1998-01
- 时间数据.dt.to_period('M') 将最低单位变为月份
对比:
- 时间数据.dt.month:只取月份,没有年份和天
- 时间数据.dt.day:只取天,没有月份和年
- ...
如何取出天/月数
如果单纯使用时间格式的数据相减,则得到的数据还是datetime格式
如果想得到int类型的天/月数,需要除以时间单位 np.timedelta64()
1 | (date1 - date2) / np.timedelta64(1, 'D') |
透视表
一种强大的分析方法
- 灵活性高,可以随意定制你的分析计算要求
- 脉络清晰易于理解数据
- 操作性强,报表神器
pivot_table
1 | # 每个pivot_table都必须有一个index |
其他
np的mean()比pd的mean()快
因为np的mean()底层是C++写的
count()和value_counts()
同一列数据
count()会给你这一列数据有多少个数据(计数)
而value_counts()会帮你列出这一列数据中,每个数据出现的次数(自动分组计数功能)
注意:value_counts()只用于Series,这就是为什么一开始强调是 同一列 数据
apply()和map()
区别:
- apply:作用于整行/列
- map:作用于每一个数据(Series类型)
用法:
apply()和map()里面都可以放 lambda表达式 和函数,而apply在放函数时要加轴
注意:
1 | # 1:apply(func(x), axis=) X |
axis = 0 , 取出每一行的一个数据组成一列传入
axis = 1 ,取出每一列的一个数据组成一行传入
count()、sum() 和 NaN、0
对一个数据
- count():NaN不计数,但0计数
- sum():0不算入(因为0+任何数 值不变),有NaN结果全为NaN
一般会用在计算个别数和总数,用0和非0数区别开
shift(axis=)
移动数据
- axis=0:向下推一行(默认)
- axis=1:向右推一列
1 | t: |
可以进行错位计算
cut()分组
设置分组后,对数据应用该函数,得出数据落在哪个分组
1 | bins=[25, 59, 70, 85, 100] |
np.all()
判断迭代器内的值是否相同
1 | np.all(['true', 'true', 'true']) -----> true |
用于判断多个列内的数据是否一一对应
相关项目
总结
这些是数据分析常用的方法,后续如果有其他需要,请自行查找官方文档
有什么问题,或者对项目有疑惑的可以在左侧资料框的Email联系我