matplotlib, Numpy, Pandas
由于有很多例子是需要运算后的图表看着更明白一些,很明显csdn不支持
所以用谷歌的Colab(可以理解为白嫖谷歌的云端来运行的jupyter notebook)来展示:
Colab链接(需要梯子):Python数据挖掘
当然如果实在没有梯子,那就凑合着往下看吧,我也懒得整理格式了(
目录一览:
正文
1.配置环境
1.1 基础包安装
pip install matplotlib
pip install numpy
pip install pandas
pip install jupyter
1.2 作用
- matplotlib: 画图
- numpy: 运算
- pandas: 数据处理
- jupyter:笔记/展示
2.Matplotlib画图
2.1 什么是matplotlib
- 开发2D图表,简单,渐进交互式实现数据可视化
- js(D3/echarts)同样可以实现可视化,但根据奥卡姆剃刀原理:如无必要勿增实体,给自己看不需要那么复杂。
- matplotlib官方文档
2.2 图像包含的信息以及具体描述
2.3 Matplotlib三层结构
1. 容器层(Container Layer)
容器层是最底层,提供了图表的物理容器:
- 画板层(Canvas): 是最底层的容器,代表了绘图的物理表面。在显示器或其他设备上,它是实际绘制图形的地方,但通常不需要直接与之交互。
- 画布层(Figure):
plt.figure()
用于创建一个画布,在这个画布上可以添加一个或多个绘图区(Axes)。Figure是最顶层的容器,用于包含图表中的所有元素。 - 绘图区/坐标系(Axes):
plt.subplots()
用于在Figure上添加绘图区,这是实际绘制图形的地方,每个Axes对象可以看作是一个独立的图表。
2. 辅助显示层(Artist Layer)
这一层包括了图表中的所有可视化元素,除了基本的图像以外,还有用于增强理解的辅助图形,例如:
- 标题(Title): 图表的标题,用于简要说明图表的主题。
- 图例(Legend): 用于解释图表中的符号或颜色。
- 网格(Grid): 背景上的网格线,用于更好地量化图表中的数据点。
- 坐标轴(Axis): 包括坐标轴本身和坐标轴标签,用于显示数据的尺度和单位。
- 刻度(Ticks) 和 刻度标签(Tick Labels): 轴上的刻度和对应的标签,用于标识数据的具体值。
3. 图像层(Rendering Layer)
图像层是最顶层,用于绘制图表中的数据点,包括:
- 线条(Line plots): 用于绘制线图。
- 散点(Scatter plots): 用于绘制散点图。
- 柱状图(Bar charts): 用于绘制柱状图。
- 等高线图(Contour plots): 用于绘制等高线图。
- 图像(Images): 直接在图表中显示图像。
2.4 各种图的应用场景
1. 折线图(Line Plot)(时间变化)
作用:折线图主要用于展示数据随时间或有序类别变化的趋势。它通过将数据点按顺序连接起来的线条表示,非常适合用于显示数据如何在一段时间内变化,比如股票价格的波动、气温的变化等。
特点:
- 优秀的时间序列数据展示工具。
- 易于识别趋势和模式。
2. 散点图(Scatter Plot)(关系/规律)
作用:散点图用于展示两个(或更多)变量之间的关系,每个数据点在图表中由其在两个轴上的值确定。它是研究变量之间是否存在相关性的好方法,比如身高和体重的关系。
特点:
- 显示变量之间的相关性
- 正相关:当一个变量增加时,另一个变量也增加。
- 负相关:当一个变量增加时,另一个变量减少。
- 无相关:两个变量之间没有明显的线性关系。
- 识别数据集中的异常值。
3. 柱状图(Bar Chart)(统计/对比)
作用:柱状图通过水平或垂直的柱子长度来显示不同类别间的比较。每个柱子代表一个类别,柱子的长度表示该类别的数值大小。柱状图非常适合比较多个类别之间的数值或展示每个类别随时间的变化。
特点:
- 易于比较不同类别的数值大小。
- 显示一个或多个类别的数值变化。
4. 直方图(Histogram)(分布情况)
作用:直方图是一种特殊类型的柱状图,用于表示数据的分布情况。与柱状图不同,直方图的每个柱子代表数据在某个区间(或“bin”)的频率或数量,适合用来展示数据集的统计分布,如人群的年龄分布、成绩分布等。
特点:
- 展示数据的分布情况(集中趋势、偏斜和峰度等)。
- 有助于识别数据的异常值和分布的形状。
和柱状图的区别:
- 柱状的宽在柱状图中没有意义,而直方图有意义。
- 柱状图不是连续的柱,而直方图是。
5. 饼图(Pie chart) (占比)
作用: 饼图最适合用来展示各部分相对于整体的比例大小。每个扇形的大小按其所代表的数量的比例分配,使得观众可以一目了然地看出各部分之间的比较。饼图通过不同的颜色区分不同的类别,便于观众识别和比较各个类别的占比。
2.5 折线图代码及使用示例
“”"
import matplotlib.pyplot as plt
import numpy as np
import matplotlib as mpl
Example 1
fig, ax = plt.subplots() # Create a figure containing a single axes.
ax.plot([1, 2, 3, 4], [1, 4, 2, 3]) # Plot some data on the axes.
plt.show()
Example 2
x = np.linspace(0, 2, 100) # 一组list数据
创建画板和绘图区,layout是设定自动调整所有子图参数(xy轴/线…), nrows和ncols是调整有几个绘图区,调用的时候就是ax[n].xxx即可
fig, ax = plt.subplots(figsize=(8, 4), dpi=80, layout=‘constrained’, nrows=1, ncols=1)
三条线
ax.plot(x, x, label=‘linear’, color=‘green’)
ax.plot(x, x2, label=‘quadratic’, color=‘red’)
ax.plot(x, x3, label=‘cubic’, color=‘#66ccff’)
设置xy轴
ax.set_xlabel(‘x-axis’)
ax.set_ylabel(‘y-axis’)
ax.set_title(“Title”)
添加主刻度/副刻度的网格线,which控制, alpha控制透明度
ax.grid(which=‘major’, color=‘gray’, linestyle=‘-’, linewidth=0.5, alpha=0.5)
设置x轴和y轴的范围
ax.axis([0, 3, 0, 10])
添加一个箭头,以及标注语
ax.annotate(‘end here’, xy=(2, 4), xytext=(2.5, 2.5), arrowprops=dict(facecolor=‘black’, shrink=0.05))
添加legend,也就是显示每条不同的线代表什么的小表格
ax.legend()
注意这里是画布或者画板调用show,而绘图区/坐标轴是无法调用show的
plt.show()
Example 3
x = np.linspace(0, 10, 100) # 生成0-10之间的100个数
y = np.sin(x) # 将x中的数都进行sin取值
plt.plot(x, y)
plt.xticks(ticks=np.arange(0, 11, 2), labels=[‘zero’, ‘two’, ‘four’, ‘six’, ‘eight’, ‘ten’], rotation=45) # 自定义X轴刻度,以及文字斜度
plt.show()
Example 4
x = np.linspace(0, 2, 100) # 一组list数据
创建画板和绘图区,layout是设定自动调整所有子图参数(xy轴/线…), nrows和ncols是调整有几个绘图区,调用的时候就是ax[n].xxx即可
fig, ax = plt.subplots(figsize=(12, 6), dpi=80, layout=‘constrained’, nrows=1, ncols=3)
三条线
titles = [‘linear’, ‘quadratic’, ‘cubic’]
ax[0].plot(x, x, label=titles[0], color=‘green’)
ax[1].plot(x, x2, label=titles[1], color=‘red’)
ax[2].plot(x, x3, label=titles[2], color=‘#66ccff’)
设置xy轴
for i in range(3):
ax[i].set_xlabel(‘x-axis’)
ax[i].set_ylabel(‘y-axis’)
ax[i].set_title(titles[i])
添加主刻度/副刻度的网格线,which控制, alpha控制透明度
ax[i].grid(which=‘major’, color=‘gray’, linestyle=‘-’, linewidth=0.5, alpha=0.5)
设置x轴和y轴的范围
ax[i].axis([0, 3, 0, 10])
添加legend,也就是显示每条不同的线代表什么的小表格
ax[i].legend()
注意这里是画布或者画板调用show,而绘图区/坐标轴是无法调用show的
plt.show()
“”“## 2.6 散点图代码及使用示例”“”
Example 1
x, y = [i for i in range(10)], [i for i in range(10)]
plt.figure(figsize=(10, 6), dpi=80)
plt.scatter(x, y)
plt.show()
“”"
2.7 柱状图的代码及使用示例"“”
Example 1
categories = [‘Category A’, ‘Category B’, ‘Category C’, ‘Category D’]
values = [23, 45, 56, 78]
创建柱状图
fig, ax = plt.subplots(layout=‘constrained’)
绘制柱状图
‘align’ 控制柱体与标签的对齐方式,‘edge’ 表示柱体边缘对齐到刻度标签位置
‘color’ 可以设置柱体颜色,plt.cm.tab20.colors调用系统设置好的20种容易区分的颜色
‘edgecolor’ 设置柱体边缘颜色
ax.bar(categories, values, align=‘center’, color=‘skyblue’, edgecolor=‘black’)
ax.bar(categories, values, align=‘center’, color=plt.cm.tab20.colors, edgecolor=‘black’)
添加标题和轴标签
ax.set_title(‘Values per Category’)
ax.set_xlabel(‘Categories’)
ax.set_ylabel(‘Values’)
显示数值标签
for i, value in enumerate(values):
ax.text(i, value+1, str(value), ha=‘center’)
显示网格线
ax.grid(True, axis=‘y’, linestyle=‘–’, alpha=0.7)
plt.show()
Example 2
categories = [‘Stud A’, ‘Stud B’, ‘Stud C’, ‘Stud D’]
values1 = [23, 45, 56, 78]
values2 = [36, 28, 39, 17]
fig, ax = plt.subplots(layout=‘constrained’)
width = 0.6
offset = [i for i in range(0,8,2)]
绘制柱状图时,使用偏移的位置
ax.bar(offset, values1, align=‘center’, color=“skyblue”, edgecolor=‘black’, width=width, label=‘First Exam’)
ax.bar([i+width for i in offset], values2, align=‘center’, color=“orange”, edgecolor=‘black’, width=width, label=‘Second Exam’)
设置X轴刻度标签
ax.set_xticks([i + width/2 for i in offset]) # 使用两个柱的中点位置来对齐文本
ax.set_xticklabels(categories) # 设置类别名称为X轴标签
调整文本标签的位置
for i in range(len(values1)):
ax.text(i2, values1[i]+1, str(values1[i]), ha=‘center’) # 为第一组数据设置文本标签
ax.text(i2+width, values2[i]+1, str(values2[i]), ha=‘center’) # 为第二组数据设置文本标签
ax.set_title(‘First and Second Exam score’)
ax.set_xlabel(‘Score’)
ax.set_ylabel(‘Values’)
ax.grid(True, axis=‘y’, linestyle=‘–’, alpha=0.7)
添加图例
ax.legend()
plt.show()
“”"## 2.8 直方图的代码以及使用示例
- 组数:在统计数据时,把数据按照不同的范围分成的几个组,组的个数。
- 组距:每组的两个端点的差值。
“”"
import random
import matplotlib.pyplot as plt
import numpy as np
import matplotlib as mpl
Example 1
fig, ax = plt.subplots(layout=‘constrained’, figsize=(10, 6))
data = [random.randint(50, 250) for i in range(30)] # 生成30个50-250之间的随机数据
绘制直方图
bins参数定义柱体的数量(组数),可以是一个整数或一个序列定义边界
alpha参数定义透明度,edgecolor定义柱体边缘的颜色
ax.hist(data, bins=(max(data)-min(data))//10, alpha=0.7, color=‘blue’, edgecolor=‘black’)
添加标题和轴标签
ax.set_title(‘Histogram of Random Numbers’)
ax.set_xlabel(‘Value Range’)
ax.set_ylabel(‘Frequency’)
添加网格线
ax.grid(True, which=‘both’, axis=‘both’, linestyle=‘–’, alpha=0.5)
显示图表
plt.show()
“”“## 2.9 饼图的代码以及使用示例”“”
import matplotlib.pyplot as plt
Example 1
range_name = [“NA”, “A”, “M”, “E”]
data = [0.2, 0.3, 0.4, 0.1]
创建饼图
fig, ax = plt.subplots(layout=‘constrained’, figsize=(10, 6))
绘制饼图
‘autopct’ 用于格式化百分比标签,‘explode’ 用于突出显示某一块
colors=plt.cm.tab20.colors 从colormap中调取用于类别图的颜色。
explode = (0, 0.1, 0, 0) # 例如,这里突出显示第二块
ax.pie(data, explode=explode, labels=range_name, autopct=‘%.2f%%’, startangle=90, colors=plt.cm.tab20.colors)
添加图例
ax.legend(title=“Categories”)
添加标题
ax.set_title(‘Distribution of Categories’)
显示图表
plt.show()
“”"# 3.Numpy运算库
3.1 什么是Numpy,为什么学习
- NumPy(Numerical Python的简写)是一个开源的Python库,用于支持大量的维度数组与矩阵运算,此外也针对数组运算提供了大量的数学函数库。NumPy是科学计算中一个非常重要的包,广泛应用于加载、存储和处理大型数组的快速高效处理。
- 性能:NumPy的核心是在C语言和Fortran语言编写的,这使得NumPy的运算速度比纯Python快得多。
- 多维数组支持:NumPy支持多维数组(ndarray),这是进行科学计算的基础。
- 广泛的数学函数库:NumPy提供了大量的数学函数,可以轻松地进行各种数学计算,包括线性代数、统计操作等。
- 集成:NumPy可以与各种数据分析、机器学习库无缝集成,如Pandas、SciPy、Matplotlib、scikit-learn等。
- 内存效率:NumPy的数组存储在连续的内存块中,由于较少的内存占用和快速的处理,可以处理大量数据。
3.2 numpy中的ndarray
- numpy提供的N维数组类型,描述了相同类型的items的集合,这就是ndarray
1.简单使用
“”"
import random
import numpy as np
score = np.array([
[random.randint(50,100) for i in range(5)] for i in range(5)
])
score
type(score)
“”"## 3.3 原生list和ndarray运算时间对比
- ndarray仅能存储单一类型的数据格式
- ndarray支持并行化运算
- ndarray底层语言为c,解除了GIL(全局解释器锁),不受python解释器的限制
“”"
import numpy as np
import time
创建大型列表和NumPy数组
list_size = 10000000
python_list = list(range(list_size))
numpy_array = np.array(python_list)
测量对列表的运算时间
start_time_list = time.time()
list_result = [x * 2 for x in python_list]
end_time_list = time.time()
time_for_list = end_time_list - start_time_list
测量对NumPy数组的运算时间
start_time_array = time.time()
array_result = numpy_array * 2
end_time_array = time.time()
time_for_array = end_time_array - start_time_array
print(f"list: {time_for_list}\nndarray: {time_for_array}")
“”“## 3.4 ndarray的属性”“”
import numpy as np
import random
score = np.array([
[random.randint(50,100) for i in range(5)] for i in range(8)
])
print(f"shape: {score.shape}“) # 几行几列
print(f"dtype: {score.dtype}”) # 数据类型
“”"## 3.5 ndarray shape示例
- [[1,2,3],[2,3,4]]
- (2,3),第一层两个元素,第二层三个元素。
- [1,2,3,4]
- (4,),第一层四个元素。
- [[[1,2,3],[2,3,4]],[[4,5,6],[6,7,8]]]
- (2,2,3) …
3.6 ndarray生成数组方法
- 1.生成01数组
- 2.从现有数组中生成
- 3.生成固定范围的数组
- 4.生成随机数组
“”"
import numpy as np
1.生成01数组
zero_list = np.zeros(shape=[3,3],dtype=“int32”)
one_list = np.ones(shape=[3,3])
print(zero_list, “\n\n”, one_list, “\n”)
2.从现有数组中生成
data1 = [[1,2,3],[2,3,4]]
copys = np.array(data1) # np.array是deep copy
print(copys, “\n”)
3.生成固定范围的数组
lines1 = np.linspace(0,10,5) # 生成0-10,左右闭口的,5个等距的数
lines2 = np.arange(0,10,5) # 和range效果一样
print(lines1, “\n\n”, lines2, “\n”)
4.生成随机数
random_list1 = np.random.uniform(low=-1,high=1,size=10000) # 生成均匀分布的随机数
random_list2 = np.random.normal(loc=1.75,scale=0.1,size=10000) # 生成正态分布的随机数,loc是均值,scale是差值
random_list2 = np.random.normal(0, 1, (10, 5)) 直接传递shape也可以
“”"### 3.6.1 正态分布的补充知识
1.正态分布定义
正态分布(高斯分布)是一种连续概率分布,其概率密度函数(PDF)的形式由两个参数决定:均值((\mu))和标准差((\sigma))。
2.概率密度函数
正态分布的概率密度函数为:
f ( x ∣ μ , σ ) = 1 σ 2 π e − ( x − μ ) 2 2 σ 2 f(x|\mu,\sigma) = \frac{1}{\sigma\sqrt{2\pi}} e^{-\frac{(x-\mu)^2}{2\sigma^2}} f(x∣μ,σ)=σ2π1e−2σ2(x−μ)2
- (x):随机变量的值
- (\mu):分布的均值,决定了分布的中心位置
- (\sigma):分布的标准差,描述了数据的分散程度
- (\sigma^2):方差
3.参数解释及其影响
-
均值 ((\mu)):指定了分布的中心。改变 (\mu) 会使分布沿 x 轴移动,但不会改变其形状。
-
标准差 ((\sigma)):度量了分布中数值的离散程度。较小的 (\sigma) 会让分布更紧凑,峰值更高;较大的 (\sigma) 会使分布更宽散,峰值更低。
4.np.random.normal
的使用
np.random.normal
函数允许根据正态分布生成随机数,其基本语法如下:
numpy.random.normal(loc=0.0, scale=1.0, size=None)
参数说明:
loc
:正态分布的均值 (\mu)scale
:正态分布的标准差 (\sigma)size
:生成的随机数的数量或形状shape
5.正态分布数据的生成过程
要从理论上生成一组遵循正态分布的数据,我们需要依据正态分布的概率密度函数(PDF)和其参数(均值 (\mu) 和标准差 (\sigma))。但在实际操作中,我们并不是直接使用正态分布的PDF公式来手动计算每个点的值。相反,我们通常依赖于随机数生成算法,如Box-Muller变换或Ziggurat算法,这些算法能高效地生成满足特定正态分布参数的随机数。
-
确定分布参数:首先,你需要确定正态分布的参数,即均值 (\mu) 和标准差 (\sigma)。这两个参数定义了你希望生成数据的分布特性。
-
使用随机数生成算法:实际上,生成正态分布数据的过程是通过随机数生成算法实现的,而不是直接从PDF公式计算。例如,NumPy库的
np.random.normal
函数内部使用这样的算法来生成数据。 -
生成随机样本:通过指定的算法,计算机会生成一组随机数,这些随机数在统计上遵循你所指定的正态分布(具有特定的 (\mu) 和 (\sigma))。
3.7 ndarray的重塑方法
1.reshape
reshape
方法用于在不改变数组数据的前提下,改变数组的形状。
- 语法:
numpy.reshape(a, newshape)
其中a
是要被重塑的数组,newshape
是整数或整数元组,指定了新的形状。新形状应该与原始形状兼容,即总元素数量保持不变。
- 示例:
import numpy as np
a = np.arange(6) # 创建一个数组[0, 1, 2, 3, 4, 5]
print(a.reshape(2, 3)) # 重塑为2行3列的数组
2.resize
resize
方法与reshape
类似,也用于改变数组的形状,但它可以修改原始数组,并且在需要时可以填充或截断原数组以匹配新形状。
- 语法:
numpy.resize(a, new_shape)
这里,a
是要调整大小的数组,而new_shape
是新的形状。如果新形状的总元素多于原始数组,resize
会重复数组中的元素来填充新数组。
- 示例:
import numpy as np
a = np.array([1, 2, 3, 4])
b = np.resize(a, (2, 3))
print(b)
3.T方法
T
属性是数组的转置视图,它将数组的行和列互换。
-
使用:对于二维数组,
T
简单地交换其维度。对于多于两维的数组,T
属性返回数组的简单转置,这等同于反转其轴的顺序。 -
示例:
import numpy as np
a = np.array([[1, 2], [3, 4], [5, 6]])
print(a.T) # 转置数组
3.8 ndarray的类型转换方法
1.astype方法
astype
方法用于将ndarray
数组中的元素从一种类型转换成另一种类型。这是通过创建原数组的一个新副本来实现的,副本中的数据类型被转换为指定的类型。
-
语法:
ndarray.astype(dtype, order='K', casting='unsafe', subok=True, copy=True)
-
参数:
dtype
:新的数据类型。可以是NumPy数据类型对象或表示数据类型的字符串。- 其他参数控制着转换的具体行为,但通常
dtype
是最常用的参数。
-
示例:
import numpy as np
arr = np.array([1, 2, 3, 4])
float_arr = arr.astype(np.float64)
print(float_arr) # 输出转换类型后的数组
这个示例中,整数数组被转换成了浮点数数组。
2.tobytes方法
tobytes
方法将数组的元素转换为其二进制表示形式的字符串。这在进行低级别的二进制数据操作或将数组数据保存到文件中为二进制格式时特别有用。
-
语法:
ndarray.tobytes(order='C')
-
参数:
order
:指定元素在二进制字符串中的顺序。默认为’C’,即按行主顺序排列。'F’表示按列主顺序排列。
-
示例:
import numpy as np
arr = np.array([1, 2, 3, 4], dtype=np.int32)
binary_data = arr.tobytes()
print(binary_data) # 输出二进制字符串
3.frombuffer方法
为了从二进制数据中恢复出ndarray
对象
-
语法:
numpy.frombuffer(buffer, dtype=float, count=-1, offset=0)
-
参数:
buffer
:包含原始数据的缓冲区。dtype
:数组的数据类型。- 其他参数控制着数组的形状和解释缓冲区的方式。
-
示例:
import numpy as np
binary_data = b'\x01\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00\x04\x00\x00\x00'
arr = np.frombuffer(binary_data, dtype=np.int32)
print(arr)
3.9 ndarray数组去重
1.数组去重
NumPy中去重数组的主要函数是np.unique
。这个函数不仅可以找出数组中所有唯一元素,并且按照从小到大的顺序返回这些唯一元素。
-
语法:
numpy.unique(arr, return_index=False, return_inverse=False, return_counts=False, axis=None)
-
参数:
arr
:输入数组。return_index
:如果为True
,则返回唯一元素的原始数组中的索引。return_inverse
:如果为True
,则返回一个数组,用于重建原始数组。return_counts
:如果为True
,则返回每个唯一元素在原数组中出现的次数。axis
:沿着它去重数组,默认为None
,即将数组展平后去重。
-
示例:
import numpy as np
arr = np.array([1, 2, 2],[3, 3, 4])
unique_arr = np.unique(arr)
print(unique_arr) # 输出:[1 2 3 4]
2.用途
- 数据清洗:在分析数据之前,去除重复的观察值,确保分析的准确性。
- 特征工程:在机器学习中,去重可以帮助识别和生成更有效的特征。
- 统计分析:计算唯一事件的发生次数,或者分析不同类别的数量。
- 内存优化:在处理大规模数据集时,去重可以减少内存的使用。
3.10 ndarray的逻辑运算
1.布尔索引
- 布尔索引允许你使用布尔数组来选择数组中的元素。当你在索引操作中使用布尔数组时,结果数组将只包含对应于布尔数组中
True
值位置的元素。
import numpy as np
a = np.array([1, 2, 3, 4, 5])
bool_index = a > 2 # 布尔索引
print(a[bool_index]) # 输出满足条件的元素
2.all 和 any 函数
all
:检查数组中的所有元素是否都满足某个条件(即是否都为True
)。如果是,则返回True
;否则返回False
。any
:检查数组中是否至少有一个元素满足某个条件(即为True
)。如果是,则返回True
;否则返回False
。
b = np.array([1, 2, 3, 4, 5])
condition = b > 3
print(np.all(condition)) # 检查是否所有元素都为符合条件
print(np.any(condition)) # 检查是否至少有一个元素符合条件
3.where 函数
where
函数是NumPy中的三元运算符,用于基于条件从两个数组中选择元素。它的基本用法是np.where(condition, x, y)
,其中condition
是一个布尔数组,x
和y
是可选的;当condition
的某个位置为True
时,where
将从x
中选择元素,否则从y
中选择。
使用where
- 基本用法:
c = np.array([1, 2, 3, 4])
result = np.where(c > 2, c, c*10)
print(result) # 条件为True时选择c,否则选择c*10
- 结合逻辑运算(
and
和or
):
在NumPy中进行逻辑运算时,应使用&
(逻辑与)和|
(逻辑或)代替and
和or
,同时注意条件表达式需要用括号括起来。
# 使用and条件
result_and = np.where((c > 2) & (c < 4), c, -1)
print(result_and) # 满足c>2且c<4时选择c,否则为-1
# 使用or条件
result_or = np.where((c <= 2) | (c == 4), c, -1)
print(result_or) # 满足c<=2或c==4时选择c,否则为-1
3.11 ndarray统计函数
1.常用NumPy统计函数及其作用
np.mean
或arr.mean
- 计算平均值np.median
- 计算中位数- 注意:
median
没有对应的数组方法,只能通过np.median(arr)
调用
- 注意:
np.std
或arr.std
- 计算标准差np.var
或arr.var
- 计算方差np.sum
或arr.sum
- 计算总和np.min
或arr.min
- 计算最小值np.max
或arr.max
- 计算最大值np.argmin
或arr.argmin
- 查找最小值的索引np.argmax
或arr.argmax
- 查找最大值的索引np.percentile
- 计算百分位数- 和
median
类似,percentile
也没有直接对应的数组方法
- 和
3.11.1 axis的使用
- 大部分统计函数都可以传入axis参数。
- 根据shape的下标调用即可。
- [[1,2,3,4],[2,3,4,5],[3,4,5,6]] 的shape=(3,4)
- 从代码角度来看,第一层有三个元素,第二层有四个元素。
- 从实际意义角度来看,第一层是3个学生,第二层是4个科目。
- 想要对哪个对象进行处理,直接找到shape中其下标位置即可。
“”"
import numpy as np
创建一个二维数组,表示3个学生的4门科目成绩
grades = np.array([
[88, 92, 80, 89], # 学生1
[85, 87, 86, 85], # 学生2
[78, 81, 89, 88] # 学生3
])
计算每个学生的平均成绩,即沿着科目方向(axis=1)
student_means = grades.mean(axis=1)
计算每门科目的平均成绩,即沿着学生方向(axis=0)
subject_means = grades.mean(axis=0)
print(“每个学生的平均成绩:”, student_means)
print(“每门科目的平均成绩:”, subject_means)
“”"### 3.11.2 方差/标准差的补充知识
1.方差(Variance)
方差是衡量数据分布离散程度的指标,表示各数据点与平均值之差的平方的平均值。方差的数学公式为:
σ 2 = ∑ ( x i − μ ) 2 N \sigma^2 = \frac{\sum (x_i - \mu)^2}{N} σ2=N∑(xi−μ)2
- 其中, σ 2 \sigma^2 σ2 表示方差, x i x_i xi 表示每个数据点, μ \mu μ 表示数据的平均值, N N N 是数据点的总数。
方差越大,意味着数据点相对于平均值的分散程度越大。
2.标准差(Standard Deviation)
标准差是方差的平方根,它提供了与原始数据相同单位的离散程度度量。标准差的公式为:
σ = ∑ ( x i − μ ) 2 N \sigma = \sqrt{\frac{\sum (x_i - \mu)^2}{N}} σ=N∑(xi−μ)2
- 其中, σ \sigma σ 表示标准差,其他符号与方差公式中的相同。
标准差越大,表明数据分布越分散。
3.例子
考虑一个简单的例子:一个班级里5名学生的数学成绩分别为60, 70, 80, 90, 100。
首先,计算平均成绩( μ \mu μ):
μ = 60 + 70 + 80 + 90 + 100 5 = 80 \mu = \frac{60 + 70 + 80 + 90 + 100}{5} = 80 μ=560+70+80+90+100=80
接着,计算方差( σ 2 \sigma^2 σ2):
σ 2 = ( 60 − 80 ) 2 + ( 70 − 80 ) 2 + ( 80 − 80 ) 2 + ( 90 − 80 ) 2 + ( 100 − 80 ) 2 5 = 400 + 100 + 0 + 100 + 400 5 = 200 \sigma^2 = \frac{(60-80)^2 + (70-80)^2 + (80-80)^2 + (90-80)^2 + (100-80)^2}{5} = \frac{400 + 100 + 0 + 100 + 400}{5} = 200 σ2=5(60−80)2+(70−80)2+(80−80)2+(90−80)2+(100−80)2=5400+100+0+100+400=200
最后,计算标准差( σ \sigma σ):
σ = 200 ≈ 14.14 \sigma = \sqrt{200} \approx 14.14 σ=200≈14.14
这表明,尽管学生的平均成绩为80分,但他们的成绩围绕平均值上下波动大约14分,这提供了成绩分布离散程度的一个度量。
3.12 ndarray数组间运算
在NumPy中,数组间的运算和广播机制是处理多维数据时的核心概念,它们允许进行高效的矢量化计算,避免了显式的循环。这些特性使得NumPy在科学计算中非常强大。
1.数组间运算
-
NumPy支持数组间的元素级运算,包括加、减、乘、除等基本运算,这些运算是逐元素进行的。
import numpy as np a = np.array([1, 2, 3]) b = np.array([4, 5, 6]) # 元素级加法 c = a + b # 元素级乘法 d = a * b print(f"a + b = {c}") print(f"a * b = {d}")
- 这里,
a + b
和a * b
都是逐元素进行的操作,结果分别是两个数组对应元素的和与乘积。
- 这里,
2.广播机制
-
广播机制允许NumPy在执行数组运算时自动扩展数组的形状,使得具有不同形状的数组能够进行运算。为了满足广播规则,NumPy执行以下步骤:
- 如果两个数组维度数不同,将维度数较小的数组形状前面填充1,直到两个数组的维度数相同。
- 检查两个数组在每个维度上的大小,它们要么相同,要么其中一个为1。如果条件不成立,则无法广播。
- 对于维度大小为1的任意维度,该维度在运算中的大小会扩展到与另一个数组在该维度的大小相同。
import numpy as np a = np.array([1, 2, 3]) b = np.array([[1], [2], [3]]) # 通过广播,a的形状被扩展为(3, 3),b的形状也被扩展为(3, 3),然后进行逐元素相加 c = a + b print(f"a + b = \n{c}")
-
在这个例子中,
a
的形状为(3,)
,而b
的形状为(3, 1)
。根据广播规则,a
的形状被扩展为(3, 3)
,b
的形状也被扩展为(3, 3)
,然后两个数组可以进行逐元素相加。
3.12.1 广播机制的补充知识
以刚才的例子为基础,来详细讲解如何通过广播机制进行运算。
给定两个数组:
a = np.array([1, 2, 3])
b = np.array([[1], [2], [3]])
-
这里,
a
的形状为(3,)
,意味着它是一个一维数组,包含3个元素。b
的形状为(3, 1)
,意味着它是一个二维数组,有3行1列。 -
当执行
a + b
时,NumPy会自动应用广播机制,步骤如下:- 形状对齐:首先,比较两个数组的维度,将较小维度的数组形状在前面填充1,使得两个数组的维度数相同。在本例中,数组
a
的形状会从(3,)
扩展为(1, 3)
,以匹配b
的二维形状。此时,a
和b
的形状分别变为:
a
:(1, 3)
b
:(3, 1)
- 广播:接下来,NumPy检查每个维度,确保它们是兼容的,即每个维度的大小要么相同,要么其中一个为1。在本例中:
- 第一个维度中,
a
为1,b
为3。由于a
在该维度上的大小为1,它可以被扩展以匹配b
的大小。 - 第二个维度中,
a
为3,b
为1。同样,b
在该维度上的大小为1,它可以被扩展以匹配a
的大小。
通过广播,
a
被扩展为一个(3, 3)
的二维数组,b
也被扩展为一个(3, 3)
的二维数组,具体如下:a扩展后: [[1, 2, 3], [1, 2, 3], [1, 2, 3]] b扩展后: [[1, 1, 1], [2, 2, 2], [3, 3, 3]]
- 逐元素相加:现在,
a
和b
都被扩展为同样的形状,它们可以进行逐元素的相加操作:
[[1+1, 2+1, 3+1], [1+2, 2+2, 3+2], [1+3, 2+3, 3+3]] 结果为: [[2, 3, 4], [3, 4, 5], [4, 5, 6]]
- 形状对齐:首先,比较两个数组的维度,将较小维度的数组形状在前面填充1,使得两个数组的维度数相同。在本例中,数组
3.13 ndarray的矩阵运算
1.矩阵加法和减法
-
矩阵的加法和减法是逐元素进行的。两个形状相同的矩阵可以直接相加或相减。
import numpy as np # 创建两个2x2矩阵 A = np.array([[1, 2], [3, 4]]) B = np.array([[5, 6], [7, 8]]) # 矩阵加法 C = A + B # 矩阵减法 D = A - B print(f"A + B =\n{C}") print(f"A - B =\n{D}")
2.点乘(元素乘)
-
点乘指的是两个矩阵相同位置的元素相乘,结果是一个同样形状的新矩阵。
# 元素乘 E = A * B print(f"A * B (element-wise) =\n{E}")
3.矩阵乘法
-
矩阵乘法(又称为点积、内积)不同于元素乘,它按照线性代数中的规则进行计算。
# 矩阵乘法 F = np.dot(A, B) # 或者使用 A @ B print(f"A dot B =\n{F}")
4.矩阵转置
- 和ndarray相同,使用.T方法即可。
矩阵的逆
-
矩阵的逆是指一个矩阵乘以其逆矩阵的结果为单位矩阵。
# 矩阵逆 H = np.linalg.inv(A) print(f"Inverse of A =\n{H}")
3.13.1 矩阵乘法的补充知识
- 这种乘法不同于元素级乘法,它遵循线性代数中的矩阵乘法规则,即第一个矩阵的列数必须与第二个矩阵的行数相等。
1.矩阵乘法的计算
-
给定两个矩阵 (A) 和 (B),其中 (A) 是一个 (m * n) 矩阵,(B) 是一个 (n * p) 矩阵,它们的乘积 (C = AB) 是一个 (m * p) 矩阵,其中 (C) 的每个元素是通过下面的方式计算得到的:
-
$ C_{ij} = \sum_{k=1}^{n} A_{ik}B_{kj} $
-
这意味着结果矩阵的第 (i) 行第 (j) 列的元素是由第一个矩阵的第 (i) 行与第二个矩阵的第 (j) 列进行点乘得到的。
2.示例
假设有两个矩阵 (A) 和 (B):
-
(A) 是一个 (2 * 3) 矩阵:
-
A = \begin{pmatrix} 1 & 2 & 3 \ 4 & 5 & 6 \end{pmatrix}
-
(B) 是一个 (3 * 2) 矩阵:
-
B = \begin{pmatrix} 7 & 8 \ 9 & 10 \ 11 & 12 \end{pmatrix}
-
计算 (A) 和 (B) 的乘积:
import numpy as np A = np.array([ [1, 2, 3], [4, 5, 6] ]) B = np.array([ [7, 8], [9, 10], [11, 12] ]) C = np.dot(A, B) # 或者 C = A @ B print(C)
-
执行这段代码后,将得到矩阵 (C):
-
C = \begin{pmatrix} 58 & 64 \ 139 & 154 \end{pmatrix}
其中,
- (C_11 = (1 * 7) + (2 * 9) + (3 * 11) = 58)
- (C_12 = (1 * 8) + (2 * 10) + (3 * 12) = 64)
- (C_21 = (4 * 7) + (5 * 9) + (6 * 11) = 139)
- (C_22 = (4 * 8) + (5 * 10) + (6 * 12) = 154)
“”"
Example 矩阵乘法的使用
给出n个学生的平时成绩和期末成绩,根据占比,来求出该学生的最终成绩
例:平时分94,期末分89,平时占比30%,期末占比70%,94 * 0.3 + 89 * 0.7
import numpy as np
data1 = np.array([ # shape 42
[70, 83],
[68, 71],
[83, 65],
[32, 96]
])
data2 = np.array([ # shape 21
[0.3],
[0.7]
])
res = np.dot(data1, data2)
res # shape 4*1
“”"## 3.14 ndarray合并与分割
1.ndarray合并
NumPy中常用的数组合并函数包括:
np.concatenate
:沿指定轴连接数组序列。np.vstack
(垂直栈):沿着垂直轴堆叠数组。np.hstack
(水平栈):沿着水平轴堆叠数组。
import numpy as np
a = np.array([1, 2, 3])
b = np.array([4, 5, 6])
# 水平合并
c = np.hstack((a, b))
# array([1, 2, 3, 4, 5, 6])
# 垂直合并
d = np.vstack((a, b))
# array([[1, 2, 3],
# [4, 5, 6]])
2.ndarray分割
相对应的,NumPy也提供了函数来分割数组:
np.split
:将数组分成多个子数组。np.hsplit
:沿水平轴分割数组。np.vsplit
:沿垂直轴分割数组。
# 创建一个数组
arr = np.arange(9).reshape(3,3)
# 水平分割
result = np.hsplit(arr, 3)
# 垂直分割
result2 = np.vsplit(arr, 3)
注意事项
- 合并时,除了要合并的轴外,其他轴的大小必须相同。
- 分割时,指定的分割数量或分割位置必须能够被数组在指定轴上的大小整除。
3.15 Numpy的IO交互,读取文件
1. 使用numpy.loadtxt()
读取文本文件:
import numpy as np
data = np.loadtxt('data.txt', delimiter=',')
这里,'data.txt'
是要读取的文件名,delimiter=','
指定了数据之间的分隔符为逗号。loadtxt()
函数会将文件中的数据读取到一个NumPy数组中。
2. 使用numpy.genfromtxt()
读取文本文件:
import numpy as np
data = np.genfromtxt('data.csv', delimiter=',')
genfromtxt()
函数类似于loadtxt()
,但它更加灵活,可以处理缺失值和不同的数据类型。它也支持使用delimiter
参数指定分隔符。
3. 使用numpy.fromfile()
读取二进制文件:
import numpy as np
data = np.fromfile('data.bin', dtype=np.float64)
fromfile()
函数用于读取二进制文件。你需要指定数据的类型,例如dtype=np.float64
表示读取双精度浮点数。
4. 使用numpy.load()
读取NumPy的.npy
或.npz
文件:
import numpy as np
data = np.load('data.npy')
3.16 读取后,处理Nan值
1.删除含有缺失值的样本
- 如果有大量数据,可以这样操作。
2.替换、插补
- 按列求平均,用平均值进行填补。
- 例:行是一只股票在一段时间内的涨跌数据,那么列就是所有股票在同一天的涨跌数据,那么,想要弥补空缺值Nan,只要填补该天所有不为Nan的股票数据的平均值即可,不会影响总体的计算。
- numpy没有直接能够替换插补的方法,所以一般使用pandas来进行这一步。
4.Pandas数据处理库
4.1 什么是Pandas,为什么使用
-
介绍
- 2008年由WesMcKinney开发的库
- 专用于数据挖掘的开源py库
- 集成numpy
- 集成matplotlib
- 独特的数据结构,可以清晰的表示数据是什么
-
为什么使用pandas
- 便捷的数据处理能力,如替换Nan值
- 读取文件方便
- 集成了Numpy和Matplotlib的计算和画图
4.2 pandas的独特数据结构
Pandas是一个开源数据分析和处理的Python库,它提供了高性能、易用的数据结构和数据分析工具。DataFrame是Pandas中最常用的数据结构之一,用于处理结构化数据,类似于Excel中的表格或SQL数据库中的表。
4.2.1 DataFrame
- 定义:DataFrame是一个二维的、大小可变的、异质性数据表格,有行标签和列标签。
- 特点:可以存储多种类型的数据,如整数、浮点数、字符串、Python对象等。
- 用途:适用于各种数据操作,包括数据清洗、转换、分析等。
- 其本质是在ndarray外套了一层行列索引
1.创建DataFrame
可以通过多种方式创建DataFrame,包括字典、列表、外部数据文件等。
import pandas as pd
# 通过字典创建DataFrame
data = {
'Name': ['John', 'Anna', 'Peter', 'Linda'],
'Age': [28, 34, 29, 32],
'City': ['New York', 'Paris', 'Berlin', 'London'],
"date": pd.date_range(start='2024-3-1', periods=3, freq='D')
}
df = pd.DataFrame(data)
print(df)
2.DataFrame的属性
DataFrame有很多属性,可以用来访问关于DataFrame的信息。
.shape
:返回DataFrame的行数和列数。.dtypes
:返回每列的数据类型。.columns
:返回列名。.index
:返回索引。.values
:返回DataFrame的数据部分,不包括行列标签,作为NumPy数组。
3.DataFrame的常用方法
.head()
和.tail()
:分别查看DataFrame的前几行和后几行数据。.describe()
:对DataFrame中的数值列进行描述性统计。.sort_values(by='column_name')
:按某列的值排序数据。.groupby('column_name')
:按某列的值分组数据。
print(df.head(2)) # 查看前2行
print(df.describe()) # 数值列的统计信息
4.对行列的常用操作
- 选择:使用
.loc[]
、.iloc[]
或列名选择数据。 - 添加:可以直接赋值来添加新的列。
- 删除:使用
.drop()
方法删除行或列。 - 修改:直接通过索引或
.loc[]
、.iloc[]
赋值修改。 - 设置索引:使用
.set_index('column_name')
设置某列为索引。
# 选择
print(df['Age']) # 选择一列
print(df.loc[0]) # 选择一行
# 添加
df['Country'] = ['USA', 'France', 'Germany', 'UK']
# 删除
df.drop('Country', axis=1, inplace=True) # 删除列
# 修改
df.loc[0, 'Age'] = 30 # 修改某个值
# 设置索引
df.set_index('Name', inplace=True)
# 也可以使用set_index来实现MultiIndex
df.set_index(['Country', 'Name'], inplace=True)
“”"
import numpy as np
import pandas as pd
import random
Example 1
创建一个由numpy转换的股票案例
data1 = np.random.normal(0, 1, (10, 5))
pd.DataFrame(data1, index=[f"S{i}" for i in range(1, 11)], columns=pd.date_range(start=‘2024-3-1’, periods=5, freq=‘D’))
Example 2
设置新索引
data1 = pd.DataFrame(
{
“Stock Name”: [“A”, “B”, “C”],
“Start Year”: [“2019”, “2021”, “2020”],
“Year1”: [random.uniform(-30, 30) for i in range(3)],
“Year2”: [random.uniform(-30, 30) for i in range(3)],
“Year3”: [random.uniform(-30, 30) for i in range(3)],
}
)
将单个/多个已存在的列设为索引
data1.set_index(“Stock Name”)
data1.set_index([“Stock Name”,“Start Year”], inplace=True) # inplace代表是否保留不为索引的内容,True为不保留
data1
“”"### 4.2.2 MultiIndex
1.MultiIndex
MultiIndex
是Pandas中的一种数据结构,用于表示多级(或层次化)索引。这种索引结构允许你在一个轴上(无论是行还是列)有多个(两个以上)索引级别,从而使你能够以更高维度组织和操作数据。使用MultiIndex
可以让你在DataFrame中处理更复杂的数据形式,比如分组、分类和其他形式的层次化数据。
“”"
import pandas as pd
import numpy as np
Example 1
创建一个多级索引(MultiIndex)
index = pd.MultiIndex.from_tuples([(‘A’, ‘2024’), (‘A’, ‘2025’), (‘B’, ‘2024’), (‘B’, ‘2025’)], names=[‘Stock’, ‘Year’])
columns = [‘Jan’, ‘Feb’, ‘Mar’]
使用MultiIndex创建DataFrame
data = np.random.rand(4,3) # 随机数据
pd.DataFrame(data, index=index, columns=columns)
Example 2
由于Panel已被弃用,下面展示如何使用具有MultiIndex的DataFrame来处理相同的三维数据:
假设我们有三维数据:年份、股票代码和月份
years = [‘2024’, ‘2025’]
stocks = [‘A’, ‘B’]
months = [‘Jan’, ‘Feb’, ‘Mar’]
创建一个三维的MultiIndex
multi_index = pd.MultiIndex.from_product([years, stocks, months], names=[‘Year’, ‘Stock’, ‘Month’])
使用MultiIndex创建DataFrame
res = pd.DataFrame(np.random.rand(len(multi_index)), index=multi_index, columns=[‘Value’])
res
抓取数据
1.访问抓取.loc方法
res.loc[“2024”, “A”, “Jan”]
2.跨级别抓取.xs方法
res.xs(“A”, level=“Stock”)
“”"### 4.2.3 Series
Series
是Pandas库中的一种基本数据结构,它用于存储一维的标签化数组。Series
对象可以看作是一个带有索引的一维数组。
与NumPy的数组不同,Series
可以有一个自定义的索引标签,意味着你可以使用索引标签来访问数据,而不仅仅是数字位置。
独特属性
.index
:Series
的索引标签。.values
:Series
数据的数组表示。.dtype
:数据的类型。.name
:Series
的名称,可以在创建时指定,也可以之后设置。
独特方法
.describe()
:提供Series
数据的描述性统计。.apply()
:对Series
中的每个元素应用指定的函数。.value_counts()
:计算Series
中各值出现的频次。.sort_values()
和.sort_index()
:分别按值和按索引对Series
进行排序。
“”"
import pandas as pd
data = pd.Series([1, 3, 5, 7, 9], index=[‘a’, ‘b’, ‘c’, ‘d’, ‘e’])
通过索引标签访问
print(data[‘b’])
通过位置访问
print(data[1])
描述性统计
print(data.describe())
应用函数
print(data.apply(lambda x: x**2))
值的频次
print(data.value_counts())
排序
print(data.sort_values(ascending=False))
“”"## 4.3 DataFrame的基本数据操作,及四种行列索引。
“”"
import numpy as np
import pandas as pd
import random as rd
读取csv文件
data = pd.read_csv(“File_Position”)
data = {
‘open’: [round(np.random.uniform(-50, 50), 2) for i in range(5)],
‘close’: [round(np.random.uniform(-50, 50), 2) for i in range(5)],
‘volume’: [round(np.random.uniform(20_000, 50000), 2) for i in range(5)],
‘ma5’: [round(np.random.uniform(-20, 20), 2) for i in range(5)],
‘ma10’: [round(np.random.uniform(-20, 20), 2) for i in range(5)],
}
row_index = pd.date_range(start=‘2024-3-1’, periods=5, freq=‘D’)
df = pd.DataFrame(data, index=row_index)
df
去除不想显示的列
df = df.drop([“ma5”], axis=1) # axis=0为行,1为列
1.直接索引, 通过列
print(df[“open”])
print(df[“open”][“2024-03-01”])
2.按名字索引,通过行
print(df.loc[“2024-03-01”])
print(df.loc[“2024-03-01”][“open”])
3.按数字索引, [行,列]
print(df.iloc[1])
print(df.iloc[1, 0])
4.混合索引
print(df.loc[df.index[:3], [“open”, “close”]])
print(df.iloc[:3, :2])
print(df.iloc[:3, [0,1]]) # 可以传入一个list的下标
1.修改行列信息,用四种索引方式都可以。
df[“open”] = 200 # 全覆盖为200
df.iloc[1] = [i for i in range(5)]
2.排序,根据列
df.sort_values([“open”, “close”], ascending=False) # 按照open列的值从小到大排序,如果open值相同,按close值再排序。
3.按日期排序, Series也是同样的函数来排序index。
df.sort_index()
“”"## 4.4 DataFrame的算数运算
“”"
使用4.3的数据
算数运算可以通过广播机制直接作用在所有值上,也可以通过行列索引作用于任何行列上,索引方式参考4种。
1.加10
df_add = df.add(10)
2.减10
print(df, “\n”)
df_sub = df[“open”].sub(10)
print(df_sub)
3.乘以2
df_mul = df.mul(2)
4.除以2
df_div = df.div(2)
5.模3
df_mod = df.mod(3)
6.乘方2
df_pow = df.pow(2)
“”"## 4.5 DataFrame的逻辑运算
- 列与列,行与行,列/行与数值,之间的比较,返回的是bool的Series
“”"
使用4.3的数据
1.检查 ‘open’ 列的值是否 大于 ‘close’ 列的值
greater_than = df[‘open’] > df[‘close’]
2.检查 ‘volume’ 列的值是否 小于 50000
volume_high = df[‘volume’] < 50000
3.同时满足 (‘open’ 大于 ‘close’) 且 (‘volume’ 小于 50000)
both_conditions = greater_than & volume_high
4.满足 (‘open’ 大于 ‘close’) 或 (‘volume’ 小于 50000)
either_condition = greater_than | volume_high
将得到的bool-series应用在原数据上, 进行类似数据库查找的操作
5.找到所有open大于0的行数据
find_greater_than_zero = df[df[“open”]>0]
6.找到所有open大于0,且close大于2的行数据
find_greater_zero_and_two = df[(df[“open”]>0) & (df[“close”]>2)]
逻辑函数方法的使用
7.更直接的查询
df.query(“open > 0 & close > 0”)
8.判断是否存在某数值
df[“open”].isin([19.2, 11.5])
“”“## 4.6 DataFrame的统计运算”“”
使用4.3的数据
计算最小值
min_values = df.min()
计算最大值
max_values = df.max()
计算平均值
mean_values = df.mean()
计算中位数
median_values = df.median()
计算标准差
std_dev = df.std()
计算求和
sum_values = df.sum()
计算方差
variance = df.var()
查找最小值的索引,返回的是所有列的最小值索引
idx_min = df.idxmin()
查找最大值的索引
idx_max = df.idxmax()
累计求和, 累计意味着从1-n天的所有和,例如用于查看一只股票开盘以来的总涨跌情况,返回一个f=[n]+[n-1]的series
cum_sum = df.cumsum()
累计最大值
cum_max = df.cummax()
累计最小值
cum_min = df.cummin()
累计乘积
cum_prod = df.cumprod()
自定义运算,使用apply函数即可, 传入自定函数,以及axis=0按列计算
例,计算每列的最大值和最小值的差
应用lambda
result = df.apply(lambda x: x.max()-x.min(), axis=0)
应用正常的函数,自动传参
def range_diff(x):
return x.max() - x.min()
result = df.apply(range_diff, axis=0)
result
“”“## 4.7 DataFrame的画图”“”
使用4.3的数据
import matplotlib.pyplot as plt
categories = df.index.date
values1 = df[“open”]
values2 = df[“close”]
frist_label = “open”
second_label = “close”
title = “stock open and close report”
x_label = “Stocks”
y_label = “Value”
fig, ax = plt.subplots(layout=‘constrained’)
width = 0.6
offset = [i for i in range(0,10,2)]
绘制柱状图时,使用偏移的位置
ax.bar(offset, values1, align=‘center’, color=“skyblue”, edgecolor=‘black’, width=width, label=frist_label)
ax.bar([i+width for i in offset], values2, align=‘center’, color=“orange”, edgecolor=‘black’, width=width, label=second_label)
设置X轴刻度标签
ax.set_xticks([i + width/2 for i in offset]) # 使用两个柱的中点位置来对齐文本
ax.set_xticklabels(categories) # 设置类别名称为X轴标签
调整文本标签的位置
for i in range(len(values1)):
ax.text(i2, values1[i]+1 if values1[i] > 0 else values1[i]-3, str(values1[i]), ha=‘center’) # 为第一组数据设置文本标签
ax.text(i2+width, values2[i]+1 if values2[i] > 0 else values2[i]-3, str(values2[i]), ha=‘center’) # 为第二组数据设置文本标签
ax.set_title(title)
ax.set_xlabel(x_label)
ax.set_ylabel(y_label)
添加虚线
ax.grid(True, axis=‘y’, linestyle=‘–’, alpha=0.7)
添加图例
ax.legend()
plt.show()
“”“## 4.8 pandas-CSV”“”
import pandas as pd
1.读取
df = pd.read_csv(‘file.csv’)
参数:
指定列名
df = pd.read_csv(‘file.csv’, names=[‘col1’, ‘col2’, ‘col3’])
指定索引列
df = pd.read_csv(‘file.csv’, index_col=‘index_col_name’)
跳过指定行数的头部
df = pd.read_csv(‘file.csv’, skiprows=2)
指定缺失值标识符
df = pd.read_csv(‘file.csv’, na_values=[‘NA’, ‘N/A’])
2.写入
df.to_csv(‘output.csv’, index=False, mode=“w”)
参数:
指定列名
df.to_csv(‘output.csv’, columns=[‘col1’, ‘col2’])
写入不包括行索引
df.to_csv(‘output.csv’, index=False)
写入不包括列名
df.to_csv(‘output.csv’, header=False)
以制表符分隔
df.to_csv(‘output.csv’, sep=‘\t’)
“”"## 4.9 pandas-hdf5
- hdf5的储存格式类似于key: dataframe
- 因为dataframe是二维的,那么再加一维的hdf5可以看作是三维数组。
“”"
1.写入
‘table’ 格式支持后续查询操作
df.to_hdf(‘data.h5’, key=‘df’, format=‘table’, mode=‘w’)
2.读取
df_read = pd.read_hdf(‘data.h5’, key=‘df’)
查询操作,只有当format为’table’时才能使用
df_query = pd.read_hdf(‘data.h5’, key=‘df’, where=[‘index>2’])
“”“## 4.10 pandas-Json”“”
1.写入
df.to_json(‘data.json’)
参数:
orient - 控制JSON格式,比如’split’,‘records’,‘index’,‘columns’,'values’等
force_ascii - 为了兼容性,默认为True,将所有非ASCII字符转义
date_format - 控制日期的格式化方式,默认为’epoch’
double_precision - 控制小数点后的精度,默认为10
ensure_ascii - 默认为True,所有非ASCII字符在输出时都会被转义
2.读取
df_read = pd.read_json(‘data.json’)
参数:
orient - 指定JSON字符串的格式
typ - 返回对象类型,默认为’frame’,表示返回DataFrame;'series’表示返回Series
convert_dates - 指定将JSON中的字段解析为日期,默认为True
convert_axes - 是否尝试将轴标签转换为适当的数据类型,默认为True
precise_float - 是否使用更精确的浮点转换,默认为False
“”"## 4.11 pandas处理缺失值Nan
- 直接删除含有缺失值的样本 - 行
- 根据其余样本数据填补平均值 - 列的平均值
“”"
import pandas as pd
import numpy as np
1.创建一个包含缺失值的DataFrame
df = pd.DataFrame({
‘A’: [1, 2, np.nan, 4],
‘B’: [5, np.nan, np.nan, 8],
‘C’: [10, 11, 12, 13]
})
2.判断是否存在缺失值 isnull、notnull
missing_values = df.isnull().any()
两种方法
A.直接删除包含缺失值的样本(行)
df_dropped = df.dropna()
参数:
axis - 0 或 ‘index’ 删除包含缺失值的行, 1 或 ‘columns’ 删除包含缺失值的列
how - ‘any’ 删除任何有缺失值的行/列, ‘all’ 只删除全为缺失值的行/列
thresh - 设置行/列中非缺失值的最小数量,低于这个数量的行/列将被删除
inplace - 如果为True,则直接在原数据上修改,如果为False则返回一个新的DataFrame
B.填补缺失值:用各列的均值填补对应列的缺失值
df_filled = df.fillna(df.mean())
参数:
value - 可以是一个字典,指定每列填充的值
method - 'ffill’向前填充,'bfill’向后填充
axis - 0 或 ‘index’ 沿着行的方向填充, 1 或 ‘columns’ 沿着列的方向填充
inplace - 如果为True,则直接在原数据上修改,如果为False则返回一个新的DataFrame
3.处理其他类型的缺失值,如"?“,”"等,替换为Nan,之后就和处理Nan一样了
df_filled.replace(to_replace=“?”, value=np.nan)
“”"## 4.12 pandas处理数据离散化/one-hot编码
-
离散化
- 在机器学习中,将连续变量转换成有限数量的类别,简化模型的复杂性,提高对数据的泛化能力,尤其在处理非线性关系时更有效。
-
One-hot 编码
- 用于将分类变量转换为二进制(0或1)格式,每个类别对应一个独立的特征,从而使得模型能够更好地处理无序(名义)类别数据,避免引入数值大小的误导。
pd.cut函数
bins
参数定义了将数据分割成不同区间的边界。- 这里我们使用
[0, 160, 180, float('inf')]
来定义三个区间:0到160cm,160到180cm,以及180cm以上。 - 参数
right=False
指定区间的右边界是开区间。 - labels参数用于为每个区间赋予一个标签。
- 也可以使用qcut函数,pandas会自动分出区间,df.qcut(data, 区间数量)
pd.get_dummies函数
- 用于创建独热编码的列,它会为
height_category
中的每个唯一标签添加一个新的列,如果该行的标签匹配,则在相应的列中使用1来表示,否则使用0。
“”"
import pandas as pd
df = pd.DataFrame(
{‘height’: [158, 165, 170, 174, 180, 185]}
)
定义区间边界和标签
bins = [0, 160, 180, float(‘inf’)] # float(‘inf’)代表无限
labels = [‘矮’, ‘中’, ‘高’]
使用 pd.cut 进行离散化
df[‘height_category’] = pd.cut(df[‘height’], bins=bins, labels=labels, right=False)
df[‘height_category’]
使用 pd.get_dummies 进行 One-Hot 编码, 这里返回的是一个新的dataframe
df_one_hot = pd.get_dummies(df, columns=[‘height_category’])
df_one_hot
value_count显示每组的数量
df[‘height_category’].value_counts()
“”"## 4.13 pandas组合方法 concat / merge
concat
函数
- 用于沿着一条轴将多个 pandas 对象堆叠在一起。这可以用于简单地合并(堆叠)数据集,不涉及根据索引或列对数据进行对齐。
merge
函数
- 用于根据一个或多个键将两个数据集的行连接起来。类似于 SQL 中的 JOIN 操作。
- inner是合并都存在的索引。
- outer是合并所有,不存在的索引内容会以Nan填充。
- left和right就是根据哪个表的索引内容进行拼接。
“”"
import pandas as pd
1.pd.concat
df1 = pd.DataFrame({
‘Name’: [‘Alice’, ‘Bob’],
‘Age’: [25, 22]
})
df2 = pd.DataFrame({
‘Name’: [‘Cindy’, ‘Dan’],
‘Age’: [20, 23]
})
result = pd.concat([df1, df2], ignore_index=True, axis=0) # 0是垂直,1是水平
print(result)
2.pd.merge
df_a = pd.DataFrame({
‘Name’: [‘Alice’, ‘Bob’],
‘Age’: [25, 22]
})
df_b = pd.DataFrame({
‘Name’: [‘Alice’, ‘Bob’],
‘Score’: [88, 92]
})
result = pd.merge(df_a, df_b, on=[‘Name’]) # left,right,how=“inner”,on=索引
print(result)
“”"## 4.14 pandas的交叉表
- 交叉表(crosstab),可以有效地对比两个类别变量的频率分布。
- 假设想分析股票涨跌与星期几之间的关系
“”"
import pandas as pd
import numpy as np
设置随机种子,以便重现示例
np.random.seed(0)
模拟数据
df = pd.DataFrame({
‘DayOfWeek’: np.random.choice([‘Monday’, ‘Tuesday’, ‘Wednesday’, ‘Thursday’, ‘Friday’], size=100),
‘StockChange’: np.random.choice([‘Up’, ‘Down’], size=100)
})
将 ‘DayOfWeek’ 转换为有序类别类型
weekdays = [‘Monday’, ‘Tuesday’, ‘Wednesday’, ‘Thursday’, ‘Friday’]
df[‘DayOfWeek’] = pd.Categorical(df[‘DayOfWeek’], categories=weekdays, ordered=True)
cross_tab = pd.crosstab(df[‘DayOfWeek’], df[‘StockChange’])
print(cross_tab)
import matplotlib.pyplot as plt
绘制交叉表的条形图
cross_tab.plot(kind=‘bar’, stacked=True)
plt.title(‘Stock Change Frequency by Day of Week’)
plt.xlabel(‘Day of Week’)
plt.ylabel(‘Frequency’)
plt.show()
“”"## 4.15 pandas分组与聚合
- 分组:将相同的类别分为一组 (groupby)
- 聚合:将分组后的数据,进行统计运算 (sum, mean…)
“”"
import pandas as pd
df = pd.DataFrame({
‘Name’: [‘Alice’, ‘Bob’, ‘Charlie’, ‘David’, ‘Eve’],
‘Department’: [‘HR’, ‘IT’, ‘IT’, ‘HR’, ‘Marketing’],
‘Salary’: [50000, 60000, 70000, 52000, 45000]
})
按部门分组并计算每个部门的平均薪资
department_group = df.groupby(by=“Department”)[“Salary”].mean()
department_group = df[“Salary”].groupby(by=df[“Department”]).mean()
print(department_group)
“”"## 电影数据分析案例
分析电影数据
数据源:https://www.kaggle.com/datasets/PromptCloudHQ/imdb-data?resource=download
-
1.电影分数的平均分?
-
2.总共有多少位导演?
-
3.对于这些电影,如何查看Rating的分布情况,如何以合适的方式呈现数据?
-
4.对于这些电影,如何统计电影的分类情况?
“”"
import pandas as pd
import numpy as np
import matplotlib as mpl
import matplotlib.pyplot as plt
导入数据
点击左侧的文件图标,再点击窗口中的循环drive标志,导入drive文件,然后复制路径
df = pd.read_csv(‘/content/drive/MyDrive/colab data/IMDB-Movie-Data.csv’)
df.head(2)
---------------------------------------------
1.评分的平均分
print(df[“Rating”].mean())
---------------------------------------------
2.导演人数
print(np.unique(df[“Director”]).size)
---------------------------------------------
3.Rating的分布情况-直方图
fig, ax = plt.subplots(layout=‘constrained’, figsize=(20,8))
data = df[“Rating”]
ax.hist(data, bins=20, alpha=0.7, color=‘blue’, edgecolor=‘black’)
plt.xticks(np.linspace(data.min(), data.max(), 21))
ax.set_title(‘Rating distribution’)
ax.set_xlabel(‘Value Rating’)
ax.set_ylabel(‘Star’)
ax.grid(True, which=‘both’, axis=‘both’, linestyle=‘–’, alpha=0.5)
plt.show()
---------------------------------------------
4.统计电影的分类情况
拿到每个电影的分类,得到去重后的所有电影类别
each_movie = [i.split(“,”) for i in df[“Genre”]]
movie_genre = sorted(list(set([j for i in each_movie for j in i])))
total_movie = len(df[“Title”])
total_genre = len(movie_genre)
创建一个新的表,一行为一部电影,一列为一个类别,以0或1区分是否是这个类别
count_df = pd.DataFrame(np.zeros(shape=[total_movie,total_genre],dtype=“int32”), index=df[“Title”], columns=movie_genre)
根据索引进行+1
for i in range(0,total_movie):
m_name = df.loc[i][“Title”]
m_genre = each_movie[i]
count_df.loc[m_name][m_genre] = 1
sum_df = count_df.sum().sort_values(ascending=False)
柱状图展示
categories = sum_df.index
values = sum_df.values
fig, ax = plt.subplots(layout=‘constrained’, figsize=(20,8))
ax.bar(categories, values, align=‘center’, color=plt.cm.tab20.colors, edgecolor=‘black’)
ax.set_title(‘Values per Genre’)
ax.set_xlabel(‘Genre’)
ax.set_ylabel(‘Values’)
for i, value in enumerate(values):
ax.text(i, value+4, str(value), ha=‘center’)
ax.grid(True, axis=‘both’, linestyle=‘–’, alpha=0.5)
plt.show()
如果有所帮助请给个免费的赞吧~有人看才是支撑我写下去的动力!
声明:
本文仅用作学习记录和交流