Numpy、Panads

80 阅读1分钟

Numpy

用来存储和处理大型矩阵

NumPy重要功能如下:

  1. 高性能科学计算和数据分析的基础包
  2. ndarray,多维数组,具有矢量运算能力,快速、节省空间
  3. 矩阵运算,无需循环,可完成类似Matlab中的矢量运算
  4. 用于读写磁盘数据的工具以及用于操作内存映射文件的工具

Numpy 属性

import numpy as np
# 生成15个数据
arr = np.arange(15)
print(arr) # [ 0  1  2  3  4  5  6  7  8  9 10 11 12 13 14]

转换成 3 行 5 列

# 转换
reshape = arr.reshape(3, 5)
print(reshape)
# [[ 0  1  2  3  4]
# [ 5  6  7  8  9]
# [10 11 12 13 14]]


print(f'数组的维度(轴):{reshape.ndim}') # 几维数组。轴就是几
print(f'数组的形状:{reshape.shape}') # 几行几列 (行数,列数)
print(f'数组的元素类型:{reshape.dtype}')# 整型
print(f'数组中每个元素所占字节数:{reshape.itemsize}') #int32 4字节 int64 8字节
print(f'数组中元素的个数:{reshape.size}') # 长度
print(f'数组的类型:{type(reshape)}') # <class 'numpy.ndarray'>

# 数组的维度(轴):2
# 数组的形状:(3, 5)
# 数组的元素类型:int64
# 数组中每个元素所占字节数:8
# 数组中元素的个数:15
# 数组的类型:<class 'numpy.ndarray'>

创建 ndarray

NumPy数组是一个多维的数组对象(矩阵),称为ndarray,具有矢量算术运算能力和复杂的广播能力,并具有执行速度快和节省空间的特点。

注意:ndarray的下标从0开始,且数组里的所有元素必须是相同类型

array 函数
import numpy as np
# 将普通数组转换成 numpy
arr = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12])

指定字节类型,注意如果是小数,用的是整型,会直接砍掉,并不是四舍五入

array = np.array([1, 2, 3, 4, 5], dtype=np.int32)
print(f'数组的元素类型:{array.dtype}')  # 整型
print(f'数组中每个元素所占字节数:{array.itemsize}')  #int32 4字节 int64 8字节
print(f'数组的类型:{type(array)}')  # <class 'numpy.ndarray'>
arange 函数

包左不包右

import numpy as np
# 创建一个数组,从2到10,步长为2
array = np.arange(2, 10, 2)
print(array) # [2 4 6 8]
random 随机数

random.rand

import numpy as np
# 随机数, 0-1, 3 行 4 列
array = np.random.rand(3, 4)
print(array)

# [[0.31049238 0.75832324 0.37506145 0.32252616]
#  [0.38807463 0.93432297 0.17881305 0.88305402]
#  [0.41024363 0.28271881 0.86731565 0.53035414]]

random.randint 整数

import numpy as np
# 随机数, -1-4, 3 行 4 列
array = np.random.randint(-1, 5, size=(3, 4))
print(array)

# [[ 3  2  1  1]
#  [ 3  4  3 -1]
#  [ 1  0  3  0]]

random.uniform 包含小数

import numpy as np
# 随机数, -1-4, 3 行 4 列,包含小数
array = np.random.uniform(-1, 5, size=(3, 4))
print(array)

# [[ 4.67745816  4.20730726  2.1148062   1.7430438 ]
#  [ 4.13875101  3.95117814 -0.91604952  0.31978374]
#  [ 2.18948176  2.99218651  4.02325524  2.29999013]]

randn

生成正态分布,的浮点数,3行5列。

import numpy as np
f = np.random.randn(3, 5)
print(f)
创建等比数列

logspace(起始次幂,结束次幂,数字个数, base=基数) -> 生成等比数列,默认基数是10,即:10的起始次幂 ~ 10的结束次幂,包左包右

需求:创建长度为 5 的等比数列,起始次幂为1,结束次幂为3

过程:会自动计算,每生成一个数字,加多少幂合适。中间会变,开始和结尾不会变。

import numpy as np
n = np.logspace(1, 3, 5, base=10)
print(n)
# [  10.           31.6227766   100.          316.22776602 1000.        ]
创建等差数列

np.linspace(起始值,结束值,元素个数, endpoint=True)

生成指定范围内的等差数列,默认包左包右。

  • endpoint:设置为false,可以不包右
import numpy as np
# 创建一个等差数列,从1开始,到10结束,共10个数,包右
n = np.linspace(1, 10, 10, endpoint=True)
print(n)
# [ 1.  2.  3.  4.  5.  6.  7.  8.  9. 10.]

数据类型转换

1. 把元素类型为 np.float64 -> np.int32
  1. zeros 创建用 0 填充的数组
  2. astype 用于将调用者转换成指定类型,返回
import numpy as np
# 生成 3行4列用0填充的数组,类型是float
zeros = np.zeros((3, 4), dtype=np.float64)
print(zeros)
# [[0. 0. 0. 0.]
#  [0. 0. 0. 0.]
#  [0. 0. 0. 0.]]
# 
# 将zeros数组转换成整型
astype = zeros.astype(np.int32)
print(astype)
# [[0 0 0 0]
#  [0 0 0 0]
#  [0 0 0 0]]

Numpy 内置函数

