快速入门python数据分析

本篇文章将介绍数据分析常用的python库和常用的方法,快速入门数据分析

数据分析常用的第三方库为:

  • matplotlib:绘图
  • numpy:处理数值型数组
  • pandas:在numpy基础上能够处理字符串、时间序列、列表、字典......

Matplotlib

一种将数据可视化的python底层绘图库

导库

1
from matplotlib import pyplot as plt

绘制折线图

1
2
3
4
plt.plot(x, y, else)

# 绘制之后必须有show()才能展示图片
plt.show()

必选参数:

  • 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
2
3
4
5
6
# x轴
plt.xticks(x)
plt.xticks(x, _x)
# y轴
plt.yticks(y)
plt.yticks(y, _y)

参数

  • 填入一个参数
    • x:x轴的数据
  • 填入两个参数
    • x:x轴的数据
    • _x:一般为字符串,用来替换x轴的数据(x 和 _x 要一一对应)

例如:

1
2
3
4
5
6
# 画出的图形x轴为1,2,3
plt.xticks([1, 2, 3])

# 那么画出的图形,x轴就被替换为a,b,c
plt.xticks([1, 2, 3], ['a', 'b', 'c'])

y同理

其他参数:

  • rotation:坐标轴数值逆时针旋转的度数

设置中文

由于matplotlib不支持中文显示,需要设置中文

1
2
3
import matplotlib
# 设置中文字体
matplotlib.rc('font', family='KaiTi')

将以上代码插入开头即可显示中文

参数:

  • family:中文字体。有以下字体
    • KaiTi:楷体
    • SimSun:宋体
    • SimHei:黑体
    • Microsoft YaHei:微软雅黑
    • FangSon:仿宋

还有更多字体请查看官方文档

其他参数:

  • size:字体大小
  • weight='bold':粗体

图表信息

1
2
3
4
5
6
7
8
9
10
11
# 设置x轴标签
plt.xlabel('内容', fontsize=标题字体大小)

# 设置y轴标签
plt.ylabel("内容", fontsize=标题字体大小)

# 设置图片标题
plt.title("标题", fontsize=标题字体大小)

# 设置图片网格
plt.grid()

grid()参数:

  • alpha:透明度(0~1)
  • linestyle:线条种类
    • '-':实线
    • '--':虚线
    • '-.':点划线
    • ':':点虚线
    • 无参数:无线条

绘制多个图

多写几个plt.plot()

图例

1
2
3
4
5
plt.plot(x, y, label='内容1')
plt.plot(x, y, label='内容2')

# 在图片上展示图例
plt.legend()

legend()参数:

  • loc:图例展示位置
    • 0:默认,自动展示在合适的位置
    • 1:右上角
    • 2:左上角
    • 3:左下角
    • 4:右下角
    • 5:右
    • 6:左中
    • 7:右中
    • 8:中下
    • 9:中上
    • 10:正中
  • fontsize:图例大小

其他图形

散点图:

1
plt.scatter(x, y)

条形图:

1
2
3
4
5
# 竖着的条形图
plt.bar(x, y)

# 横着的条形图
plt.barh(x, y)

条形图粗细参数:(默认0.8,范围:0~1;若为1,则条形图连到一起)

竖着的条形图:

  • width:粗细

横着的条形图:

  • height:粗细

直方图

1
plt.hist(data, bins)

参数:

  • data:数据列表
  • bins:分组
    • 数字:分为几组
    • 列表:按照列表分组(列表中的数字必须是严格递增)

其他参数:

  • normed=1(true):改为频率分布直方图

直方图绘制注意点:

能够绘制的图形:原始的,未经过统计的数据

对于已经统计过的数据:使用条形图,将粗细改为1来cosplay直方图

参考网站

前端绘图网站:ECHARTS

图表网站:plotly

扩展库:seaborn

其他功能和注意事项

坐标轴数值限制

1
2
x.lim(min, max)
y.lim(min, max)

对于时间的处理

对带有时间的坐标轴格式化

1
data.strftime('时间格式')

注意

