绿色健康小清新

耐得住寂寞,守得住繁华

数据挖掘

安装模块

1
2
3
4
5
6
matplotlib
numpy
pandas
TA-Lib
tables
jupyter

案例测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
def matplolib_demo():
"""画图"""
plt.figure(figsize=(20, 8), dpi=100)
plt.plot([1,2,3], [4,5,6])
plt.show()
plt.savefig("./jupyter_demo01.png")
return None

def read_csv_dem():
"""分析"""
stock_key = pd.read_csv("./jupyter_demo01.png")
print(stock_key)
return None

if __name__ == "__main__":
matplolib_demo()
read_csv_dem()



Jupyter Notebook

介绍

Jupyter Notebook是一个开源的Web应用程序,允许用户创建和共享包含代码、方程式、可视化和文本的文档。它的用途包括:数据清理和转换、数值模拟、统计建模、数据可视化、机器学习等等。

名字源于Julia,Python,和R(数据科学的三种开源语言)

是一款程序员和工作者的编程/文档/展示软件

.ipynb文件格式是用于计算型叙述的JSON文档格式的正式规范

优势

可选择语言:支持超过40种编程语言,包括Python、R、Julia、Scala等。
分享笔记本:可以使用电子邮件、Dropbox、GitHub和Jupyter Notebook Viewer与他人共享。
交互式输出:代码可以生成丰富的交互式输出,包括HTML、图像、视频、LaTeX等等。
大数据整合:通过Python、R、Scala编程语言使用Apache Spark等大数据框架工具。支持使用pandas、scikit-learn、ggplot2、TensorFlow来探索同一份数据。


启动

在终端运行

1
2
3
jupyter notebook

ipython notebook

在浏览器输入localhost:8888,进入该页面

点击一下day01_jupyter_demo.ipynb


测试

运行代码 shift + enter



Matplotlib

介绍

Matplotlib 是一个 Python 的 2D绘图库,它以各种硬拷贝格式和跨平台的交互式环境生成出版质量级别的图形 [1] 。

通过 Matplotlib,开发者可以仅需要几行代码,便可以生成绘图,直方图,功率谱,条形图,错误图,散点图等


案例

1
2
3
4
5
from matplotlib import pyplot

pyplot.figure()
pyplot.plot([1, 0, 9], [4, 5, 6])
pyplot.show()


三层结构

容器层: 主要由Canvas、Figure、Axes组成。

Canvas是位于最底层的系统层,在绘图的过程中充当画板的角色,即放置画布(Figure)的工具。

Figure是Canvas上方的第一层,也是需要用户来操作的应用层的第一层,在绘图的过程中充当画布的角色。

Axes是应用层的第二层,在绘图的过程中相当于画布上的绘图区的角色。

Figure:指整个图形(可以通过plt.figure()设置画布的大小和分辨率等)
Axes(坐标系):数据的绘图区域
Axis(坐标轴):坐标系中的一条轴,包含大小限制、刻度和刻度标签

注意点:
一个figure(画布)可以包含多个axes(坐标系/绘图区),但是一个axes只能属于一个figure
一个axes(坐标系/绘图区)可以包含多个axis(坐标轴),包含两个即为2d坐标系,3个即为3d坐标系

辅助显示层
辅助显示层为Axes(绘图区)内的除了根据数据绘制出的图像以外的内容,主要包括Axes外观(facecolor)、边框线(spines)、坐标轴(axis)、坐标轴名称(axis label)、坐标轴刻度(tick)、坐标轴刻度标签(tick label)、网格线(grid)、图例(legend)、标题(title)等内容。
该层的设置可使图像显示更加直观更加容易被用户理解,但又不会对图像产生实质的影响。

图像层

图像层指Axes内通过plot、scatter、bar、histogram、pie等函数根据数据绘制出的图像。

总结
Canvas(画板)位于最底层,用户一般接触不到
Figure(画布)建立在Canvas之上
Axes(绘图区)建立在Figure之上
坐标轴(axis)、图例(legend)等辅助显示层以及图像层都是建立在Axes之上


折线图

1
2
3
4
5
6
7
8
from matplotlib import pyplot

# 创建画布
pyplot.figure()
# 绘制图像
pyplot.plot([1, 2, 3, 4, 5, 6, 7], [17, 17, 18, 15, 11, 11, 13])
# 显示图像
pyplot.show()

设置画布属性和图片保存

1
2
3
4
5
6
7
8
9
10
def figure(num=None,  # autoincrement if None, else integer from 1-N
figsize=None, # defaults to rc figure.figsize
dpi=None, # defaults to rc figure.dpi
facecolor=None, # defaults to rc figure.facecolor
edgecolor=None, # defaults to rc figure.edgecolor
frameon=True,
FigureClass=Figure,
clear=False,
**kwargs
):

**num:**整型或者字符串,可选参数,默认:None。
如果不提供该参数,一个新的画布(figure)将被创建而且画布数量将会增加。
如果提供该参数,带有id的画布是已经存在的,激活该画布并返回该画布的引用。
如果这个画布不存在,创建并返回画布实例。
如果num是字符串,窗口标题将被设置为该图的数字。
**figsize:**整型元组,可选参数 ,默认:None。
每英寸的宽度和高度。如果不提供,默认值是figure.figsize。
**dpi:**整型,可选参数,默认:None。每英寸像素点。如果不提供,默认是figure.dpi。
**facecolor:**背景色。如果不提供,默认值:figure.facecolor。
**edgecolor:**边界颜色。如果不提供,默认值:figure.edgecolor。
**framemon:**布尔类型,可选参数,默认值:True。如果是False,禁止绘制画图框。
**FigureClass:**源于matplotlib.figure.Figure的类。(可选)使用自定义图实例。
**clear:**布尔类型,可选参数,默认值:False。如果为True和figure已经存在时,这是清理掉改图。


1
2
3
4
5
6
7
8
# 创建画布
pyplot.figure(figsize=(20, 8), dpi=40)
# 绘制图像
pyplot.plot([1, 2, 3, 4, 5, 6, 7], [17, 17, 18, 15, 11, 11, 13])
# 保存图像
pyplot.savefig("test_plot.png")
# 显示图像
pyplot.show()

注意:pyplot.show()会释放figure资源,如果在显示图像之后保存图片只能保存空图片


增加图形信息

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
import random
import matplotlib.pyplot as plt

# 准备数据x,y
x = range(60)
y_shanghai = [random.uniform(15, 18) for i in x]
y_beijing = [random.uniform(15, 18) for i in x]
# 创建画布
plt.figure(figsize=(20, 8), dpi=80)

# 绘制图像
# 八种颜色 b:blue g:green r:red c:cyan m:magenta y:yellow k:black w:white
# 四种线形 - 实线; -- 虚线; -. 点实线 : 点虚线
plt.plot(x, y_shanghai, color="r", linestyle="--", label="上海")
plt.plot(x, y_beijing, color="b", label="北京")
# 显示图例(结合上方的label)
# best;upper right;upper left;lower left;lower right;right;center left;center right;lower center;upper center;center
plt.legend(loc="upper center")

# 显示中文标签
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False

# 修改x,y刻度,标签
x_label = ["11点{}分".format(i) for i in x]
plt.xticks(x[::5], x_label[::5])
plt.yticks(range(10, 30, 5))

# 添加网格显示
plt.grid(True, linestyle="--", alpha=0.5)

# 添加描述信息
plt.xlabel("时间")
plt.ylabel("温度")
plt.title("北京,上海中午11点到12点之间的温度变化")

# 显示图像
plt.show()


多个绘图区

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
import random
import matplotlib.pyplot as plt

# 准备数据x,y
x = range(60)
y_shanghai = [random.uniform(15, 18) for i in x]
y_beijing = [random.uniform(15, 18) for i in x]
# 创建画布
# plt.figure(figsize=(20, 8), dpi=80)
figure, axes = plt.subplots(nrows=1, ncols=2, figsize=(20, 8), dpi=80)

# 绘制图像
# 八种颜色 b:blue g:green r:red c:cyan m:magenta y:yellow k:black w:white
# 四种线形 - 实线; -- 虚线; -. 点划线 : 点虚线
axes[0].plot(x, y_shanghai, color="r", linestyle="--", label="上海")
axes[1].plot(x, y_beijing, color="b", label="北京")
# 显示图例(结合上方的label)
axes[0].legend(loc="upper center")
axes[1].legend(loc="upper center")

# 显示中文标签
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False

# 修改x,y刻度,标签
x_label = ["11点{}分".format(i) for i in x]
axes[0].set_xticks(x[::5])
axes[0].set_xticklabels(x_label[::5])
axes[0].set_yticks(range(10, 30, 5))
axes[1].set_xticks(x[::5])
axes[1].set_xticklabels(x_label[::5])
axes[1].set_yticks(range(10, 30, 5))