f = [[-0.30398695  0.39242509  0.83707249 -0.5360649 ]
 [-0.10631079 -0.69037792 -0.47947986 -1.06188956]
 [-0.45553133 -0.49964343  1.3645323   0.26271202]]

根据上面的 f 进行函数运算。

import numpy as np
# 天花板数,向上取整
print(np.ceil(f))
# [[-0.  1.  1. -0.]
#  [-0. -0. -0. -1.]
#  [-0. -0.  2.  1.]]

# 地板数,向下取整
print(np.floor(f))
# [[-1.  0.  0. -1.]
#  [-1. -1. -1. -2.]
#  [-1. -1.  1.  0.]]

# 四舍五入
print(np.rint(f))
# [[-0.  0.  1. -1.]
#  [-0. -1. -0. -1.]
#  [-0. -0.  1.  0.]]

# 判断是否为空
print(np.isnan(f))
# [[False False False False]
#  [False False False False]
#  [False False False False]]

# 矩阵乘法
# 矩阵乘法的意思是,np.multiply() 会对数组 x 和 y 的每个对应位置的元素执行乘法运算。
print(np.multiply(f, f))
# [[0.09240807 0.15399745 0.70069035 0.28736557]
#  [0.01130198 0.47662167 0.22990094 1.12760944]
#  [0.20750879 0.24964356 1.8619484  0.0690176 ]]

# 矩阵除法
# 意思是,会对数组 x 和 y 的每个对应位置的元素执行除法运算。
print(np.divide(f, f))
# [[1. 1. 1. 1.]
#  [1. 1. 1. 1.]
#  [1. 1. 1. 1.]]

# 条件运算
print(np.where(f > 0, 1, 0))
# [[0 1 1 0]
#  [0 0 0 0]
#  [0 0 1 1]]

统计函数

数据展示

image.png

0 是列,1是行

# 创建3行4列数据
f = np.arange(12).reshape(3,4)

# 求所有的和
print(f.sum()) # 66
# 求每列的和
print(f.sum(axis=0)) # [12 15 18 21]
# 求每行的和
print(f.sum(axis=1)) # [ 6 22 38]

# 求累加和,会把数组转成一维数组,进行累加
print(f.cumsum()) # [ 0  1  3  6 10 15 21 28 36 45 55 66]
# 按列统计,第一列,0,4,8,结果就是,0+0,0+4,0+4+8
print(f.cumsum(axis=0))
# [[ 0  1  2  3]
#  [ 4  6  8 10]
#  [12 15 18 21]]
# 按行统计
print(f.cumsum(axis=1))
# [[ 0  1  3  6]
#  [ 4  9 15 22]
#  [ 8 17 27 38]]

去重和排序

去重

我们创建了一个3行3列的数组,可以看到有很多重复的。通过unique执行了去重,发现变成一维数组了,并且不会影响arr的部分。

import numpy as np
arr = np.array([[1, 2, 1], [2, 3, 4], [3, 4, 5]])
# [[1 2 1]
#  [2 3 4]
#  [3 4 5]]
# 执行去重
print(np.unique(arr)) # [1 2 3 4 5]

排序

不会影响原数组。

import numpy as np
arr = np.array([33, 11, 22, 66, 55])
print(arr) # [33 11 22 66 55]
print(np.sort(arr)) # [11 22 33 55 66]

影响原数组

import numpy as np
arr = np.array([33, 11, 22, 66, 55])
arr.sort()
print(arr) # [11 22 33 55 66]

矩阵运算

多维数组运算

相加,相减,相乘,相除

可以看到每一列相加了,必须是元素个数一一对应,如果A的数组是6个,B的数组必须是6个,如果不一致,会报错。多维也是一样的。

import numpy as np
arr = np.array([33, 11, 22, 66, 55])
print(arr)# [33 11 22 66 55]
a = np.arange(5)
print(a) # [0 1 2 3 4]

print(arr + a) # [33 12 24 69 59]

矩阵乘法,矩阵A的行数 = 矩阵B的列数

将 A 的 1,2,3 这一行,去和 B 的 9,6,5 这一列,去逐个元素相乘,然后再逐个元素相加,等于 C 的第一个数字

image.png

image.png

元素个数不一致也会报错。

import numpy as np
arr = np.array([[1, 2, 3], [4, 5, 6]])
print(arr)
# [[1 2 3]
#  [4 5 6]]
a = np.array([[9, 8], [6, 5], [3, 2]])
print(a)
# [[9 8]
#  [6 5]
#  [3 2]]
print(arr.dot(a))
print(np.dot(arr, a)) # 结果和上面一样
# [[30 24]
#  [84 69]]

Pandas

Pandas 是 Python 的一个第三方包

Pandas在数据处理上具有独特的优势:

  • 底层是基于Numpy构建的,所以运行速度特别的快
  • 有专门的处理缺失数据的API
  • 强大而灵活的分组、聚合、转换功能

image.png

适用场景:

  • 数据量大到Excel严重卡顿,且又都是单机数据的时候,我们使用Pandas
  • Pandas用于处理单机数据(小数据集(相对于大数据来说))
  • 在大数据ETL数据仓库中,对数据进行清洗及处理的环节使用Pandas

不能处理 GB 以上的数据

读取 CSV 文件

配置一些参数

设置显示的最大行数和列数为None

pd.set_option('display.max_rows', None) pd.set_option('display.max_columns', None)