绘图时,Period类型的时间数据不能作为坐标轴使用

1
2
# 使用以下方法转为datetime类型
data.to_timestamp()

对坐标轴进行缩放

在今后的数据统计中,常常遇到数值差异巨大的数据,这些数据往往会拔高坐标轴的数值,导致一些数值低的数据不太容易被观察

1
2
# 将y轴变为log以10为底的数值,使得坐标轴成指数变化,可以缓解上述问题
plt.yscale('log')

快速画图

在pandas中,获取了Series数据后,不需要再取出数值和下标画图,可以在数据之后直接加上.plot()来快速画图

1
2
3
4
5
# 假设这是Serise数据
data

# 快速画图,不需要再plt.show()
data.plot(kind, ....)

参数:

  • kind:图形种类
    • 无参数:默认折线图
    • hist:直方图
      • bins:组数,同直方图
    • bar:条形图
    • scatter:散点图
  • label:图例

一个画板上画多个图

1
plt.subplot(三位数字)

参数:三位数字

  • 第一位:行
  • 第二位:列
  • 第三位:位置

例如:

1
2
3
4
5
6
7
8
9
10
plt.subplot(221)
# 则创建一个两行两列的画板,且接下来绘制的图片位于画板的位置1
'''
---------
| 1 | 2 |
---------
| 3 | 4 |
---------
'''
# 则该图片绘制在位置为1的位置

其他图形

饼图

1
plot.pie()

参数:

  • antopet:格式化比例
1
2
3
4
5
6
7
# 例如:'%1.1f%%' 则饼图上的比例为 eg: 30.5%
% 1 . 1 f %%
----------|----
| |
字符串格式 |
|
百分号符号
  • explode:数值列表,表示饼的各个部分与其他部分的间隔距离
    • 例如:[0.02,0.05,0.02] 列表长度就是饼图有几个部分,要一一对应
  • wedgeprops={'linewidth':线宽, 'edgecolor':边沿颜色}
  • shadow=true:开启阴影

面积图

1
plot.area()

可以将DataFrime作为数据直接绘制面积图

绘制直线

1
2
3
4
5
# 水平线
plt.axhline(y, color='', linestyle='')

# 竖直线
plt.axvline(x, color='', linestyle='')

附加内容

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
2
3
4
5
6
# 三种创建方式
np.array(数据)

np.array(range(10))

np.arange(10)

创建之后的数据类型为:numpy.ndarray

存储类型:

整数:int64/int32(根据计算机的位数决定)

小数:float64

numpy的数据类型