# 添加网格显示
axes[0].grid(True, linestyle="--", alpha=0.5)
axes[1].grid(True, linestyle="--", alpha=0.5)

# 添加描述信息
axes[0].set_xlabel("时间")
axes[0].set_ylabel("温度")
axes[0].set_title("上海中午11点到12点之间的温度变化")
axes[1].set_xlabel("时间")
axes[1].set_ylabel("温度")
axes[1].set_title("北京中午11点到12点之间的温度变化")

# 显示图像
plt.show()


结合数学表达式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import matplotlib.pyplot as plt
import numpy as np

# 准备x,y数据
x = np.linspace(-1, 1, 1000)
y = 2 * x * x

# 创建画布
plt.figure(figsize=(20, 8), dpi=80)

# 绘制图像
plt.plot(x, y)

# 添加网格
plt.grid(True, linestyle="--", alpha=0.5)

# 显示
plt.show()


散点图

1
2
3
4
5
6
7
8
9
10
11
12
13
import matplotlib.pyplot as plt

x = [225.98, 247.07, 253.14, 457.85, 241.58, 301.01, 20.67, 288.64,
163.56, 120.06, 207.83, 342.75, 147.9 , 53.06, 224.72, 29.51,
21.61, 483.21, 245.25, 399.25, 343.35]

y = [196.63, 203.88, 210.75, 372.74, 202.41, 247.61, 24.9 , 239.34,
140.32, 104.15, 176.84, 288.23, 128.79, 49.64, 191.74, 33.1 ,
30.74, 400.02, 205.35, 330.64, 283.45]

plt.figure(figsize=(20, 8), dpi=80)
plt.scatter(x, y)
plt.show()


柱状图

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
import matplotlib.pyplot as plt


# 准备数据
movie_names = ['雷神3:诸神黄昏','正义联盟','东方快车谋杀案','寻梦环游记','全球风暴', '降魔传','追捕','七十七天','密战','狂兽','其它']
tickets = [73853,57767,22354,15969,14839,8725,8716,8318,7916,6764,52222]

# 创建画布
plt.figure(figsize=(20, 8), dpi=80)

# 绘制柱状图
x_ticks = range(len(movie_names))
plt.bar(x_ticks, tickets, color=['b','r','g','y','c','m','y','k','c','g','b'])

plt.rcParams["font.sans-serif"] = ["SimHei"]
plt.rcParams["axes.unicode_minus"] = True

# 修改x的刻度
plt.xticks(x_ticks, movie_names)

# 添加标题
plt.title("电影票房收入")

# 添加网格
plt.grid(linestyle="--", alpha=0.5)

# 显示图像
plt.show()

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
import matplotlib.pyplot as plt


# 1、准备数据
movie_names = ['雷神3:诸神黄昏','正义联盟','寻梦环游记']

first_day = [10587.6,10062.5,1275.7]
first_weekend=[36224.9,34479.6,11830]

# 创建画布
plt.figure(figsize=(20, 8), dpi=80)

# 绘制柱状图
x_ticks = range(len(movie_names))
plt.bar(x_ticks, first_day, color='r', width=0.2, label="首日票房")
plt.bar([x_tick+0.2 for x_tick in x_ticks], first_weekend, color='c', width=0.2, label="首周票房")
plt.legend()

plt.rcParams["font.sans-serif"] = ["SimHei"]
plt.rcParams["axes.unicode_minus"] = True

# 修改x的刻度
plt.xticks([x_tick+0.1 for x_tick in x_ticks], movie_names)

# 添加标题
plt.title("电影票房收入")

# 添加网格
plt.grid(linestyle="--", alpha=0.5)

# 显示图像
plt.show()


直方图

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import matplotlib.pyplot as plt

# 准备数据
time = [131, 98, 125, 131, 124, 139, 131, 117, 128, 108, 135, 138, 131, 102, 107, 114, 119, 128, 121, 142, 127, 130, 124, 101, 110, 116, 117, 110, 128, 128, 115, 99, 136, 126, 134, 95, 138, 117, 111,78, 132, 124, 113, 150, 110, 117, 86, 95, 144, 105, 126, 130,126, 130, 126, 116, 123, 106, 112, 138, 123, 86, 101, 99, 136,123, 117, 119, 105, 137, 123, 128, 125, 104, 109, 134, 125, 127,105, 120, 107, 129, 116, 108, 132, 103, 136, 118, 102, 120, 114,105, 115, 132, 145, 119, 121, 112, 139, 125, 138, 109, 132, 134,156, 106, 117, 127, 144, 139, 139, 119, 140, 83, 110, 102,123,107, 143, 115, 136, 118, 139, 123, 112, 118, 125, 109, 119, 133,112, 114, 122, 109, 106, 123, 116, 131, 127, 115, 118, 112, 135,115, 146, 137, 116, 103, 144, 83, 123, 111, 110, 111, 100, 154,136, 100, 118, 119, 133, 134, 106, 129, 126, 110, 111, 109, 141,120, 117, 106, 149, 122, 122, 110, 118, 127, 121, 114, 125, 126,114, 140, 103, 130, 141, 117, 106, 114, 121, 114, 133, 137, 92,121, 112, 146, 97, 137, 105, 98, 117, 112, 81, 97, 139, 113,134, 106, 144, 110, 137, 137, 111, 104, 117, 100, 111, 101, 110,105, 129, 137, 112, 120, 113, 133, 112, 83, 94, 146, 133, 101,131, 116, 111, 84, 137, 115, 122, 106, 144, 109, 123, 116, 111,111, 133, 150]

# 创建画布
plt.figure(figsize=(20, 8), dpi=80)

# 绘制直方图
distance = 2
group_num = int(max(time)-min(time) / distance)

# 默认显示的是频数,使用density是频率
plt.hist(time, bins=group_num, density=True)

# 修改x轴刻度
plt.xticks(range(min(time), max(time)+2, distance))

# 添加网格
plt.grid(linestyle="--", alpha=0.5)

# 显示图像
plt.show()

hist参数详解:https://blog.csdn.net/ToYuki_/article/details/104114925


饼图

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import matplotlib.pyplot as plt

# 准备数据
movie_name = ['雷神3:诸神黄昏','正义联盟','东方快车谋杀案','寻梦环游记','全球风暴','降魔传','追捕','七十七天','密战','狂兽','其它']
place_count = [60605,54546,45819,28243,13270,9945,7679,6799,6101,4621,20105]

# 准备画布
plt.figure(figsize=(20, 8), dpi=80)

plt.rcParams["font.sans-serif"] = ["SimHei"]
plt.rcParams["axes.unicode_minus"] = True
# 绘制饼图,autopct为显示格式
plt.pie(place_count, labels=movie_name, colors=['b','r','g','y','c','m','y','k','c','g','y'], autopct="%1.2f%%")
plt.legend()

# 为了让饼图显示圆形,保证长宽一致
plt.axis('equal')

# 显示
plt.show()


总结


Numpy

介绍

NumPy(Numerical Python) 是 Python 语言的一个扩展程序库,支持大量的维度数组与矩阵运算,此外也针对数组运算提供大量的数学函数库。

NumPy 的前身 Numeric 最早是由 Jim Hugunin 与其它协作者共同开发,2005 年,Travis Oliphant 在 Numeric 中结合了另一个同性质的程序库 Numarray 的特色,并加入了其它扩展而开发了 NumPy。NumPy 为开放源代码并且由许多协作者共同维护开发。

NumPy 是一个运行速度非常快的数学库,主要用于数组计算,包含:

  • 一个强大的N维数组对象 ndarray
  • 广播功能函数
  • 整合 C/C++/Fortran 代码的工具
  • 线性代数、傅里叶变换、随机数生成等功能

Ndarray

NumPy 最重要的一个特点是其 N 维数组对象 ndarray,它是一系列同类型数据的集合,以 0 下标为开始进行集合中元素的索引。

ndarray 对象是用于存放同类型元素的多维数组。

ndarray 中的每个元素在内存中都有相同存储大小的区域。

ndarray 内部由以下内容组成:

  • 一个指向数据(内存或内存映射文件中的一块数据)的指针。
  • 数据类型或 dtype,描述在数组中的固定大小值的格子。
  • 一个表示数组形状(shape)的元组,表示各维度大小的元组。
  • 一个跨度元组(stride),其中的整数指的是为了前进到当前维度下一个元素需要"跨过"的字节数。

ndarray 的内部结构:

跨度可以是负数,这样会使数组在内存中后向移动,切片中 obj[::-1] 或 obj[:,::-1] 就是如此。

创建一个 ndarray 只需调用 NumPy 的 array 函数即可:

1
numpy.array(object, dtype = None, copy = True, order = None, subok = False, ndmin = 0)
名称描述
object数组或嵌套的数列
dtype数组元素的数据类型,可选
copy对象是否需要复制,可选
order创建数组的样式,C为行方向,F为列方向,A为任意方向(默认)
subok默认返回一个与基类类型一致的数组
ndmin指定生成数组的最小维度