恢复显示的最大行数到默认值

pd.reset_option('display.max_rows') # 恢复显示的最大列数到默认值 pd.reset_option('display.max_columns')

恢复所有选项到默认值 pd.reset_option('all')

开始

首先要确保工作路径,可以通过 os.getcwd() 获取工作目录,使用 os.chdir(r'E:\') 修改路径。因为每次都会默认到用户路径下

如果编码是不正确的,会直接抛出异常,默认会打印所有。

# 导入
import pandas as pd
# 加载路径下的文件,并指定编码
csv = pd.read_csv('./1960-2019全球GDP数据.csv', encoding='gbk')
# print(csv)

head = csv.head() # 查看前 5 行
head = csv.head(10) # 查看前 10 行

曲线生成 / 数据检索

需求:检索出中国,按照年份查看(并且将年份设置为行)

image.png

注意 Pandas 绘制图需要的是 matplotlib,pip install matplotlib

在设置索引的时候,inplace 表示的是否在原数据进行修改,默认false

GDP 是表中的字段,表示绘制那一列。

import pandas as pd
csv = pd.read_csv('./1960-2019全球GDP数据.csv', encoding='gbk')
# 获取中国数据
s = csv[csv.country == '中国']
# 设置行列
s.set_index('year', inplace=True)
# 绘制 GDP 折线图
s.GDP.plot()

image.png

前面是一个图一个折现,如果是多个呢

注意:只能通过 s.GDP.plot() 这种方式去绘制,当多个字段一样时,自动合并

有个坑:inplace=True 表示 原地修改 DataFrame,这样就不能链式调用了。

那如果想修改颜色呢,和加上图例呢。注意,图例的名称默认是行名。比如GDP就是GDP,通过 color 和 legend,通过 label 属性呢,设置图例的名称。

显示出来了,但是我们发现,中文是乱码啊,这是因为 matplotlib 是 UTF-8的。

import pandas as pd
csv = pd.read_csv('./1960-2019全球GDP数据.csv', encoding='gbk')

# 获取中国数据
s = csv[csv.country == '中国'].set_index('year')
# 获取日本数据
j = csv[csv.country == '日本'].set_index('year')
# 获取美国数据
u = csv[csv.country == '美国'].set_index('year')

s.GDP.plot(color='red', legend=True, label='中国')
j.GDP.plot(color='gray', legend=True, label='日本')
u.GDP.plot(color='blue', legend=True, label='美国')

修复乱码

import matplotlib as plt
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False

image.png

Pandas 数据结构

在 pandas 中没有行的概念。

看图中,其中,0,1,2,3,4,5~这一列是索引列

索引列的左侧还隐藏了一列,叫行索引列,看不到,但是有,无法修改。

year,country,GDP,这一行叫列名

每一列都是一个 Series 对象

还隐藏了一个列的编号,下方图中,year的编号是0,country 是1,GDP 是2。

这一整个图,叫做DataFrame对象 image.png

Series 对象的创建

Series也是Pandas中的最基本的数据结构对象,是 DataFrame 的列对象,series 本身也具有索引。

Series 是一种类似于一维数组的对象,由下面两个部分组成:

image.png

  1. 通过列表创建 series,使用 index 设置索引
import pandas as pd
series = pd.Series([1, 2, 3], index=['a', 'b', 'c'])
print(series)
# a    1
# b    2
# c    3
# dtype: int64
  1. 通过元组创建 series
import pandas as pd
s3 = pd.Series(('张三', '男', 23), index=['name', 'sex', 'age'])
print(s3)
# name    张三
# sex      男
# age     23
# dtype: object
  1. 通过字典生成,默认key是索引,value是数据
import pandas as pd
s3 = pd.Series({'name': '张三', 'age': 18, 'sex': '男'})
print(s3)
# name    张三
# age     18
# sex      男
# dtype: object
  1. 将 numpy 的 ndarray 对象转换成 series
import pandas as pd
import numpy as np
arange = np.arange(5)
s3 = pd.Series(arange)
print(s3)

Series 的常用属性

  • 我希望获取索引列
  • 我希望获取数值列
  • 我希望根据索引获取数据
import pandas as pd
s1 = pd.Series(data=[i for i in range(6)], index=[i for i in 'ABCDEF'])
print(s1)
# A    0
# B    1
# C    2
# D    3
# E    4
# F    5
# dtype: int64

# 索引列
print(s1.index)
# 数据列
print(s1.values)
# 根据索引D找值
print(s1['D'])

DataFrame 对象

DataFrame是一个类似于二维数组或表格(如excel)的对象,既有行索引,又有列索引

  • 行索引,表明不同行,横向索引,叫index,0轴,axis=0
  • 列索引,表明不同列,纵向索引,叫columns,1轴,axis=1

image.png

除了之前用 csv文件读取获取 DataFrame 还有很多方式

  1. 创建 DataFrame 对象,字典 + 列表的方式
import pandas as pd
data_dict = {
    '日期': ['2025-11-08', '2025-11-09', '2025-11-10'],
    '温度': [5, 3, 4],
    '湿度': [60, 70, 60]
}
# 把上面的数据字典转换成DataFrame
s1 = pd.DataFrame(data=data_dict, index=['A', 'B', 'C'])
print(s1)
#            日期  温度  湿度
# A  2025-11-08   5  60
# B  2025-11-09   3  70
# C  2025-11-10   4  60
  1. 创建 DataFrame 对象,列表加元组的方式,不一定是元组,列表+列表也是可以的。

通过 columns 设置列名,通过index设置索引

import pandas as pd
data_dc = [
    ('2025-11-08', 5, 60),
    ('2025-11-09', 3, 70),
    ('2025-11-10', 4, 60)
]
s2 = pd.DataFrame(data=data_dc, columns=['日期', '温度', '湿度'], index=['A', 'B', 'C'])
print(s2)

#            日期  温度  湿度
# A  2025-11-08   5  60
# B  2025-11-09   3  70
# C  2025-11-10   4  60
  1. 通过 numpy 创建
import pandas as pd
import numpy as np
s3 = pd.DataFrame(np.arange(9).reshape(3, 3))
print(s3)
#    0  1  2
# 0  0  1  2
# 1  3  4  5
# 2  6  7  8

DataFrame 常用属性

import pandas as pd
import numpy as np
score = np.random.randint(40, 101, size=(10, 5))
score_df = pd.DataFrame(score)
# 赋值
score_df.columns = ['语文', '数学', '英语', '物理', '化学']
score_df.index = ['同学' + str(i) for i in range(10)]

已有数据是

image.png

注意,打印的 dtype 虽然是 object,但是表示的意思是字符串,等于 str

# 获取形状
print(score_df.shape) # (10, 5)
# 获取索引
print(score_df.index) # Index(['同学0',....], dtype='object')
# 获取数据
print(score_df.values)
# [[92 81 63 79 83]
# ...
#  [71 89 90 94 64]]
# 转换成 numpy
print(score_df.to_numpy())
# 行列,数据转换,之前是行的转成列,之前是列的转成行
print(score_df.T)
#     同学0  同学1  同学2  同学3  同学4  同学5  同学6  同学7  同学8  同学9
# 语文   92   51   58   40   43   40   71   76   56   71
# 数学   81   54   96   84   67   44   70   80   99   89
# 英语   63   92   41   46   96   44   93   90   64   90
# 物理   79   66   43   98   76   64   43   92   48   94
# 化学   83   45   48   45   84   52   54   58   99   64
# size 大小,统计的元素个数。只包含数据
print(score_df.size) # 50
# 获取数据类型
print(score_df.dtypes)
# 语文    int32
# 数学    int32
# 英语    int32
# 物理    int32
# 化学    int32
# dtype: object

常用方法

已知数据 score_df

image.png

# 查看前5行
score_df.head()
# 查看前10行
score_df.head(10)

# 查看后5行
score_df.tail()
# 查看后10行
score_df.tail(10)

获取方法的描述信息统计信息等

score_df.describe()
行名含义示例解释(以“语文”为例)
count非空(有效)样本数一共有 10 个学生的语文成绩
mean平均值(算术平均数)平均语文成绩是 67 分
std标准差(standard deviation)成绩的波动程度是 19.9,说明分数差距较大
min最小值语文最低分 41
25%第 1 四分位数(Q1)有 25% 的学生语文 ≤ 50.5
50%中位数(Q2)一半学生语文 ≤ 64,另一半 ≥ 64
75%第 3 四分位数(Q3)有 75% 的学生语文 ≤ 82.75
max最大值语文最高分 98
# 获取数据的描述性,详细信息
score_df.info()
# <class 'pandas.core.frame.DataFrame'>
# Index: 10 entries, 同学0 to 同学9
# Data columns (total 5 columns):
#  #   Column  Non-Null Count  Dtype
# ---  ------  --------------  -----
#  0   语文      10 non-null     int32
#  1   数学      10 non-null     int32
#  2   英语      10 non-null     int32
#  3   物理      10 non-null     int32
#  4   化学      10 non-null     int32
# dtypes: int32(5)
# memory usage: 280.0+ bytes

索引操作

已知数据是

image.png

新增一列,列名是 同学0,值全部是 stu

score_df['同学0'] = 'stu'
# 删除列,axis = 1 是列
score_df.drop('同学0', axis=1, inplace=True)

image.png

设置索引列

reset_index,可以被执行多次,但是执行多次有上限,会将 index 和 level0置顶过去。

# 设置
score_df.reset_index('month', drop=False, inplace=True)
# 取消设置索引列
score_df.reset_index(inplace=True)
# 设置多列索引
score_df.reset_index(['month', 'year'], drop=False, inplace=True)

数据类型

Pandas数据类型说明对应的Python类型
Object字符串类型string
int整数类型int
float浮点数类型float
datetime日期时间类型datetime包中的datetime类型
timedelta时间差类型datetime包中的timedelta类型
category分类类型无原生类型,可以自定义
bool布尔类型bool(True,False)
nan空值类型None
import pandas as pd
pd.to_datetime('2025-11-10')
# <class 'pandas._libs.tslibs.timestamps.Timestamp'>
pd.to_datetime(['2025-11-10', '2025-11-11', '2025-11-12'])
# DatetimeIndex(['2025-11-10', '2025-11-11', '2025-11-12'], dtype='datetime64[ns]', freq=None)

计算时间间隔

import pandas as pd
start = pd.to_datetime('2025-11-10')
end = pd.to_datetime('2025-11-13')

result = end - start
print(result) # 3 days 00:00:00
print(type(result)) # <class 'pandas._libs.tslibs.timedeltas.Timedelta'>

category 类型

此时有重复的数据。

打印结果为:

0 apple
1 pear
2 orange
3 apple
4 pear
dtype: object

加上 dtype = category,数据一样,但是打印的值类型是3个,减少了内存消耗,只存储唯一值。

0 apple
1 pear
2 orange
3 apple
4 pear
dtype: category
Categories (3, object): ['apple', 'orange', 'pear']

import pandas as pd
# f = pd.Series(['apple', 'pear', 'orange', 'apple', 'pear'])
f = pd.Series(['apple', 'pear', 'orange', 'apple', 'pear'], dtype='category')

操作 pandas 数据

使用语法和 loc 获取

已知 sd 数据为

image.png

因为时间设置了索引,所以是按照时间排的,注意:必须是先列后行

# 获取 open 列
sd['open']

# 必须是5个,因为是5行,控制是否查看这一行。
sd.head(5)[[True, True, True, False, True]]

image.png

# 获取到具体的数据,语法:sd[列][行] 
sd['open']['2018-02-23'] # 22.88
# 这也是获取的,只不过是先行后列,语法:sd.loc[行, 列]
sd.loc['2018-02-23', 'open']

获取区间的数据,语法:loc[开始:结束, 列名],不指定列,是所有列

sd.loc['2018-02-27':'2018-02-22', 'open']
# 获取多列
sd.loc['2018-02-27':'2018-02-22', ['open', 'high']]
# 写一个 : 号也是所有列
sd.loc['2018-02-27':'2018-02-22', :]
# 都不写,所有时间,所有列
sd.loc[:, :]

使用 iloc 获取

iloc 是操作索引的

获取第指定行所有列

# 获取第 0 行所有
print(sd.iloc[0])

image.png

获取指定行的指定列

sd.iloc[0,0]

区间查找

获取前四行数据,只要第0列。

sd.iloc[:4, 0]

获取前四行,并且要第0~4列

sd.iloc[:4, 0:4]
# 获取前四行,所有列
sd.iloc[:4, :]
# 获取所有行所有列
sd.iloc[:, :]

加上步长

# 从第1行到第5行,步长为2,获取2~5列
sd.iloc[1:5:2, 2:5]
# 查看第 0 行和第2行
sd.iloc[[0, 2]]

删除、添加、修改

# 删除 axis = 1 的列,列名是ma20和ma10
sd.drop(['ma20', 'ma10'], axis=1)

在进行修改的时候,可以直接使用列名进行赋值,如果存在则修改,不存在则添加

# 将open列的值设置为1
sd['open'] = 1
# 因为ai列没有,此时是新增
sd['ai'] = '333'
# 这样新增的时候,会每行进行计算,而不是每一列都是一个数据
sd['diff'] = sd['high'] - sd['low']

细节:方括号里写列名和.列名,都是一样的,只是特殊内容,直接写出来,并不合规

排序

已知 sd 数据如下图

image.png

  • ascending:等于 false 是降序排序
  • 注意axis 只能是 0
# 默认是升序排序,指定列名
sd.sort_values('列名', ascending=False)
# 多列名排序
sd.sort_values(['列名', '列名'])
# 多列名排序,并单独指定排序规则
sd.sort_values(['列名', '列名'], ascending=[True, False])
# 根据索引排序,默认是True,升序
sd.sort_index(ascending=True)
# 这样也可以
sd.列名.sort_values()

pandas 基础运算

已知 open 数据如下

image.png

基础运算符 +-*/ 都一样

# 临时数据,此时 s 的结果是open这一列 + 1的数据
s = open + 1
# 此时返回的 s 也是加 1 的
s = open.add(1)

# 修改原数据 + 1
open += 1
# 加法是 open,减法是 sub
open.sub(1)

可以进行两个字段相计算。空用Nan填充

实现对整个DataFrame表加 1

已知整个表的数据为 sd

image.png

sd + 1

pandas 逻辑运算

已知 sd 数据为

image.png

# 筛选出 open 的值大于 23 的
sd[sd.open > 23]
# 多条件判断方式一
sd[(sd.open >= 23) & (sd.open <= 24)]
sd[(sd['open'] >= 23) & (sd['open'] <= 24)]

逻辑运算函数方式

  • query:可以直接写表达式
  • isin:等于比较
# 查询出来 open 的值在 23 和 24 之间
sd.query('open >= 23 & open <= 24')
# 查询出来 open 等于 23.8或者等于22.8
sd[(sd.open == 23.8) | (sd.open == 22.8)]
# query 方式
sd.query('open in [22.8, 23.8]')
# isin 方式
sd[sd.open.isin([22.8, 23.8])]

统计函数

已知数据是

image.png

# 统计每列数据的总条数
sd.count()
sd.count(axis=0)

# 统计每行有多少列
sd.count(axis='columns')
# 统计每列有多少行
sd.count(axis='rows')

# 查看每列最大值
sd.max()
sd.max(0)
# 按行索引统计最大值
sd.max(1)
# 最小值  min
# 查看平均值
sd.mean()

方差怎么算呢,每个值和平均值的差值。

每个值和 平均值的差的一个平方和的平均值。

标准差等于 方差开根号。

# 查看每列的标准差(std),方差(var)
sd.std()
sd.var()

求中位数,将数据从小到大排序,取中间的那个数字,如果是偶数,取中间两个数字的平均值。

df = pd.DataFrame({
    'col1': [2, 3, 4, 5, 4, 2], # 排序后:2,2,3,4,4,5
    'col2': [0, 1, 2, 3, 4, 2]  # 排序后:0,1,2,2,3,4
})
df.median()
# col1    3.5,3和4之间就是3.5
# col2    2.0 # 两个一样就是 2
# dtype: float64

如果不是偶数,是奇数,直接取中间的数字

df = pd.DataFrame({
    'col1': [2, 3, 4, 5, 4, 2, 10], # 排序后:2,2,3,4,4,5,10
    'col2': [0, 1, 2, 3, 4, 2, 10]  # 排序后:0,1,2,2,3,4,10
})
# 求中位数
df.median()
# col1    4.0
# col2    2.0
# dtype: float64

# 求最大值位置,找出行 索引
df.idxmax()
# df.idxmax(1) # 如果是1没有意义,求出来的是列名
# col1    6
# col2    6
# dtype: int64

累加和函数

已知 sd 数据为

image.png

计算每列的累加和

# 求每列累加和
sd.cumsum()

image.png

# 计算 open 列
sd.open.cumsum()
# 绘制所有列的可视化图
sd.cumsum().plot()

apply 函数执行自定义函数

apply(函数对象,axis=0)

执行自定义函数,按行 1 或者 按列 0 传入数据。

# 求每行的最大值
sd.apply(lambda col: col.max(), axis=0)
# 求每行的最小值
sd.apply(lambda col: col.max(), axis=0)

image.png

以行的方式传入

sd.apply(lambda row: row.max(), axis=1)

读写文件

csv 是以逗号分隔,tsv 是以 Tab 分割。

读取 CSV

  • index_col:设置索引列
# 读取所有列
sd = pd.read_csv('./stock_day.csv')
# 加载指定列
sd = pd.read_csv('./stock_day.csv', usecols=['high', 'low'])

写入 csv

  • index:是否将索引写入,默认True
  • header:是否将表头写入,默认True
sd.to_csv('./testHead10.csv', index=True, header=True)

读取 TSV

  • columns:指定写出的列
  • sep:按 \t 分割
  • mode='a':表示追加
sd.to_csv('./testHead10.tsv', sep='\t', columns=['low'])

读写 SQL

创建引擎对象

  • mysql+pymysql:要操作的数据库,具体用的包
  • root:123456:要操作的数据库的账号和密码
  • localhost:3306:数据库的IP和端口
  • my_project:数据库表
  • charset:码表
# 导包
from sqlalchemy import create_engine
engine =  create_engine('mysql+pymysql://root:123456@localhost:3306/my_project?charset=utf8')
# Engine(mysql+pymysql://root:***@localhost:3306/my_project?charset=utf8)

写入

  • 参数一:导入的sql表名
  • 参数二:连接对象
  • 参数三:是否包含索引
  • 参数四:导入模式(如果表名存在),fail/报错, replace/覆盖,append/追加
sd = pd.read_csv('./csv示例文件.csv', encoding='GBK', index_col=0)
sd.to_sql('person_info', engine, index=False, if_exists='replace')

读入

  • 参数一:sql语句
  • 参数二:引擎对象
import pandas as pd
from sqlalchemy import create_engine
engine =  create_engine('mysql+pymysql://root:123456@localhost:3306/my_project?charset=utf8')
pd.read_sql('select * from person_info', engine)

数据转JSON

  • ensure_ascii:是否将中文转换为 ASCII 码
import json
# 创建一个字典 
dict_data = {'name': '乔峰', 'age': 38, 'sex': '男'}

# 将字典转为JSON
json2 = json.dumps(dict_data, ensure_ascii=False)

# 将 JSON 转换为 字典
newDict = json.loads(json2)

读取JSON文件

首先 json 文件是如下

{"name": "乔峰", "age": 38, "sex": "男"}
{"name": "乔峰2", "age": 39, "sex": "男"}
{"name": "乔峰3", "age": 40, "sex": "男"}
  • 参数一:是路径
  • 参数二:是读取方式,表示每个对象是一行
    • records:每个对象一行
    • columns:以列为主
    • index:以索引为主
  • 参数三:是一行一行的读取
import pandas as pd
pd.read_json('./my.json', orient='records', lines=True)

写入 JSON 文件

已知数据是

image.png

import pandas as pd
df.to_json('./my_to.json')
# 效果同上
df.to_json('./my_to.json', orient='columns')

转换后是 image.png

希望是按行读取,返回列表 orient='records'

import pandas as pd
df.to_json('./my_to.json', orient='records')

image.png

希望每个对象一行一行,而不是一个列表,lines = True

import pandas as pd
df.to_json('./my_to.json', orient='records', lines=True)

image.png

DateFrame 列操作

已知 sd 数据为

image.png

这些都会修改原始数据

增加 col1 列,值全是 2

sd['col1'] = 2

增加col2 列,每列指定数据,这种方式,假设该 DataFrame,有五列,就只能指定 5 个,否则会报错

sd['col2'] = [1, 2, 3, 4, 5]

还可以使用其他列计算

sd['col3'] = sd.year * 2

不会修改原始数据的

# 添加一列 cole = 1
sd.assign(cole = 1)
sd.assign(cole = [1,2,3,4,5])
sd.assign(cole = sd.year * 2)

使用 series 对象传入,如果行数对不齐,使用 NAN 填充

import pandas as pd
series = pd.Series(['段延庆', '王伟', '叶二娘', '王小虎'])
sd.assign(col = series)

使用函数

def fun1(df):
    # 返回索引
    return df.index.values

sd.assign(col = fun1)

一次添加多个列

sd.assign(
    col=2, # 列1
    col1=[1, 2, 3, 4, 5] # 列2
)

删除

删除行

# 删除第 0 行,不会修改数据,这是根据索引
sd.drop([0])
# 效果同上
sd.drop([0], axis = 0)

# 删除多行
sd.drop([0, 1, 4])

删除列

# 删除列
sd.drop(['year', 'col', 'col1'], axis=1)

修改原数据,删除列

del sd['year']

去重

dataframe 的去重

已知数据 sd 数据是 9930 行

image.png

# 执行去重
sd.drop_duplicates()

serires 的去重

假设有个 s 变量是series类型

# 去重
s.unique()
# 去重
s.drop_duplicates()

修改

# 修改df5,的GDP列为 66,临时修改
df5.assign(GDP=66)
# 同上
df5['GDP'] = [5, 4, 3, 2, 1]

replace 替换

# 将 sd2 的 year 字段的 1960 修改为 2025
sd2.year.replace(1960, 2025)

# 替换多个值,方式一
sd2.replace([1960, '日本', '中国'], [2025, '鬼子', '龙国'])
# 多个值,方式二
sd2.replace({1960: 2025, '日本': '鬼子', '中国': '龙国'})

查询dataFrame中的数据

# 默认取前5行数据
df.head()
df.head(10) # 取前10行

# 默认取后5行数据
df.tail()
df.tail(15) # 倒数15行

获取一列或多列数据

df['country']
df.country
df[['country', 'GDP']] # 返回新的df

索引下标切片取行

格式:df[start:stop:step]

df[:3] # 取前3行
df[:5:2] # 取前5行,步长为2
df[1::3] # 取第2行到最后所有行,步长为3

查找数据

df.query('country=="帕劳"')
df[df['country']=='帕劳']

多条件查询

df.query('country=="中国" or country=="日本" or country=="美国"').query('year in ["2015", "2016", "2017", "2018", "2019"]')
df.query('(country=="中国" or country=="日本" or country=="美国") and year in ["2015", "2016", "2017", "2018", "2019"]')

排序函数

已知 sd 数据为

image.png

# 根据索引排序,默认升序, ascending 设置为false ,降序
sd.sort_index(ascending=False)
# 按照字段排序,默认升序,ascending 设置 False,降序
sd.sort_values('GDP', ascending=False)
# 如果year一样,按照GDP排序,降序排序
sd.sort_values(['year', 'GDP'], ascending=False)
# 如果year一样,按照GDP排序,year 是降序排序,GDP 是升序排序
sd.sort_values(['year', 'GDP'], ascending=[False, True])

排名函数,rank

定义数据

df = pd.DataFrame({
    '姓名': ['小明', '小美', '小强', '小兰'],
    '成绩': [100, 90, 90, 80]
})

image.png

# 按照排名,降序排序,评分一致,取平均值
df.rank(ascending=False)
df.rank(ascending=False, method='average')
# 评分一致,取最小值
df.rank(ascending=False, method='min')
# 评分一致,取最大值
df.rank(ascending=False, method='max')
# 评分一致,数值相同,完全等价于SQL中的dense_rank(),完全等于 min函数
df.rank(ascending=False, method='dense')

缺失值处理

已知 sd 数据为

image.png

查看信息

sd.info()

# <class 'pandas.core.frame.DataFrame'>
# RangeIndex: 1000 entries, 0 to 999 # 有 0 ~ 999 行数据
# Data columns (total 12 columns):
#  #   Column              Non-Null Count  Dtype  
# ---  ------              --------------  -----  
#  0   Rank                1000 non-null   int64  
#  1   Title               1000 non-null   object 
#  2   Genre               1000 non-null   object 
#  3   Description         1000 non-null   object 
#  4   Director            1000 non-null   object 
#  5   Actors              1000 non-null   object 
#  6   Year                1000 non-null   int64  
#  7   Runtime (Minutes)   1000 non-null   int64  
#  8   Rating              1000 non-null   float64
#  9   Votes               1000 non-null   int64  
#  10  Revenue (Millions)  872 non-null    float64 # 872行非空
#  11  Metascore           936 non-null    float64 # 936行非空
# dtypes: float64(3), int64(4), object(5)
# memory usage: 93.9+ KB

判断缺失值

import pandas as pd
import numpy as np
# 打印的列表有 true 的就是空值
sd.isnull()
# 打印的列表有 true 的是非空值
sd.notnull()
# 打印缺失值的个数
sd.isnull().sum()
# 打印非缺失值的个数
sd.notnull().sum()
# 使用 numpy 的all方法,判断是否全部不为空,有一个就 false
np.all(sd.notnull())

删除缺失值

比如,A 字段 和 B 字段,B字段为空,那么即使A字段不为空,也会删除。

但是索引会留下,比如删除了 8 行,那么 9 索引不会往前靠。

# 删除行
sd.dropna()
# 删除列
sd.dropna(axis=1)

填充缺失值

根据平均值,填充所有列。

# 计算平均值
avg = sd['Revenue (Millions)'].mean()
# 执行填充
sd.fillna(avg, inplace=True)

循环遍历,是否存在缺失值,用每列的平均值填充每列

for col_name in sd:
    # 判断是否存在缺失值
    if sd[col_name].isnull().sum() > 0:
        # 计算每列平均值
        mean_value = sd[col_name].mean()
        # 填充给每列
        sd[col_name] = sd[col_name].fillna(mean_value)

如果表示空的不是NaN呢,那该怎么处理

已知数据集中使用的是 ? 号作为空值,处理逻辑是:先进行更换成 nan,再进行删除

# 加载数据
wis = pd.read_csv("https://archive.ics.uci.edu/ml/machine-learning-databases/breast-cancer-wisconsin/breast-cancer-wisconsin.data")
# 将问号替换为空
wis.replace('?', np.nan, inplace=True)
# 进行删除
wis.dropna(inplace=True)

数据合并

concat 可以合并多个 DataFrame 对象,可以行也可以列合并

已知数据如下

import pandas as pd
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']})

left

image.png

right

image.png

合并结果

  • 列名一样,列合并
  • 列名不一样,行合并
  • 默认是纵向合并
import pandas as pd
pd.concat([left, right])
# 同上
# pd.concat([left, right], axis=0)

上述会发现,索引居然出现了重复,去除索引重复,忽略索引

pd.concat([left, right], axis=0, ignore_index=True)

image.png

列合并呢,直接往后面堆叠就可以,但是会参考行索引

import pandas as pd
pd.concat([left, right], axis=1)

image.png

行索引不一致演示,会使用空填充

import pandas as pd
pd.concat([left, right], axis=1)

image.png

merge

只能两个两个合并

  • 参数1:第一个df对象
  • 参数2:第二个df对象
  • 参数3:how 连接方式
    • left 左外连接,
    • right 右外连接
    • inner 内连接
    • outer 全连接,满外连接
  • 参数4:on 关联字段,表示参考谁合并

左外连接

import pandas as pd
pd.merge(left, right, how='left', on=['key1'])

image.png

结果

image.png

右连接

也是按照右表,去一一的找,找不到就丢弃左表的。

import pandas as pd
pd.merge(left, right, how='right', on=['key1', 'key2'])

内连接,基于左右表全有

pd.merge(left, right, how='inner', on=['key1', 'key2'])

全连接

会基于左表的全部和右表的全部

pd.merge(left, right, how='outer', on=['key1', 'key2'])

聚合分组基础

已知 sd 数据为

image.png

根据 gender_group 分组得到 DataFrameGroupBy 对象

sd.groupby('gender_group')

获取单列分组对象 SeriesGroupBy 对象

sd.groupby('gender_group')['city']

获取分组的数据呢,Female 是字段值,就是分组的类型中,有这个字段值。

# 单列分组
sd_gb = sd.groupby('gender_group')
sd_gb.get_group('Female')

# 多列分组
sd_gb = sd.groupby(['city', 'gender_group'])
sd_gb.get_group(('深圳', 'Female'))

获取第一条和最后一条

sd_gb = sd.groupby(['gender_group', 'city' ])
# 获取第一条
sd_gb.first()
# 获取最后一条
    sd_gb.last()

image.png

DataFrameGroupBy 对象

image.png

分组集合操作

按照城市分组,计算每个城市的客户的数量,已知客户字段 = customer

sum() 是求和

# 格式:sd.groupby(分组字段).[列名].sum()
sd.groupby('city').customer.sum()

# 效果同上
sd.groupby('city').agg(
    customer2=('customer', 'sum')
)

第二种方式 分组采用 city,按customer列,进行sum聚合

sd.pivot_table(index='city', values='customer', aggfunc='sum')

透视表行列转换

  • columns='gender_group',用这列的值,作为索引列,查出来这列的数据。
sd.pivot_table(index='city', columns='gender_group', values='customer', aggfunc='sum')

image.png

案例

# 写法一
sd.groupby(['city']).agg(
    revenue=('revenue', 'mean'),
    unit_cost=('unit_cost', 'sum')
)
# 写法二
sd.pivot_table(index=['city', 'channel'], values=['revenue', 'unit_cost'],
               aggfunc={'revenue': 'mean', 'unit_cost': 'sum'})

对于写法二,还能变形,就是我不指定那个字段计算平均值,那个字段求和,我都要

sd.pivot_table(index=['city', 'channel'], values=['revenue', 'unit_cost'],
               aggfunc=['sum', 'mean'])

还能行列转置变形

sd.pivot_table(index=['city'], columns='channel', values=['revenue', 'unit_cost'],
               aggfunc={'revenue': 'sum', 'unit_cost': 'mean'})

image.png


highlight: a11y-dark theme: lilsnake

过滤分组

执行流程是,从 city 先聚合分组后,再将每一行传递过去,进行过滤。

sd.groupby('city').filter(lambda x: x.revenue.mean() > 200)
sd.groupby('city').revenue.filter(lambda x: x.mean() > 200)

交叉分组

df = pd.DataFrame({
    '性别': ['男', '女', '男', '女', '男', '女', '女', '男', '男'],
    '购买': ['是', '否', '是', '是', '否', '否', '是', '否', '是']
})
# 创建交叉表
cros = pd.crosstab(df['性别'], df['购买'])

image.png