类型 类型代码 说明
整型
int_ i 默认整数类型(通常为 int32int64
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
2
3
4
5
6
7
8
9
10
np.array(数据, dtype='类型')

# 调整数据类型
数组.astype('类型')

# 输出存储数据类型
数组.dtype

# 输出容器数据类型
type(数组)

取小数

1
2
3
4
5
# 取0~1的小数
random.random()

# 保留小数位数
np.round(数据, 保留位数)

数组形状(多维数组)

1
2
3
4
5
6
7
# 输出维度
数组.shape
# shape以元组储存

# output
(num, ) # 一维,数值为数组个数
(num, num) # 二维,分别为行数和列数

取出行列数

1
2
shape[0] # 取出行数
shape[1] # 取出列数

形状重组

1
2
数组.reshape((num, num, .....))
# 将原数组改为X行X列的数组,前提是前后数量相同

有返回值,且不改变原值

展开数组

1
数组.flatten()

将数组展开成一维形式

转置

1
2
3
数组.transpose()

数组.T

有返回值,且不改变原值

数值计算

异常值

  • 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
2
3
4
5
6
7
# 对于数据t
'''
([0, 1] <-- 0
[2, 3]) <-- 1
'''

t[0] -->[0, 1]

取行切片

1
2
t[start: end]
# 从索引为start,取到end(不包括)

取独立多行

1
t[[行1, 行2, ....]]

取列

1
2
3
t[:, 列索引]
# 第一个冒号表示对行不操作
# 取制定列索引的一列

取连续多列

1
2
3
t[:, start: end]
# 第一个冒号表示对行不操作
# 从start列取到end列(不包括)

取独立多列

1
2
t[:, [列1, 列2, ....]]
# 第一个冒号表示对行不操作

取某个独立值

1
2
t[2, 3]
# 取行索引为2,列索引为3的那个数据

取多个独立值

1
2
3
4
5
6
7
8
9
10
t[[0, 2], [3, 4]]
------------------------------
# [0, 2]:表示取索引为0,2的行
# | |
# [3, 4]:表示取索引为3, 4的列
# | \
# | \
# V V
#(0, 3) (2, 4)
# 取行索引为0,列索引为3的数据 以及 取行索引为2,列索引为4的数据

numpy赋值

取出某个数据,某行/列数据赋值即可

在numpy取值的基础上,在后面进行赋值即可

布尔索引

使用数组索引进行逻辑判断

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 对于数据t
'''
([5, 4]
[2, 9])
'''

t < 5
|
| output
|
V
'''
([false, true]
[true, false])
'''

使用布尔索引赋值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 对于数据t
'''
([5, 4]
[2, 9])
'''

t[t<5]=3
|
| output
|
V
'''
([5, 3]
[3, 9])
'''

三元运算

where

1
2
3
4
np.where(t<10, 0, 10)
# 若数据小于10,则赋值为0,否则赋值为10

# 类似于 1 if x > 2 else 2

裁剪

1
2
t.clip(10, 18)
# 小于10的赋值为10,大于18的赋值为18

数组操作

数组拼接

拼接前要先将数组内容改为统一类型

竖直拼接

1
2
3
4
5
6
7
8
9
10
np.vstack((数据, 数据))

np.vstack((t1, t2))
'''
t1: 1 2
3 4
+
t2: 5 6
7 8
'''

水平拼接

1
2
3
4
5
6
7
8
np.hstack((数据, 数据))

np.hstack((t1, t2))
'''
t1: t2:
1 2 + 5 6
3 4 7 8
'''

数组行列交换

1
2
3
4
5
6
7
# 行交换
t[[1, 2], :] = t[[2, 1], :]
# 行1与行2交换位置

# 列交换
t[:, [1, 2]] = t[:, [2, 1]]
# 列1与列2交换位置

特殊数组

全0数组

1
2
3
4
5
6
7
8
np.zeros((行, 列))
------
|
|
V
shape(行, 列, ...)

# 默认为float类型

全1数组

1
2
3
4
5
6
7
8
np.ones((行, 列))
------
|
|
V
shape(行, 列, ...)

# 默认为float类型

单位矩阵E(对角线全为1,其余全为0)

1
2
# 单位矩阵是方阵,行列相同
np.eye(边长)

统计非零数据的个数

1
2
np.count_nonzero(数据)
# 返回非零数据的个数

补充

获取最大值与最小值的位置

1
2
3
np.argmax(数据, 轴)
np.argmin(数据, 轴)
# 轴为axis=0/1/2....

若不输入轴,则返回数组中的最大值

当axis=0时,找出每的最大/小值,返回所在的小标

由于返回值形状为一行,所以axis=0

当axis=1时,找出每的最大/小值,返回所在的小标

由于返回值形状为一列,所以axis=1

copy

1
2
3
4
5
6
7
a = b # 或者 a = b[:]
# 此时a只是指向b的地址,内容没有赋值过来
# 若改变b的值a的值也会改变

# 使用copy
a = b.copy()
# 此时二者互不影响

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 未提供,则返回从 0low(不包含)的随机整数。
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
2
# 利用两个nan不相等特性
t[t==t]

统计nan个数

1
2
# 利用两个nan不相等特性
np.nan != np.nan

判断是否为nan

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 对于数据t
'''
([5, 4]
[nan, 9])
'''
np.isnan(t)
|
|
V
'''
([false, false]
[true, false])
'''

------------------------

t[np.isnan(t)] = 0
# 将nan赋值为0

--------------------------

np.count_nonzero(t != t)
# 统计nan的个数

任何数值和nan计算都等于nan

1
2
3
# t中含有nan
np.sum(t)
# 结果也为nan

numpy统计函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 假设有数据t
# 求和
t.sum() / np.sum(t)
# 均值
t.mean() / np.mean(t)
# 中位数
t.median()
# 最大值
t.max() / np.max(t)
# 最小值
t.min() / np.min(t)
# 极差
t.ptp() / np.ptp(t)
# 标准差
t.std() / np.std(t)

上述函数都可指定轴

如:

1
2
3
4
5
np.sum(t, axis=0)
# 计算每列的和,返回的形状为一行,故axis=0

np.sum(t, axis=1)
# 计算每行的和,返回的形状为一列,故axis=1

在数据统计时要酌情考虑nan对数值的影响

把nan赋值为0,会影响均值和其他值

可以将nan赋值为均值或中位数

Pandas

高性能数据分析工具,在Numpy的基础上,处理的数据类型更多

Numpy的方法也能和pandas一起使用

数据类型:

  • Series:一维(带标签的数组,像字典)
  • DataFrame:二维(类似Series容器)

导库

1
import pandas as pd

Series

创建Series

1
2
3
4
5
6
pd.Series([....])
# 自定义下标
pd.Series([....], index=下标的列表(数量与数据一致))

# 通过字典创建Series,key就是下标,value就是内容
pd.Series(字典)

类型:pandas.core.series.Series

取值(尽量使用loc和iloc,后面会讲到)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 取一个
t[下标]

# 取独立多个
t[[下标, 下标, ...]]

# 切片
t[start: end(不包括)]

# 取连续26字母
string.ascii_uppercase[start: end]

# 布尔索引(同numpy)
t[t>4] # 取出大于4的

取下标

1
2
t.index
# 存储在Index类型容器

取值

1
2
t.values
# 存储在ndarray类型容器中

ndarray中的很多方法也适用于Series,如:where,clip等

对下标重命名

1
t.name = '新名称'

DataFrame

文件读取

多列文件存储于DataFrame中

1
2
3
4
5
6
7
8
9
10
11
12
# 读取csv文件,parse_dates可以指定对应的列,直接转为datetime类型
pd.read_csv(filename, parse_dates=['时间列'])

# 读取excel文件,parse_dates可以指定对应的列,直接转为datetime类型
pd.read_excel(filename, sheet_name='工作表名', parse_dates=['时间列'])
# 若有多个工作表,将其连接一起
pd.concat([数据1, 数据2, ....], axis=0(竖直连接)/1(水平连接))

# 读取txt文件,parse_dates可以指定对应的列,直接转为datetime类型
read_table(filename, names=[列名1, 列名2, ...], sep='分隔符', parse_dates=['时间列'])
# 分隔符:\\s+ 表示匹配连续的空格
# \\:第一个'\'表示转义,第二个'\'连接's'表示空格;'+'表示匹配任意长度空格

创建DataFrame

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
pd.DataFrame(数据, index=[左索引(位置)], columns=[上索引(列名)])

# DataFrame:
'''

a b c ---> columns
------------
| 0 | 1 2 3
| 1 | 4 5 6
| 2 | 7 8 9
|
|
V
index

'''
***************************************
# 也可以使用字典创建
pd.DataFrame(字典)

# DataFrame:(字典)
'''

a b c ---> key
------------
| 0 | 1 2 3 \
| 1 | 4 5 6 --> value(若有缺失则为NaN)
| 2 | 7 8 9 /
|
|
V
index(自动创建)

'''

index:不同行,axis=0

columns:不同列,axis=1

与Series的关系:DataFrame的每一行/列都是Series

DataFrame方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
t.index # 行索引
t.columns # 列索引
t.values # 值,ndarray类型
t.dtypes # 展示每个列索引类型
t.ndim # 展示维度深度
t.shape # 展示几行几列

t.head(行数) # 展示前X行,默认5行
t.tail(行数) # 展示后X行,默认5行
t,info() # 信息概览
t.describe() # 快速统计,包含:min,max,mean,std,medium,25%,50%,75%等数据

# 前n项累加
t['列1'] = t['列2'].cumsum()
'''
t:
列2 列2 列1
1 t['列1'] = t['列2'].cumsum() 1 1
2 ------------------------------------> 2 3
3 3 6
4 4 10

列1是列2前n项累加的结果
'''

排序

1
2
# 有数据集df
df.sort_values(by='需要排序的列', ascending=False(降序)) # 默认升序true

取值

1
2
3
4
5
6
7
8
9
# 取行列
t[:] / t[:][:] / t[行索引] # 建议使用loc和iloc

# loc:通过标签取值
t.loc['标签'] / t.loc['行', '列'] / t.loc['行', ['列1', '列2']] 等等
# 只有行,逗号可以省略,写':'表示对行/列不操作

# iloc:通过位置取值
t.iloc[1] # 其他操作同loc,只是内容只能填数字,即索引

布尔索引

1
2
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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 获取一维不重复
len(set(t['列'].tolist()))
=====================
|
|
V
相当于: t['列'].unique()
# 获取二维不重复数据
t1 = ['含有重复数据的列表']
t2 = [i for j in t1 for i in j]
|--1--| | |
| |--3-|
| |
--------2---------

缺失值处理

所谓缺失值:空、None、NaN、NAT(日期类型缺失值)、'0'

判断是否为NAN

1
pd.isnull(数据) / pd.notnull(数据)

删除数据

使用bool索引删除

1
2
# 数据t
t[pd.notnull(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
2
3
4
5
6
7
t.drop_duplicates(keep='first', inplace=)
|
|
V
遇到重复保留第一个

t.unique() 也有同样的功能

填充数据

1
2
3
4
5
6
# 填充NaN
t.fillna(值)
# 值一般是:mean() / medium() / '0'

# 处理为0的数据
t[t==0] = np.nan

数据合并

join

把行索引相同的合并到一起,列索引不能相同,否则报错

左.join(右):最后形状以左边为主,多的删除,少的补NaN

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
'''
t1: t2:
a b c k x m n
A 12 15 0 A 4 6 12 1
B 3 3 7 B 6 7 14 17
C 9 19 18

t1.join(t2):
a b c k x m n
A 12 15 0 4.0 6.0 12.0 1.0 <-- 相同的行索引
B 3 3 7 6.0 7.0 14.0 17.0 <-- 相同的行索引
C 9 19 18 NaN NaN NaN NaN <-- 没有就补NaN
---t1----- --------t2----------

t2.join(t1):(t1和t2交换)
k x m n a b c
A 4 6 12 1 12 15 0 <-- 相同的行索引
B 6 7 14 17 3 3 7 <-- 相同的行索引
<-- 多余的列删除
-----t2----- ---t1---

'''

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
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
"""
****************inner 取交集************************

t1: a b c t2: k x m n
A 12 15 0 A 4 6 12 1
B 3 3 7 B 6 7 14 17
C 9 19 18

t1.merge(t2, left_on='a', right_on='m')
匹配字段 匹配字段 匹配字段数值相同
| |
V V
a b c k x m n
0 12 15 0 4 6 12 1
<--其余不相同的则删除
----t1--- ----t2-----

****************交换t1和t2的位置***********************

t2.merge(t1, left_on='m', right_on='a')
匹配字段 匹配字段 匹配字段数值相同
| |
V V
# k x m n a b c
# 0 4 6 12 1 12 15 0
<--其余不相同的则删除
----t2------- ---t1----

*****************outer 取并集*************************

t1.merge(t2, left_on='a', right_on='m', how='outer')
匹配字段 匹配字段 匹配字段数值相同
| |
V V
a b c k x m n
0 3.0 3.0 7.0 NaN NaN NaN NaN <--其余缺失补NaN
1 9.0 19.0 18.0 NaN NaN NaN NaN <--其余缺失补NaN
2 12.0 15.0 0.0 4.0 6.0 12.0 1.0 <--这一行匹配,拉到最后一行
3 NaN NaN NaN 6.0 7.0 14.0 17.0 <--其余缺失补NaN
-------t1------- ---------t2---------
匹配行,两表均有数值,不匹配的,两表二者其一全为NaN

********************交换t1和t2的位置*********************

t2.merge(t1, left_on='m', right_on='a', how='outer')
匹配字段 匹配字段 匹配字段数值相同
| |
V V
k x m n a b c
0 NaN NaN NaN NaN 3.0 3.0 7.0 <--其余缺失补NaN
1 NaN NaN NaN NaN 9.0 19.0 18.0 <--其余缺失补NaN
2 4.0 6.0 12.0 1.0 12.0 15.0 0.0 <--这一行匹配
3 6.0 7.0 14.0 17.0 NaN NaN NaN <--其余缺失补NaN
---------t2--------- -------t1-------
匹配行,两表均有数值,不匹配的,两表二者其一全为NaN

********************left左补全*************************

t1.merge(t2, left_on='a', right_on='m', how='left')
匹配字段 匹配字段 匹配字段数值相同
| |
V V
a b c k x m n
0 12 15 0 4.0 6.0 12.0 1.0 <--这一行匹配,最后行数和左边一致
1 3 3 7 NaN NaN NaN NaN <--以左表为主,右表其余补NaN
2 9 19 18 NaN NaN NaN NaN <--以左表为主,右表其余补NaN
----t1---- ---------t2--------
匹配行,两表均有数值,不匹配的,以左表为主,右表其余补NaN

********************right右补全************************

t1.merge(t2, left_on='a', right_on='m', how='right')
匹配字段 匹配字段 匹配字段数值相同
| |
V V
a b c k x m n
0 12.0 15.0 0.0 4 6 12 1 <--这一行匹配,最后行数和右边一致
1 NaN NaN NaN 6 7 14 17 <--以右表为主,左表其余补NaN
-----t1------ -----t2------
匹配行,两表均有数值,不匹配的,以右表为主,左表其余补NaN
"""

★分组★

将数据中的某个或某多个字段分组,分组后,被分组的字段自动去重

分组后的数据为长度为2的元组,元组内容为grouped=(分组名,DataFrame类型数据)

1
2
# 数据t
t.groupby(by='要分组的字段')

分组后的数据可以遍历

1
2
3
4
5
6
7
# 遍历整个元组
for i in grouped对象:

# 同时遍历分组名和DataFrame
for i, j in grouped对象:
i:分组名
j:DataFrane对象(若在分组后取出某一列,则为Series)

常用组合:

1
2
3
4
5
6
# 组合一:
t.groupby('列')['列'].count() or .sum()

# 组合二:
t.groupby('列')size() <=等价于=> t.groupby('列')['列'].count()
# 只不过.size()的数据没有标签,而后者有标签,其标签为取出的那一列的标签

常用方法:

1
2
3
4
5
6
.count() # 计数
.sum() # 求和(只能对数值型数据求和,建议分组后取出一列可求和的数据进行求和)
.mean() # 均值,注意事项同.sum
.median # 中位数
.std() / .var() # 无偏(分母为n-1)标准差和方差
.min() / .max() # 最大最小值

多列分组:

1
.groupby(by=['列1', '列2'])

同一个数据,如何取出Series和DataFrame呢?

答案就是一个[]取出的是Series,两个[]取出来的就是DataFrame

原理:嵌套[]表示取多列

  • type(t['a']) --> Series
  • type(t[['a']]) --> DataFrame

agg()聚合

分组后聚合

1
2
t.groupby('列').agg(['min', 'max'])
# 直接得出每一列的最小值和最大值(功能可以指定)

索引和复合索引

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# 获取索引
t.index

# 指定索引
t.index=['索引1', '索引2']

# 重新设置索引,若新索引在原索引中不存在,则其值为NaN
t.reindex([索引列表])

# 指定某列为索引
t.set_index('列索引', drop=) # 索引可重复
# drop=true:将作索引的列删除
# drop=false:保留作索引的列

# 若列索引设置为多个列索引,则为复合索引
t.set_index(['a''b'])

# 交换索引位置
t.swapleve('a', 'b')

# 更新索引
t.reset_index(drop=True, inplace=)
|
|
V
丢掉原索引,重置索引

# 列索引重命名
t.rename(columns={'列':'新名', '列':'新名', .....}, inplace=)

若只有一列:

t[X]:默认行索引

若有多列:

t[X]:默认列索引,若要取行要用t.loc

复合索引展开

.unstack方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
'''
t:
A:1:
2:
3:
B:1: t.unstack() 1 2 3
2: ---------------> A
3: B
C:1: C
2:
3:


'''

若有多个符合索引,则会将最低维的索引作为列索引

Pandas时间序列

生成连续时间:

1
pd.date_range(start='开始时间', end='结束时间', period=生成个数, freg='频率')
  • start和end:再开始时间和结束时间生成频率为freg的时间序列
  • start和period:从开始时间生成period个的频率为freg的时间序列
  • freg:频率,前面可以加数字,表示多少天/月
    • D:天
    • M:月
1
2
3
4
# 例如
pd.date_range(start='20240101', end='20240110', freg='D')
# output
(['2024-01-01', '2024-01-02', ....]) --> datetime类型
别名 偏移量类型 说明
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
2
t.resample('字段')
# 字段:ME,按月分组; D:按天分组 ....

跟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
2
3
4
5
6
7
(date1 - date2) / np.timedelta64(1, 'D')
| \
| \
V V
表示单位1 表示天
则结果为date1-date2的结果除以 1 天,得到int类型
# 想得到一星期,则参数改为(7, 'D')

透视表

一种强大的分析方法

  • 灵活性高,可以随意定制你的分析计算要求
  • 脉络清晰易于理解数据
  • 操作性强,报表神器

pivot_table

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 每个pivot_table都必须有一个index
# Values可以对需要的计算数据进行筛选
# aggfunc参数可以设置我们对数据聚合时进行的函数操作

# 形式一:
# 假设有数据源df
rfm = df.pivot_table(index = '索引列', <-------相当于groupby分组
values = ['列1', '列2', .... ], <--相当于分组后取出某列应用函数,聚合操作----> aggfunc={
'列1':'操作(例如sum、mean、count)',
'列2':'操作',
...
})
# 形式二:
rfm = df.pivot_table(index='列', # 作为行索引
columns='列', # 将某列数据分组后按顺序排列成列索引
values='order_dt', # 取出某列
aggfunc='count') # 在colums的分组下对values计数

其他

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
2
3
4
5
6
7
8
# 1:apply(func(x), axis=)   X
# 2:apply(func, axis=) √

# 第一个,函数在调用apply之前就执行了,且只执行函数本身,没有读取apply的数据
# 第二个,apply将行/列数据作为Series传入func函数

# apply返回值如果是Series类型,可以这么写:
# 例如: return pd.Series(data, 列名(一般是:数据.columns))

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
2
3
4
5
6
7
t:
a b a b
1 4 t['b'].shift() 1 NaN
2 5 ------------------> 2 4
3 6 3 5

# 数据被向下推了一行

可以进行错位计算

cut()分组

设置分组后,对数据应用该函数,得出数据落在哪个分组

1
2
3
4
5
6
7
8
bins=[25, 59, 70, 85, 100]
data=[33, 65, 89]
pd.cut(data, bins)
|
|
V
# [(25, 59], (59, 70], (85, 100]]
# 得出数据落在哪个分组

np.all()

判断迭代器内的值是否相同

1
2
np.all(['true', 'true', 'true'])  ----->  true
np.all(['true', 'false', 'true']) -----> false

用于判断多个列内的数据是否一一对应

相关项目

github

gitee

总结

这些是数据分析常用的方法,后续如果有其他需要,请自行查找官方文档

有什么问题,或者对项目有疑惑的可以在左侧资料框的Email联系我

作者

heimaolala

发布于

2024-11-15

更新于

2025-06-17

许可协议

评论