1
2
3
4
5
6
7
8
9
10
11
12
import numpy as np

score = np.array([[80, 89, 86, 67, 79],
[78, 97, 89, 67, 81],
[90, 94, 78, 67, 74],
[91, 91, 90, 67, 69],
[76, 87, 75, 67, 86],
[70, 79, 84, 67, 84],
[94, 92, 93, 67, 64],
[86, 85, 83, 67, 80]])
print(score)
print(type(score))

输出

1
2
3
4
5
6
7
8
9
[[80 89 86 67 79]
[78 97 89 67 81]
[90 94 78 67 74]
[91 91 90 67 69]
[76 87 75 67 86]
[70 79 84 67 84]
[94 92 93 67 64]
[86 85 83 67 80]]
<class 'numpy.ndarray'>

ndarray与Python原生list运算效率对比

1
2
3
4
5
6
7
8
9
10
11
12
# ndarray和list效率对比
python_list = []
start_time = datetime.datetime.now()
for i in range(100000000):
python_list.append(random.random())
end_time = datetime.datetime.now()
print("list的运行时间:", end_time-start_time)

start_time = datetime.datetime.now()
ndarray_list = np.array(python_list)
end_time = datetime.datetime.now()
print("ndarray的运行时间:", end_time-start_time)

输出

1
2
list的运行时间: 0:00:22.598421
ndarray的运行时间: 0:00:04.590315

啧啧啧,这能比???

为啥Ndarray这么快

  1. 内存块风格

    ndarray到底跟原生python列表有什么不同呢,请看一张图:

    从图中我们可以看出ndarray在存储数据的时候,数据与数据的地址都是连续的,这样就给使得批量操作数组元素时速度更快。

    这是因为ndarray中的所有元素的类型都是相同的,而Python列表中的元素类型是任意的,所以ndarray在存储元素时内存可以连续,而python原生list就只能通过寻址方式找到下一个元素,这虽然也导致了在通用性能方面Numpy的ndarray不及Python原生list,但在科学计算中,Numpy的ndarray就可以省掉很多循环语句,代码使用方面比Python原生list简单的多。

  2. ndarray支持并行化运算(向量化运算)

    numpy内置了并行运算功能,当系统有多个核心时,做某种计算时,numpy会自动做并行计算

  3. 效率远高于纯Python代码

    Numpy底层使用C语言编写,内部解除了GIL(全局解释器锁),其对数组的操作速度不受Python解释器的限制,所以,其效率远高于纯Python代码。


Ndarray的属性

属性说明
ndarray.ndim秩,即轴的数量或维度的数量
ndarray.shape数组的维度,对于矩阵,n 行 m 列
ndarray.size数组元素的总个数,相当于 .shape 中 n*m 的值
ndarray.dtypendarray 对象的元素类型
ndarray.itemsizendarray 对象中每个元素的大小,以字节为单位
ndarray.flagsndarray 对象的内存信息
ndarray.realndarray元素的实部
ndarray.imagndarray 元素的虚部
ndarray.data包含实际数组元素的缓冲区,由于一般通过数组的索引获取元素,所以通常不需要使用这个属性。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
score = np.array([[80, 89, 86, 67, 79],
[78, 97, 89, 67, 81],
[90, 94, 78, 67, 74],
[91, 91, 90, 67, 69],
[76, 87, 75, 67, 86],
[70, 79, 84, 67, 84],
[94, 92, 93, 67, 64],
[86, 85, 83, 67, 80]])
print(type(score))

print(score.shape) # (8, 5)
print(score.ndim) # 2
print(score.size) # 40
print(score.dtype) # int32 默认
print(score.itemsize) # 4

输出

1
2
3
4
5
6
<class 'numpy.ndarray'>
(8, 5)
2
40
int32
4

Ndarray数据类型

名称描述
bool_布尔型数据类型(True 或者 False)
int_默认的整数类型(类似于 C 语言中的 long,int32 或 int64)
intc与 C 的 int 类型一样,一般是 int32 或 int 64
intp用于索引的整数类型(类似于 C 的 ssize_t,一般情况下仍然是 int32 或 int64)
int8字节(-128 to 127)
int16整数(-32768 to 32767)
int32整数(-2147483648 to 2147483647)
int64整数(-9223372036854775808 to 9223372036854775807)
uint8无符号整数(0 to 255)
uint16无符号整数(0 to 65535)
uint32无符号整数(0 to 4294967295)
uint64无符号整数(0 to 18446744073709551615)
float_float64 类型的简写
float16半精度浮点数,包括:1 个符号位,5 个指数位,10 个尾数位
float32单精度浮点数,包括:1 个符号位,8 个指数位,23 个尾数位
float64双精度浮点数,包括:1 个符号位,11 个指数位,52 个尾数位
complex_complex128 类型的简写,即 128 位复数
complex64复数,表示双 32 位浮点数(实数部分和虚数部分)
complex128复数,表示双 64 位浮点数(实数部分和虚数部分)

numpy 的数值类型实际上是 dtype 对象的实例,并对应唯一的字符,包括 np.bool_,np.int32,np.float32,等等。

1
2
3
4
import numpy as np
data = np.array([1.1, 1.2, 1.3], dtype=np.float32)
print(data)
print(data.dtype)

输出

1
2
[1.1 1.2 1.3]
float32

Ndarray常用操作

生成0和1数组

1
2
3
4
5
6
7
8
zero = np.zeros([3, 4])
print(zero)
print("元素类型", zero.dtype)

print("------------------")

one = np.ones([3, 4], dtype=np.int_)
print(one)

输出

1
2
3
4
5
6
7
8
[[0. 0. 0. 0.]
[0. 0. 0. 0.]
[0. 0. 0. 0.]]
元素类型 float64
------------------
[[1 1 1 1]
[1 1 1 1]
[1 1 1 1]]

从现有的数组中生成

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
print("-----array(深拷贝)-----")
data01[0, 3] = 100
print("原始数据:", score[0])
print("array产生的数组修改后的数据(data01):", data01[0])
print("array产生的数组修改后的数据(score):", score[0])

print("-----asarray(浅拷贝)-----")
data02[0, 3] = 110
print("原始数据:", score[0])
print("array产生的数组修改后的数据(data02):", data02[0])
print("array产生的数组修改后的数据(score):", score[0])

print("-----copy(深拷贝)-----")
data03[0, 3] = 120
print("原始数据:", score[0])
print("array产生的数组修改后的数据(data02):", data03[0])
print("array产生的数组修改后的数据(score):", score[0])

输出

1
2
3
4
5
6
7
8
9
10
11
12
-----array(深拷贝)-----
原始数据: [80 89 86 67 79]
array产生的数组修改后的数据(data01): [ 80 89 86 100 79]
array产生的数组修改后的数据(score): [80 89 86 67 79]
-----asarray(浅拷贝)-----
原始数据: [ 80 89 86 110 79]
array产生的数组修改后的数据(data02): [ 80 89 86 110 79]
array产生的数组修改后的数据(score): [ 80 89 86 110 79]
-----copy(深拷贝)-----
原始数据: [ 80 89 86 110 79]
array产生的数组修改后的数据(data02): [ 80 89 86 120 79]
array产生的数组修改后的数据(score): [ 80 89 86 110 79]

生成固定范围的数组

1
2
3
4
arr = np.linspace(0, 10, 5)  # [0, 10] 等距离,num默认是50
print(arr)
arr = np.arange(0, 10, 2.5) # [a, b) c是步长,step默认是1
print(arr)

输出

1
2
[ 0.   2.5  5.   7.5 10. ]
[0. 2.5 5. 7.5]

均匀分布

1
2
3
4
data = np.random.uniform(-1, 1, 1000000)
plt.figure(figsize=(20, 8), dpi=80)
plt.hist(data, bins=1000)
plt.show()


正态分布

1
2
3
4
data = np.random.normal(1.75, 0.1, 100000)
plt.figure(figsize=(20, 8), dpi=80)
plt.hist(data, bins=1000)
plt.show()


案例:随机生成8只股票2周的交易日涨幅数据

1
2
3
4
stock_change = np.random.normal(loc=0, scale=1, size=(8, 10))
print(stock_change)
# 获取第一个股票的前3个交易日的涨跌幅数据
stock_change[0, :3]

输出

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
[[-0.03469926,  1.68760014,  0.05915316,  2.4473136 , -0.61776756,
-0.56253866, -1.24738637, 0.48320978, 1.01227938, -1.44509723],
[-1.8391253 , -1.10142576, 0.09582268, 1.01589092, -1.20262068,
0.76134643, -0.76782097, -1.11192773, 0.81609586, 0.07659056],
[-0.74293074, -0.7836588 , 1.32639574, -0.52735663, 1.4167841 ,
2.10286726, -0.21687665, -0.33073563, -0.46648617, 0.07926839],
[ 0.45914676, -0.78330377, -1.10763289, 0.10612596, -0.63375855,
-1.88121415, 0.6523779 , -1.27459184, -0.1828502 , -0.76587891],
[-0.50413407, -1.35848099, -2.21633535, -1.39300681, 0.13159471,
0.65429138, 0.32207255, 1.41792558, 1.12357799, -0.68599018],
[ 0.3627785 , 1.00279706, -0.68137875, -2.14800075, -2.82895231,
-1.69360338, 1.43816168, -2.02116677, 1.30746801, 1.41979011],
[-2.93762047, 0.22199761, 0.98788788, 0.37899235, 0.28281886,
-1.75837237, -0.09262863, -0.92354076, 1.11467277, 0.76034531],
[-0.39473551, 0.28402164, -0.15729195, -0.59342945, -1.0311294 ,
-1.07651428, 0.18618331, 1.5780439 , 1.31285558, 0.10777784]]


[ 0.75372007 0.37205739 -0.45823456]

形状修改

1
2
3
4
print(stock_change.reshape((10, 8)).shape)
stock_change.resize((10, 8))
print(stock_change.shape)
print(stock_change.T.shape)

输出

1
2
3
(10, 8)
(10, 8)
(8, 10)

序列化

1
print(stock_change.tostring())

输出

1
b'\x1cDY5\xba\xf6\xfd?\x1f!\xa4"H\x12\xd3\xbf\x8a\xb8\n"n\x86\xe8?V\xc8E\x01\x0c\xba\xe4?#\xa5\xcd4\xfd8\xdc?-\xfb\x01\x9by\xee\xb5?\x97\xca\xc6\xd3\xaf;\xe0?\x9b;\x1f\xd9d\x17\xfb\xbfY\x10\xca\x9c\x99D\xe5?d\xbf\x93\xfe\xfbr\xf1\xbfQ\x89\x0f\xca\x88:\xf7\xbfo\xdd22=\x9d\xf2\xbf\xa1,\xbc\xc7>B\xf0\xbfl\x8d\......省略

数组去重

1
2
3
data = np.array([[1,2,3,4],[3,4,5,6]])
print(np.unique(data))
print(set(data.flatten()))

输出

1
2
[1 2 3 4 5 6]
{1, 2, 3, 4, 5, 6}


Ndarray运算

逻辑运算

1
2
3
4
5
6
7
import numpy as np

stock_change = np.random.normal(1.5, 2, (8, 10))
# 逻辑判断, 如果涨跌幅大于等于0.5就标记为True 否则为False
print(stock_change >= 0.5)
# 修改所有涨幅小于0.5的为0.5
stock_change[stock_change < 0.5] = 0.5

输出

1
2
3
4
5
6
7
8
[[False  True  True  True False  True False  True False  True]
[False True True True True True False True True False]
[ True True True False True True False True False False]
[ True True False True True True False False True False]
[ True True True False True True True False False True]
[ True True True True True True True True True False]
[ True True True True True True True True True True]
[ True True True True True True True True True True]]

where运算

1
2
3
4
5
6
7
temp = stock_change[:4, :4]
print(temp)
print(np.where(temp > 0.5, 1, 0))
# 判断前四个股票前四天的涨跌幅 大于0.5并且小于1的,换为1,否则为0
# 判断前四个股票前四天的涨跌幅 大于0.5或者小于-0.5的,换为1,否则为0
print(np.where(np.logical_and(temp > 0.5, temp < 1), 1, 0))
print(np.where(np.logical_or(temp > 0.5, temp < -0.5), 1, 0))

输出

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
[[ 2.11334994  2.75371732 -1.45919878 -0.54644526]
[ 2.50898042 2.49334823 3.46757975 1.67814258]
[-1.63742684 2.21757841 0.51642822 -1.10437119]
[ 1.08439702 0.2920416 0.31753524 2.20334352]]

[[1 1 0 0]
[1 1 1 1]
[0 1 1 0]
[1 0 0 1]]

[[0 0 0 0]
[0 0 0 0]
[0 0 1 0]
[0 0 0 0]]

[[1 1 1 1]
[1 1 1 1]
[1 1 1 1]
[1 0 0 1]]

最大值最小值

1
2
3
4
5
6
7
print(np.max(stock_change))
# 0代表列,1代表行
print(np.max(stock_change, axis=0))
print(np.max(stock_change, axis=1))
# 最大值的位置
print(np.argmax(stock_change, axis=0))
print(np.argmax(stock_change, axis=1))

输出

1
2
3
4
5
6
7
6.693146605729187
[6.69314661 2.82844572 5.81205157 5.35317406 4.01567427 5.66452237
2.61476055 3.99797746 4.19418698 5.17729721]
[4.48925181 4.29683647 3.99797746 2.09293751 5.81205157 5.35317406
5.17729721 6.69314661]
[7 4 4 5 6 7 2 2 5 6]
[5 0 7 1 2 3 9 0]

广播机制

简单理解:对两个数组,分别比较他们的每一个维度(若其中一个数组没有当前维度则忽略),满足:

  • 数组拥有相同形状。
  • 当前维度的值相等。
  • 当前维度的值有一个是 1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
A (3d array): 		256 × 256 × 3
B (1d array): 3
Result (3d array): 256 × 256 × 3

A (4d array): 9 × 1 × 7 × 1
B (3d array): 8 × 1 × 5
Result (4d array): 9 × 8 × 7 × 5

A (2d array): 5 × 4
B (1d array): 1
Result (2d array): 5 × 4

A (3d array): 15 × 3 × 5
B (3d array): 15 × 1 × 1
Result (3d array): 15 × 3 × 5

矩阵运算

两种方法存储矩阵

  1. ndarray 二维数组
  2. matrix数据结构

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
data = np.array([[80, 86],
[82, 80],
[85, 78],
[90, 90],
[86, 82],
[82, 90],
[78, 80],
[92, 94]])

# matrix存储矩阵
data_mat = np.mat([[80, 86],
[82, 80],
[85, 78],
[90, 90],
[86, 82],
[82, 90],
[78, 80],
[92, 94]])

weights = np.array([[2], [3]])
weights_mat = np.mat([[2], [3]])
# 矩阵乘法
print(np.matmul(data, weights))
print(np.dot(data, weights))
print(data @ weights)
print(data_mat * weights_mat)

输出

1
2
3
4
5
6
7
8
9
[[418]
[404]
[404]
[450]
[418]
[434]
[396]
[466]]
.....都是一样的,就省略了

合并

其实问题理解axis有问题,df.mean其实是在每一行上取所有列的均值,而不是保留每一列的均值。也许简单的来记就是axis=0代表往跨行(down),而axis=1代表跨列(across),作为方法动作的副词(译者注)

换句话说:

  • 使用0值表示沿着每一列或行标签\索引值向下执行方法
  • 使用1值表示沿着每一行或者列标签模向执行对应的方法
1
2
3
4
5
6
7
8
9
data_1 = np.array([1, 2, 3])
data_2 = np.array([5, 6, 7])
print(np.hstack((data_1, data_2))) # 水平拼接 horizontally
print(np.vstack((data_1, data_2))) # 竖直拼接 vertically

data_1 = np.array([[1, 2, 3], [2, 3, 4], [3, 4, 5]])
data_2 = np.array([[5, 6, 7]])
print(np.concatenate((data_1, data_2), axis=0)) # 自定义合并
print(np.concatenate((data_1, data_2.T), axis=1)) # 自定义合并

输出

1
2
3
4
5
6
7
8
9
10
11
12
13
[1 2 3 5 6 7]

[[1 2 3]
[5 6 7]]

[[1 2 3]
[2 3 4]
[3 4 5]
[5 6 7]]

[[1 2 3 5]
[2 3 4 6]
[3 4 5 7]]

分割

1
2
3
4
print("-----分割-----")
data = np.arange(0, 10)
print(np.split(data, 2))
print(np.split(data, [4, 6]))

输出

1
2
[array([0, 1, 2, 3, 4]), array([5, 6, 7, 8, 9])]
[array([0, 1, 2, 3]), array([4, 5]), array([6, 7, 8, 9])]

IO操作和数值处理

文件内容

1
2
3
4
id,value1,value2,value3
1,123,1.4,23
2,110,,18
3,,2.1,19

代码

1
2
3
test = np.genfromtxt("test.csv", delimiter=",")
print(test)
print(type(test[0, 0]))

输出

1
2
3
4
5
[[  nan   nan   nan   nan]
[ 1. 123. 1.4 23. ]
[ 2. 110. nan 18. ]
[ 3. nan 2.1 19. ]]
<class 'numpy.float64'>

我们可以看到,出现了缺失值nan。

为什么呢?当我们读取本地的文件为float的时候,如果数据类型不对(或者为None),就会出现nan

上方的[0,0]明明是字符串,但是是按float读取的,就出现了nan。这是由ndarray的数据结构决定的


总结



Pandas

介绍

Pandas 是 Python 的核心数据分析支持库,提供了快速、灵活、明确的数据结构,旨在简单、直观地处理关系型、标记型数据。Pandas 的目标是成为 Python 数据分析实践与实战的必备高级工具,其长远目标是成为最强大、最灵活、可以支持任何语言的开源数据分析工具。经过多年不懈的努力,Pandas 离这个目标已经越来越近了。

Pandas 适用于处理以下类型的数据:

  • 与 SQL 或 Excel 表类似的,含异构列的表格数据;
  • 有序和无序(非固定频率)的时间序列数据;
  • 带行列标签的矩阵数据,包括同构或异构型数据;
  • 任意其它形式的观测、统计数据集, 数据转入 Pandas 数据结构时不必事先标记。

Pandas 的主要数据结构是 Series(一维数据)与 DataFrame(二维数据),这两种数据结构足以处理金融、统计、社会科学、工程等领域里的大多数典型用例。对于 R 用户,DataFrame 提供了比 R 语言 data.frame 更丰富的功能。Pandas 基于 NumPy 开发,可以与其它第三方科学计算支持库完美集成。

Pandas 就像一把万能瑞士军刀,下面仅列出了它的部分优势 :

  • 处理浮点与非浮点数据里的缺失数据,表示为 NaN;
  • 大小可变:插入或删除 DataFrame 等多维对象的列;
  • 自动、显式数据对齐:显式地将对象与一组标签对齐,也可以忽略标签,在 Series、DataFrame 计算时自动与数据对齐;
  • 强大、灵活的分组(group by)功能:拆分-应用-组合数据集,聚合、转换数据;
  • 把 Python 和 NumPy 数据结构里不规则、不同索引的数据轻松地转换为 DataFrame 对象;
  • 基于智能标签,对大型数据集进行切片、花式索引、子集分解等操作;
  • 直观地合并(merge)、**连接(join)**数据集;
  • 灵活地重塑(reshape)、**透视(pivot)**数据集;
  • 轴支持结构化标签:一个刻度支持多个标签;
  • 成熟的 IO 工具:读取文本文件(CSV 等支持分隔符的文件)、Excel 文件、数据库等来源的数据,利用超快的 HDF5 格式保存 / 加载数据;
  • 时间序列:支持日期范围生成、频率转换、移动窗口统计、移动窗口线性回归、日期位移等时间序列功能。

这些功能主要是为了解决其它编程语言、科研环境的痛点。处理数据一般分为几个阶段:数据整理与清洗、数据分析与建模、数据可视化与制表,Pandas 是处理数据的理想工具。

其它说明:

  • Pandas 速度很快。Pandas 的很多底层算法都用 Cython 优化过。然而,为了保持通用性,必然要牺牲一些性能,如果专注某一功能,完全可以开发出比 Pandas 更快的专用工具。
  • Pandas 是 statsmodels 的依赖项,因此,Pandas 也是 Python 中统计计算生态系统的重要组成部分。
  • Pandas 已广泛应用于金融领域。

数据结构

维数名称描述
1Series带标签的一维同构数组
2DataFrame带标签的,大小可变的,二维异构表格

Pandas 数据结构就像是低维数据的容器。比如,DataFrame 是 Series 的容器,Series 则是标量的容器。使用这种方式,可以在容器中以字典的形式插入或删除对象。

此外,通用 API 函数的默认操作要顾及时间序列与截面数据集的方向。多维数组存储二维或三维数据时,编写函数要注意数据集的方向,这对用户来说是一种负担;如果不考虑 C 或 Fortran 中连续性对性能的影响,一般情况下,不同的轴在程序里其实没有什么区别。Pandas 里,轴的概念主要是为了给数据赋予更直观的语义,即用“更恰当”的方式表示数据集的方向。这样做可以让用户编写数据转换函数时,少费点脑子。

处理 DataFrame 等表格数据时,index(行)或 columns(列)比 axis 0 和 axis 1 更直观。用这种方式迭代 DataFrame 的列,代码更易读易懂:

大小可变与数据复制

Pandas 所有数据结构的值都是可变的,但数据结构的大小并非都是可变的,比如,Series 的长度不可改变,但 DataFrame 里就可以插入列。

Pandas 里,绝大多数方法都不改变原始的输入数据,而是复制数据,生成新的对象。 一般来说,原始输入数据不变更稳妥。


DataFrame

创建

1
2
3
4
5
6
7
8
9
import pandas as pd
import numpy as np

stock_change = np.random.normal(loc=0, scale=1, size=(8, 5))
# 添加行索引
stock = ["股票{}".format(i) for i in range(8)]
# 添加列索引
date = pd.date_range(start="20180101", periods=5, freq="B")
print(pd.DataFrame(stock_change, index=stock, columns=date))

输出

1
2
3
4
5
6
7
8
9
     2018-01-01  2018-01-02  2018-01-03  2018-01-04  2018-01-05
股票0 -0.486596 -1.022783 0.887238 -2.115517 -0.797992
股票1 -1.248282 0.070521 -0.529684 -1.883903 -0.153754
股票2 -0.267424 -0.105139 1.883874 0.680138 -0.371504
股票3 -1.378413 -0.315324 -0.094621 0.041267 0.446303
股票4 -0.177192 0.981938 1.864708 0.979935 -0.368555
股票5 0.156191 -0.231942 0.812946 -0.999557 1.179616
股票6 -0.464277 0.008084 -0.821086 -0.154590 -1.361048
股票7 0.235237 0.159509 0.034401 -1.820553 2.109502

属性

1
2
3
4
5
6
7
print(data.shape)
print(data.index) # 行索引
print(data.columns) # 列索引
print(data.values)
print(data.T)
print(data.head(3)) # 返回前3行,默认是5
print(data.tail()) # 默认返回后5行

修改索引,重置索引

1
2
3
4
5
6
7
8
9
10
# 修改索引
print("-----修改索引-----")
# 不能进行单个修改,只能整体修改
# data.index[1] = "股票88"
data.index = ["股票{}".format(i*i) for i in range(8)]
print(data.index)

# 重置索引
print(data.reset_index())
print(data.reset_index(drop=True))

输出

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
Index(['股票0', '股票1', '股票4', '股票9', '股票16', '股票25', '股票36', '股票49'], dtype='object')
index 2018-01-01 00:00:00 ... 2018-01-04 00:00:00 2018-01-05 00:00:00
0 股票0 0.847878 ... 0.456471 -1.729287
1 股票1 -1.521886 ... -0.102665 1.081724
2 股票4 -0.256047 ... -0.630488 2.886318
3 股票9 0.769578 ... -0.320012 0.754771
4 股票16 -0.401677 ... -1.381074 0.191465
5 股票25 1.865108 ... 1.219035 0.937094
6 股票36 -0.317925 ... -0.447988 -1.343928
7 股票49 -1.760294 ... 0.248152 0.475328

[8 rows x 6 columns]
2018-01-01 2018-01-02 2018-01-03 2018-01-04 2018-01-05
0 0.847878 -0.043265 -0.470509 0.456471 -1.729287
1 -1.521886 -1.308316 -1.427331 -0.102665 1.081724
2 -0.256047 -0.269125 -1.229579 -0.630488 2.886318
3 0.769578 0.030514 -0.141035 -0.320012 0.754771
4 -0.401677 1.628133 1.290187 -1.381074 0.191465
5 1.865108 0.329742 -0.790539 1.219035 0.937094
6 -0.317925 0.518043 -0.997188 -0.447988 -1.343928
7 -1.760294 0.609189 -1.660057 0.248152 0.475328

设置新索引

1
2
3
4
5
6
7
8
# 设置新索引
df = pd.DataFrame({'month': [1, 4, 7, 10],
'year': [2012, 2014, 2013, 2014],
'sale':[55, 40, 84, 31]})
print(df.set_index("month", drop=True))
new_df = df.set_index(["year", "month"], drop=True)
print(new_df)
print(new_df.index)

输出

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
       year  sale
month
1 2012 55
4 2014 40
7 2013 84
10 2014 31

sale
year month
2012 1 55
2014 4 40
2013 7 84
2014 10 31

MultiIndex([(2012, 1),
(2014, 4),
(2013, 7),
(2014, 10)],
names=['year', 'month'])

索引操作

1
2
3
4
5
6
7
# 先列后行
print(data["open"]["2018-02-26"])
# 先行后列
print(data.loc["2018-02-26"]["open"])
print(data.iloc[1][0])
# 组合索引
print(data.iloc[0:4, data.columns.get_indexer(["open", "close", "high", "low"])])

输出

1
2
3
4
5
6
7
8
22.8
22.8
22.8
open close high low
2018-02-27 23.53 24.16 25.88 23.53
2018-02-26 22.80 23.53 23.78 22.80
2018-02-23 22.88 22.82 23.37 22.71
2018-02-22 22.25 22.28 22.76 22.02

Series

1
2
3
4
5
6
7
8
9
10
11
import numpy as np
import pandas as pd

data = pd.Series(np.arange(10))
print(data, end="\n\n")

data = pd.Series([6.5, 2.6, 9, 23.5, 4], index=[1, 2, 3, 4, 5])
print(data, end="\n\n")

data = pd.Series({"red": 100, "blue": 200, "yellow": 1000, "green": 500})
print(data, end="\n\n")

输出

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
0    0
1 1
2 2
3 3
4 4
5 5
6 6
7 7
8 8
9 9
dtype: int32

1 6.5
2 2.6
3 9.0
4 23.5
5 4.0
dtype: float64

red 100
blue 200
yellow 1000
green 500
dtype: int64

修改控制台显示

查看pandas的文档,这个问题可以通过pandas内置的set_option()方法解决,从上面的属性设置中可以看到,与显示的行数列数有关的选项主要是【display】中的【max_columns,max_rows,max_colwidth,line_width】等这几项,只需要将这几项属性值设置得大一些就可以解决。

1
2
3
4
5
6
import pandas as pd

pd.set_option('display.max_columns', 1000)
pd.set_option('display.width', 1000)
pd.set_option('display.max_colwidth', 1000)
pd.set_option('display.max_rows', 1000)

排序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import pandas as pd

pd.set_option('display.max_columns', 1000)
pd.set_option('display.width', 1000)
pd.set_option('display.max_colwidth', 1000)
# pd.set_option('display.max_rows', 1000)


data = pd.read_csv("stock_day.csv")
# 按内容进行排序
print(data.sort_values(by="high", ascending=False).head(), end="\n\n\n")
print(data.sort_values(by=["high", "close"], ascending=False).head(), end="\n\n\n")
# 按索引进行排序
print(data.sort_index(ascending=False).head(), end="\n\n\n")


sr = data["open"]
# 只有一个值,不需要指定了
print(sr.sort_values().head(), end="\n\n\n")

输出

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
             open   high  close    low     volume  price_change  p_change     ma5    ma10    ma20      v_ma5     v_ma10     v_ma20  turnover
2015-06-10 34.10 36.35 33.85 32.23 269033.12 0.51 1.53 30.538 28.660 27.424 176305.53 152266.76 149078.50 9.21
2015-06-12 34.69 35.98 35.21 34.01 159825.88 0.82 2.38 33.420 30.513 28.683 197248.25 154480.41 153888.00 5.47
2017-10-31 32.62 35.22 34.44 32.20 361660.88 2.38 7.42 32.350 30.077 28.406 372824.04 334531.90 241075.48 9.05
2015-06-15 34.99 34.99 31.69 31.69 199369.53 -3.52 -10.00 33.696 30.964 29.114 201148.55 164608.26 158362.17 6.82
2015-06-11 33.17 34.98 34.39 32.51 173075.73 0.54 1.59 32.016 29.572 28.036 193141.45 151337.71 151428.57 5.92


open high close low volume price_change p_change ma5 ma10 ma20 v_ma5 v_ma10 v_ma20 turnover
2015-06-10 34.10 36.35 33.85 32.23 269033.12 0.51 1.53 30.538 28.660 27.424 176305.53 152266.76 149078.50 9.21
2015-06-12 34.69 35.98 35.21 34.01 159825.88 0.82 2.38 33.420 30.513 28.683 197248.25 154480.41 153888.00 5.47
2017-10-31 32.62 35.22 34.44 32.20 361660.88 2.38 7.42 32.350 30.077 28.406 372824.04 334531.90 241075.48 9.05
2015-06-15 34.99 34.99 31.69 31.69 199369.53 -3.52 -10.00 33.696 30.964 29.114 201148.55 164608.26 158362.17 6.82
2015-06-11 33.17 34.98 34.39 32.51 173075.73 0.54 1.59 32.016 29.572 28.036 193141.45 151337.71 151428.57 5.92


open high close low volume price_change p_change ma5 ma10 ma20 v_ma5 v_ma10 v_ma20 turnover
2018-02-27 23.53 25.88 24.16 23.53 95578.03 0.63 2.68 22.942 22.142 22.875 53782.64 46738.65 55576.11 2.39
2018-02-26 22.80 23.78 23.53 22.80 60985.11 0.69 3.02 22.406 21.955 22.942 40827.52 42736.34 56007.50 1.53
2018-02-23 22.88 23.37 22.82 22.71 52914.01 0.54 2.42 21.938 21.929 23.022 35119.58 41871.97 56372.85 1.32
2018-02-22 22.25 22.76 22.28 22.02 36105.01 0.36 1.64 21.446 21.909 23.137 35397.58 39904.78 60149.60 0.90
2018-02-14 21.49 21.99 21.92 21.48 23331.04 0.44 2.05 21.366 21.923 23.253 33590.21 42935.74 61716.11 0.58


2015-03-02 12.25
2015-09-02 12.30
2015-03-03 12.52
2015-03-04 12.80
2015-03-05 12.88
Name: open, dtype: float64

运算

算术运算

1
2
3
print(data["open"].add(3).head())
print(data.sub(100).head())
print(data["close"].sub(data["open"]).head())

输出

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
2018-02-27    26.53
2018-02-26 25.80
2018-02-23 25.88
2018-02-22 25.25
2018-02-14 24.49

Name: open, dtype: float64
open high close low ... v_ma5 v_ma10 v_ma20 turnover
2018-02-27 -76.47 -74.12 -75.84 -76.47 ... 53682.64 46638.65 55476.11 -97.61
2018-02-26 -77.20 -76.22 -76.47 -77.20 ... 40727.52 42636.34 55907.50 -98.47
2018-02-23 -77.12 -76.63 -77.18 -77.29 ... 35019.58 41771.97 56272.85 -98.68
2018-02-22 -77.75 -77.24 -77.72 -77.98 ... 35297.58 39804.78 60049.60 -99.10
2018-02-14 -78.51 -78.01 -78.08 -78.52 ... 33490.21 42835.74 61616.11 -99.42

[5 rows x 14 columns]
2018-02-27 0.63
2018-02-26 0.73
2018-02-23 -0.06
2018-02-22 0.03
2018-02-14 0.43
dtype: float64

逻辑运算

1
2
3
4
print(data[data["open"] > 33])
print(data[(data["open"] > 33) & (data["low"] < 33)])
print(data.query("open > 33 & low < 33"))
print(data["turnover"].isin([2.39, 1.53, 1.32]))

输出

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
             open   high  close  ...     v_ma10     v_ma20  turnover
2017-11-01 33.85 34.34 33.83 ... 346829.10 233701.92 5.81
2015-06-15 34.99 34.99 31.69 ... 164608.26 158362.17 6.82
2015-06-12 34.69 35.98 35.21 ... 154480.41 153888.00 5.47
2015-06-11 33.17 34.98 34.39 ... 151337.71 151428.57 5.92
2015-06-10 34.10 36.35 33.85 ... 152266.76 149078.50 9.21

[5 rows x 14 columns]

open high close ... v_ma10 v_ma20 turnover
2015-06-15 34.99 34.99 31.69 ... 164608.26 158362.17 6.82
2015-06-11 33.17 34.98 34.39 ... 151337.71 151428.57 5.92
2015-06-10 34.10 36.35 33.85 ... 152266.76 149078.50 9.21
[3 rows x 14 columns]
open high close ... v_ma10 v_ma20 turnover
2015-06-15 34.99 34.99 31.69 ... 164608.26 158362.17 6.82
2015-06-11 33.17 34.98 34.39 ... 151337.71 151428.57 5.92
2015-06-10 34.10 36.35 33.85 ... 152266.76 149078.50 9.21
[3 rows x 14 columns]


2018-02-27 True
2018-02-26 True
2018-02-23 True
2018-02-22 False
2018-02-14 False
...
2015-03-06 False
2015-03-05 False
2015-03-04 False
2015-03-03 False
2015-03-02 False

统计运算

1
2
3
print(data.describe())
data.max(axis=1) # 默认是0(列)
print(data.idxmax())

输出

50%就是中位数了

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
[8 rows x 14 columns]
2018-02-27 95578.03
2018-02-26 60985.11
2018-02-23 56372.85
2018-02-22 60149.60
2018-02-14 61716.11
...
2015-03-06 179831.72
2015-03-05 98904.79
2015-03-04 100812.93
2015-03-03 139071.61
2015-03-02 96291.73
Length: 643, dtype: float64


open 2015-06-15
high 2015-06-10
close 2015-06-12
low 2015-06-12
volume 2017-10-26
price_change 2015-06-09
p_change 2015-08-28
ma5 2015-06-15
ma10 2015-06-18
ma20 2015-06-18
v_ma5 2017-10-26
v_ma10 2017-11-02
v_ma20 2017-11-15
turnover 2017-10-26
dtype: object

累计统计函数

函数解释
cumprod累积
cumsum累和
cummin累计中最小的值
cummax累计中最大的值
1
2
3
print(data["p_change"].sort_index().cumsum())
data["p_change"].sort_index().cumsum().plot()
plt.show()

输出

1
2
3
4
5
6
7
8
9
10
11
12
2015-03-02      2.62
2015-03-03 4.06
2015-03-04 5.63
2015-03-05 7.65
2015-03-06 16.16
...
2018-02-14 112.59
2018-02-22 114.23
2018-02-23 116.65
2018-02-26 119.67
2018-02-27 122.35
Name: p_change, Length: 643, dtype: float64


自定义显示

1
2
# 自定义运算
print(data[["open", "close"]].apply(lambda x: x.max() - x.min(), axis=0))

输出

1
2
3
open     22.74
close 22.85
dtype: float64

图形显示

1
2
3
4
5
6
7
import pandas as pd
# 一定要导入
import matplotlib.pyplot as plt

data["p_change"].sort_index().cumsum().plot()
# 展示
plt.show()

1
2
3
4
5
6
7
8
9
10
import pandas as pd
import matplotlib.pyplot as plt

data = pd.read_csv("stock_day.csv")

data.plot(x="volume", y="turnover", kind="scatter")
plt.show()

data.plot(x="high", y="low", kind="scatter")
plt.show()

在这里插入图片描述


文件的读取和存储

读取CSV

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import pandas as pd

# 读取csv
# 带字段
data = pd.read_csv("stock_day.csv", usecols=["high", "low", "open", "close"])
print(data)

# 不带字段,自己指定
data = pd.read_csv("stock_day2.csv", names=["open", "high", "close", "low", "volume", "price_change", "p_change", "ma5", "ma10", "ma20", "v_ma5", "v_ma10", "v_ma20", "turnover"])
print(data)

# 保存'open'列的数据
data[:10]["open"].to_csv("test_open.csv")
data[:10].to_csv("test_open2.csv", columns=["open"], index=False, mode="w", header=False)
print(pd.read_csv("test_open2.csv"))

输出

1
2
3
4
5
6
7
8
9
10
   23.53
0 22.80
1 22.88
2 22.25
3 21.49
4 21.40
5 20.70
6 21.20
7 21.79
8 22.69

文件


读取HDF5

1
2
3
4
5
6
7
8
9
10
11
12
13
import pandas as pd

# 读取文件
day_close = pd.read_hdf("stock_data/day/day_close.h5")
print(day_close)

# 保存文件,指定key
day_close.to_hdf("test_day.h5", key="close")
pd.read_hdf("stock_data/day/day_open.h5").to_hdf("test_day.h5", key="open")

# 此时有两个test_day.h5文件,必须要指定key才能读取
print(pd.read_hdf("test_day.h5", key="close"))
print(pd.read_hdf("test_day.h5", key="open"))


读取Json

1
2
3
4
5
6
import pandas as pd

data = pd.read_json("Sarcasm_Headlines_Dataset.json", orient="records", lines=True)
print(data)

data.to_json("test.json", orient="records", lines=True)

缺失值处理(nan)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import pandas as pd
import numpy as np


movie = pd.read_csv("IMDB/IMDB-Movie-Data.csv")

# 缺失值判断
print(np.any(pd.isna(movie))) # 为True,就表明存在nan
print(np.all(pd.notna(movie))) # 为False,就表明存在nan
print(pd.isna(movie).any())
print(pd.isnull(movie).any())
print(pd.notnull(movie).all())

# 缺失值处理
# 方法一:删除含有缺失值的样本
movie_drop = movie.dropna()
# movie_drop = movie.dropna(inplace=True)


# 方法二:替换,inplace在原表中修改
movie["Revenue (Millions)"].fillna(movie["Revenue (Millions)"].mean, inplace=True)
movie["Metascore"].fillna(movie["Metascore"].mean, inplace=True)
print(pd.isna(movie).any())

输出

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
True
False

Rank False
Title False
Genre False
Description False
Director False
Actors False
Year False
Runtime (Minutes) False
Rating False
Votes False
Revenue (Millions) True
Metascore True
dtype: bool

...其他的省略了

缺失值处理(其他标记)

将特殊标记替换成我们的nan,然后按nan的方式进行处理就可以了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 获取数据
path = "https://archive.ics.uci.edu/ml/machine-learning-databases/breast-cancer-wisconsin/breast-cancer-wisconsin.data"
name = ["Sample code number", "Clump Thickness", "Uniformity of Cell Size", "Uniformity of Cell Shape", "Marginal Adhesion", "Single Epithelial Cell Size", "Bare Nuclei", "Bland Chromatin", "Normal Nucleoli", "Mitoses", "Class"]
data = pd.read_csv(path, names=name)

print(data[data["Bare Nuclei"] == "?"])
# 替换缺失值
data_new = data.replace(to_replace="?", value=np.nan)
print(data_new[data_new["Bare Nuclei"].isna()])


# 处理缺失值
# 方法一:删除
data_new.dropna(inplace=True)
print(data_new.isna().any())
# 方法二:替换(以处理nan的方式处理就可以了)

输出(部分输出)

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
     Sample code number  Clump Thickness  Uniformity of Cell Size  Uniformity of Cell Shape  Marginal Adhesion  Single Epithelial Cell Size Bare Nuclei  Bland Chromatin  Normal Nucleoli  Mitoses  Class
23 1057013 8 4 5 1 2 ? 7 3 1 4
40 1096800 6 6 6 9 6 ? 7 8 1 2
139 1183246 1 1 1 1 1 ? 2 1 1 2



Sample code number Clump Thickness Uniformity of Cell Size Uniformity of Cell Shape Marginal Adhesion Single Epithelial Cell Size Bare Nuclei Bland Chromatin Normal Nucleoli Mitoses Class
23 1057013 8 4 5 1 2 NaN 7 3 1 4
40 1096800 6 6 6 9 6 NaN 7 8 1 2
139 1183246 1 1 1 1 1 NaN 2 1 1 2
145


Sample code number False
Clump Thickness False
Uniformity of Cell Size False
Uniformity of Cell Shape False
Marginal Adhesion False
Single Epithelial Cell Size False
Bare Nuclei False
Bland Chromatin False
Normal Nucleoli False
Mitoses False
Class False
dtype: bool

数据离散化

介绍

数据离散化是一个非常重要的思想。

为什么要离散化?当以权值为下标的时候,有时候值太大,存不下。 所以把要离散化的每一个数组里面的数映射到另一个值小一点的数组里面去。

打个比方,某个题目告诉你有104个数,每个数大小不超过1010,要你对这些数进行操作,那么肯定不能直接开1010大小的数组,但是104的范围就完全没问题。

我们来看一下定义:离散化,把无限空间中有限的个体映射到有限的空间中去,以此提高算法的时空效率。(by百度百科)

通俗的说,离散化是在不改变数据相对大小的条件下,对数据进行相应的缩小。例如:

原数据:1,999,100000,15;处理后:1,3,4,2;

原数据:{100,200},{20,50000},{1,400};

处理后:{3,4},{2,6},{1,5};

但是离散化仅适用于只关注元素之间的大小关系而不关注元素本身的值!


操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import pandas as pd

pd.set_option("display.max_columns", 1000)
pd.set_option("display.width", 1000)

data = pd.Series([165,174,160,180,159,163,192,184], index=['No1:165', 'No2:174','No3:160', 'No4:180', 'No5:159', 'No6:163', 'No7:192', 'No8:184'])

# 分位数分组
sr = pd.qcut(data, 3)
# 转换为one-hot编码
print(pd.get_dummies(sr, prefix="height"))

# 自定义分组(bins)
sr = pd.cut(data, 3) # 平均分组
print(pd.get_dummies(sr, prefix="height"))

bins = [150, 165, 180, 195]
sr = pd.cut(data, bins) # 指定分组
print(pd.get_dummies(sr, prefix="height"))

# 统计
print(sr.value_counts())

输出

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
         height_(158.999, 163.667]  height_(163.667, 178.0]  height_(178.0, 192.0]
No1:165 0 1 0
No2:174 0 1 0
No3:160 1 0 0
No4:180 0 0 1
No5:159 1 0 0
No6:163 1 0 0
No7:192 0 0 1
No8:184 0 0 1
height_(158.967, 170.0] height_(170.0, 181.0] height_(181.0, 192.0]
No1:165 1 0 0
No2:174 0 1 0
No3:160 1 0 0
No4:180 0 1 0
No5:159 1 0 0
No6:163 1 0 0
No7:192 0 0 1
No8:184 0 0 1
height_(150, 165] height_(165, 180] height_(180, 195]
No1:165 1 0 0
No2:174 0 1 0
No3:160 1 0 0
No4:180 0 1 0
No5:159 1 0 0
No6:163 1 0 0
No7:192 0 0 1
No8:184 0 0 1

(150, 165] 4
(180, 195] 2
(165, 180] 2
dtype: int64

股票案例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import pandas as pd


pd.set_option('display.max_columns', 1000)
pd.set_option('display.width', 1000)
pd.set_option('display.max_colwidth', 1000)
pd.set_option('display.max_rows', 1000)

stock = pd.read_csv("stock_day.csv")
p_change = stock["p_change"]
sr = pd.qcut(p_change, 10)
data_ = pd.get_dummies(sr, prefix="p_change")

print(data_.head())

输出


合并

按方向合并

1
2
3
4
5
6
7
8
import pandas as pd

stock = pd.read_csv("stock_day.csv")
open = pd.read_csv("stock_day.csv")

print(stock.shape)
print(pd.concat([stock, open], axis=1).shape)
print(pd.concat([stock, open], axis=0).shape)

输出

1
2
3
(643, 14)
(643, 28)
(1286, 14)

按索引合并

pandas中的merge()函数类似于SQL中join的用法,可以将不同数据集依照某些字段(属性)进行合并操作,得到一个新的数据集。

1
def merge(left, right, how: str = "inner",on=None,left_on=None, right_on=None, left_index: bool = False,right_index: bool = False,sort: bool = False, suffixes=("_x", "_y"),copy: bool = True,indicator: bool = False,validate=None,) 
参数说明
how默认为inner,可设为inner/outer/left/right
on根据某个字段进行连接,必须存在于两个DateFrame中(若未同时存在,则需要分别使用left_on和right_on来设置)
left_on左连接,以DataFrame1中用作连接键的列
right_on右连接,以DataFrame2中用作连接键的列
left_index将DataFrame1行索引用作连接键
right_index将DataFrame2行索引用作连接键
sort根据连接键对合并后的数据进行排列,默认为True
suffixes对两个数据集中出现的重复列,新数据集中加上后缀_x,_y进行区别

例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
left = pd.DataFrame({'key1': ['K0', 'K0', 'K1', 'K2'],
'key2': ['K0', 'K1', 'K0', 'K1'],
'A': ['A0', 'A1', 'A2', 'A3'],
'B': ['B0', 'B1', 'B2', 'B3']})

right = pd.DataFrame({'key1': ['K0', 'K1', 'K1', 'K2'],
'key2': ['K0', 'K0', 'K0', 'K0'],
'C': ['C0', 'C1', 'C2', 'C3'],
'D': ['D0', 'D1', 'D2', 'D3']})

print(pd.merge(left, right, how="inner", on=["key1"]), end="\n\n")
print(pd.merge(left, right, how="inner", on=["key1", "key2"]), end="\n\n")
print(pd.merge(left, right, how="left", on=["key1", "key2"]))
print(pd.merge(left, right, how="outer", on=["key1", "key2"]))

输出

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
  key1 key2_x   A   B key2_y   C   D
0 K0 K0 A0 B0 K0 C0 D0
1 K0 K1 A1 B1 K0 C0 D0
2 K1 K0 A2 B2 K0 C1 D1
3 K1 K0 A2 B2 K0 C2 D2
4 K2 K1 A3 B3 K0 C3 D3

key1 key2 A B C D
0 K0 K0 A0 B0 C0 D0
1 K1 K0 A2 B2 C1 D1
2 K1 K0 A2 B2 C2 D2

key1 key2 A B C D
0 K0 K0 A0 B0 C0 D0
1 K0 K1 A1 B1 NaN NaN
2 K1 K0 A2 B2 C1 D1
3 K1 K0 A2 B2 C2 D2
4 K2 K1 A3 B3 NaN NaN

key1 key2 A B C D
0 K0 K0 A0 B0 C0 D0
1 K0 K1 A1 B1 NaN NaN
2 K1 K0 A2 B2 C1 D1
3 K1 K0 A2 B2 C2 D2
4 K2 K1 A3 B3 NaN NaN
5 K2 K0 NaN NaN C3 D3

交叉表和透视表

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
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt


stock = pd.read_csv("stock_day.csv")


# 准备涨跌幅数据列
stock["pona"] = np.where(stock["p_change"] > 0, 1, 0)
print(stock[stock["pona"] == 0]["pona"].value_counts(), end="\n\n")
date = pd.to_datetime(stock.index)
stock["week"] = date.weekday

# 交叉表操作
stock_wp = pd.crosstab(stock["week"], stock["pona"])
print(stock_wp, end="\n\n")

data = stock_wp.div(stock_wp.sum(axis=1), axis=0)
print(data)
data.plot(kind="bar", stacked=True)
# plt.show()

# 透视表操作
print(stock.pivot_table(["pona"], index=["week"]))

输出

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
0    301
Name: pona, dtype: int64

pona 0 1
week
0 63 62
1 55 76
2 61 71
3 63 65
4 59 68

pona 0 1
week
0 0.504000 0.496000
1 0.419847 0.580153
2 0.462121 0.537879
3 0.492188 0.507812
4 0.464567 0.535433

pona
week
0 0.496000
1 0.580153
2 0.537879
3 0.507812
4 0.535433


分组与聚合

操作

1
2
3
4
5
6
7
import pandas as pd

col =pd.DataFrame({'color': ['white','red','green','red','green'], 'object': ['pen','pencil','pencil','ashtray','pen'],'price1':[5.56,4.20,1.30,0.56,2.75],'price2':[4.75,4.12,1.60,0.75,3.15]})
# 进行分组,在进行聚合
print(col.groupby(by="color"))
print(col.groupby(by="color")["price1"].max())
print(col["price1"].groupby(col["color"]).max())

输出

1
2
3
4
5
6
7
8
9
10
11
12
13
<pandas.core.groupby.generic.DataFrameGroupBy object at 0x000001A40053D1C0>

color
green 2.75
red 4.20
white 5.56
Name: price1, dtype: float64

color
green 2.75
red 4.20
white 5.56
Name: price1, dtype: float64

案例

1
2
3
4
5
6
7
# 准备数据
starbucks = pd.read_csv("directory.csv")
# 按国家进行分组
starbucks_brand = starbucks.groupby(by=["Country", "State/Province"]).count()["Brand"].sort_values(ascending=False).head(10)
print(starbucks_brand)
starbucks_brand.plot(kind="bar", figsize=(20, 8), fontsize=40)
plt.show()

输出

1
2
3
4
5
6
7
8
9
10
11
12
Country  State/Province
US CA 2821
TX 1042
GB ENG 787
US WA 757
FL 694
NY 645
IL 575
CN 31 551
CA ON 534
US AZ 488
Name: Brand, dtype: int64


综合案例

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
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt


pd.set_option('display.max_columns', 1000)
pd.set_option('display.width', 1000)
pd.set_option('display.max_colwidth', 1000)
pd.set_option('display.max_rows', 1000)

# 读取数据
movie = pd.read_csv("./IMDB/IMDB-Movie-Data.csv")
print(movie.head())

# 平均分
score_aver = movie["Metascore"].mean()
print(score_aver)

# 导演的人数
movie_director = np.unique(movie["Director"])
movie_director_sum = movie_director.size
print(movie_director_sum)

# 呈现Rating,Runtime的分布情况
# movie["Rating"].plot(kind="hist", figsize=(20, 8), fontsize=50, grid="--")
plt.figure(figsize=(20, 8), dpi=80)
plt.hist(movie["Rating"], 20)
plt.xticks(np.linspace(movie["Rating"].min(), movie["Rating"].max(), 21))
plt.grid(linestyle="--", alpha=0.5)
plt.show()

# 统计电影分类情况
# movie_genre = movie.groupby(by="Genre").count()["Rank"].sort_values(ascending=False)
# 先获取电影的类别有哪些
movie_genre = [i.split(",") for i in movie["Genre"]]
movie_class = np.unique([j for i in movie_genre for j in i])
# 统计每个类别有几个电影
count = pd.DataFrame(np.zeros(shape=[1000, 20], dtype=np.int_), columns=movie_class)
for i in range(movie.count()["Rank"]):
count.loc[i, movie_genre[i]] = 1
print(count.head())
# 画图
count.sum().sort_values(ascending=False).plot(kind="bar", figsize=(20, 8), fontsize=30, colormap="cool")
plt.show()

输出

总结


-------------本文结束感谢您的阅读-------------
六经蕴籍胸中久,一剑十年磨在手

欢迎关注我的其它发布渠道