Pandas基础-CDA学习打卡
Pandas
Pandas 是一个开源的 Python 数据分析库,它提供了高性能、易用的数据结构和数据分析工具。Pandas 的设计理念是让数据处理和分析工作在 Python 中变得更加容易。以下是 Pandas 的一些关键特性:
数据结构
Series:一维数组,类似于 Python 的列表,但是每个元素都有一个索引。
DataFrame:二维表格结构,类似于 Excel 或 SQL 表,每列可以是不同的数据类型。
Panel:三维数组,较少使用,主要在处理多维度数据时使用。
常用功能
数据导入:支持多种数据格式,如 CSV、Excel、SQL、HDF5 等。
数据清洗:缺失值处理、重复值处理、数据类型转换等。
数据筛选:基于条件筛选数据。
数据分组:类似于 SQL 的分组功能,支持聚合、转换等操作。
数据合并:支持多种方式的合并(merge)、连接(join)操作。
时间序列处理:提供强大的时间序列处理功能。
文本数据处理:字符串操作、正则表达式等。
数据类型 Series
Series:一维数组。
import pandas as pd
s = pd.Series([2,3,5,7,11],name='A')
s
0 2
1 3
2 5
3 7
4 11
Name: A, dtype: int64
# 以时间为索引的Series
dts1 = pd.DatetimeIndex(['2024-01-01 00:00:00','2024-01-01 03:00:00','2024-01-01 06:00:00'])
dts1
DatetimeIndex(['2024-01-01 00:00:00', '2024-01-01 03:00:00',
'2024-01-01 06:00:00'],
dtype='datetime64[ns]', freq=None)
# 另一种写法 pd.date_range可以按一定的频率生成时间序列
dts2 = pd.date_range(start = '2024-01-01',periods=6,freq='3H')
dts2
DatetimeIndex(['2024-01-01 00:00:00', '2024-01-01 03:00:00',
'2024-01-01 06:00:00', '2024-01-01 09:00:00',
'2024-01-01 12:00:00', '2024-01-01 15:00:00'],
dtype='datetime64[ns]', freq='3H')
dts3 = pd.date_range('2024-01-01',periods=6,freq='d')
dts3
DatetimeIndex(['2024-01-01', '2024-01-02', '2024-01-03', '2024-01-04',
'2024-01-05', '2024-01-06'],
dtype='datetime64[ns]', freq='D')
数据类型 DataFrame
DataFrame:二维的表格数据结构,可以理解为Series的容器,既有行索引,又有列索引。
# 从字典 创建DataFrame
d = {
'A':[1,2,3],
'B':[4,5,6],
'C':[7,8,9]}
df = pd.DataFrame(data=d)
df
A | B | C | |
---|---|---|---|
0 | 1 | 4 | 7 |
1 | 2 | 5 | 8 |
2 | 3 | 6 | 9 |
# 从列表创建DataFrame
d = [[4,7,10],[5,8,11],[6,9,11]]
df1 = pd.DataFrame(
data=d,
index=['a','b','c'],
columns=["A","B","C"]
)
df1
A | B | C | |
---|---|---|---|
a | 4 | 7 | 10 |
b | 5 | 8 | 11 |
c | 6 | 9 | 11 |
# 从数组创建DataFrame
# 数组(array)
import numpy as np
d = np.array([[1,2,3],[4,5,6],[7,8,9]])
df2 = pd.DataFrame(
data = d,
index=["a","b","c"],
columns=["A","B","C"]
)
df2
A | B | C | |
---|---|---|---|
a | 1 | 2 | 3 |
b | 4 | 5 | 6 |
c | 7 | 8 | 9 |
数据查看
import numpy as np
import pandas as pd
d = np.array([[81,2,34,99],
[7,4,5,6],
[8,9,5,11],
[89,3,5,8],
[9,2,34,9]])
df = pd.DataFrame(data =d,columns=list("abcd"))
df
a | b | c | d | |
---|---|---|---|---|
0 | 81 | 2 | 34 | 99 |
1 | 7 | 4 | 5 | 6 |
2 | 8 | 9 | 5 | 11 |
3 | 89 | 3 | 5 | 8 |
4 | 9 | 2 | 34 | 9 |
# 查看前几行
df.head(2)
a | b | c | d | |
---|---|---|---|---|
0 | 81 | 2 | 34 | 99 |
1 | 7 | 4 | 5 | 6 |
# 查看后几行
df.tail(2)
a | b | c | d | |
---|---|---|---|---|
3 | 89 | 3 | 5 | 8 |
4 | 9 | 2 | 34 | 9 |
# 随机查看几行
df.sample(2)
a | b | c | d | |
---|---|---|---|---|
4 | 9 | 2 | 34 | 9 |
3 | 89 | 3 | 5 | 8 |
# 按列选取
df["a"]
0 81
1 7
2 8
3 89
4 9
Name: a, dtype: int32
条件查询
d = np.array([[81,2,34,99],
[7,4,5,6],
[8,9,5,11],
[89,3,5,8],
[9,2,34,9]])
df = pd.DataFrame(data =d,columns=list("abcd"))
df
a | b | c | d | |
---|---|---|---|---|
0 | 81 | 2 | 34 | 99 |
1 | 7 | 4 | 5 | 6 |
2 | 8 | 9 | 5 | 11 |
3 | 89 | 3 | 5 | 8 |
4 | 9 | 2 | 34 | 9 |
# 单一条件
df[df["a"]>60]
a | b | c | d | |
---|---|---|---|---|
0 | 81 | 2 | 34 | 99 |
3 | 89 | 3 | 5 | 8 |
df.loc[df["a"]>60]
a | b | c | d | |
---|---|---|---|---|
0 | 81 | 2 | 34 | 99 |
3 | 89 | 3 | 5 | 8 |
# 单一条件 & 多列
df.loc[df["a"]>60,["a","b","d"]]
a | b | d | |
---|---|---|---|
0 | 81 | 2 | 99 |
3 | 89 | 3 | 8 |
# 多条件
df[(df["a"]>20) & (df["b"]>1)]
a | b | c | d | |
---|---|---|---|---|
0 | 81 | 2 | 34 | 99 |
3 | 89 | 3 | 5 | 8 |
# 多条件筛选行 & 指定列筛选列
df.loc[(df["a"]>60)&(df["b"]>2),["a","b","d"]]
a | b | d | |
---|---|---|---|
3 | 89 | 3 | 8 |
# 多条件筛选行 & 指定列筛选列
df.loc[(df["a"]>60)&(df["b"]>3),["a","b","d"]]
a | b | d |
---|
数学计算
import pandas as pd
import numpy as np
d = np.array([[81,28,24,25,96],
[8,35,56,98,39],
[13,39,55,36,3],
[70,54,69,48,12],
[63,80,97,25,70]])
df =pd.DataFrame(data=d,columns=list("abcde"))
df
a | b | c | d | e | |
---|---|---|---|---|---|
0 | 81 | 28 | 24 | 25 | 96 |
1 | 8 | 35 | 56 | 98 | 39 |
2 | 13 | 39 | 55 | 36 | 3 |
3 | 70 | 54 | 69 | 48 | 12 |
4 | 63 | 80 | 97 | 25 | 70 |
聚合计算
聚合计算:是指对数据进行汇总和统计的操作。常用的聚合计算方法包括计算均值、求和、最大值、最小值、计数等。
df["a"].mean()
47.0
df["a"].sum()
235
df["a"].max()
81
df["a"].min()
8
df["a"].count()
5
df["a"].median() # 中位数
63.0
df["a"].var() # 方差
1154.5
df["a"].skew() # 偏度
-0.45733193928530436
df["a"].kurt() # 峰度
-2.9999915595685325
df["a"].cumsum() # 累计求和
0 81
1 89
2 102
3 172
4 235
Name: a, dtype: int32
df["a"].cumprod() # 累计求积
0 81
1 648
2 8424
3 589680
4 37149840
Name: a, dtype: int32
df["a"].diff() # 差分
0 NaN
1 -73.0
2 5.0
3 57.0
4 -7.0
Name: a, dtype: float64
df["a"].mad() # 平均绝对值
29.2
按行、列聚合计算
df.sum(axis=0) # 按列汇总求和
a 235
b 236
c 301
d 232
e 220
dtype: int64
df.sum(axis=1) # 按行汇总求和
0 254
1 236
2 146
3 253
4 335
dtype: int64
df.describe() # 描述性统计
a | b | c | d | e | |
---|---|---|---|---|---|
count | 5.000000 | 5.000000 | 5.000000 | 5.000000 | 5.000000 |
mean | 47.000000 | 47.200000 | 60.200000 | 46.400000 | 44.000000 |
std | 33.977934 | 20.656718 | 26.395075 | 30.369392 | 39.083244 |
min | 8.000000 | 28.000000 | 24.000000 | 25.000000 | 3.000000 |
25% | 13.000000 | 35.000000 | 55.000000 | 25.000000 | 12.000000 |
50% | 63.000000 | 39.000000 | 56.000000 | 36.000000 | 39.000000 |
75% | 70.000000 | 54.000000 | 69.000000 | 48.000000 | 70.000000 |
max | 81.000000 | 80.000000 | 97.000000 | 98.000000 | 96.000000 |
agg函数
对整个DataFrame批量使用多个聚合函数
df.agg(["sum","mean","max","min","median"]) # 默认按照列
a | b | c | d | e | |
---|---|---|---|---|---|
sum | 235.0 | 236.0 | 301.0 | 232.0 | 220.0 |
mean | 47.0 | 47.2 | 60.2 | 46.4 | 44.0 |
max | 81.0 | 80.0 | 97.0 | 98.0 | 96.0 |
min | 8.0 | 28.0 | 24.0 | 25.0 | 3.0 |
median | 63.0 | 39.0 | 56.0 | 36.0 | 39.0 |
df.agg(["sum","mean","max","min","median"],axis=1)
sum | mean | max | min | median | |
---|---|---|---|---|---|
0 | 254.0 | 50.8 | 96.0 | 24.0 | 28.0 |
1 | 236.0 | 47.2 | 98.0 | 8.0 | 39.0 |
2 | 146.0 | 29.2 | 55.0 | 3.0 | 36.0 |
3 | 253.0 | 50.6 | 70.0 | 12.0 | 54.0 |
4 | 335.0 | 67.0 | 97.0 | 25.0 | 70.0 |
对DataFrame的某些列应用不同的聚合函数
df.agg({"a":["max","min"],"b":["sum","mean"],"c":["median"]})
a | b | c | |
---|---|---|---|
max | 81.0 | NaN | NaN |
min | 8.0 | NaN | NaN |
sum | NaN | 236.0 | NaN |
mean | NaN | 47.2 | NaN |
median | NaN | NaN | 56.0 |
apply、applymap、map函数
注:applymap函数在新版已被弃用,这里的案例是基于pandas==1.3.2写的
在Python 中如果想要对数据使用函数,可以借助apply(),applymap(),map()对数据进行转换,括号里面可以是直接函数式,或者自定义函数(def)或者匿名函数(lambda)
1、当我们要对数据框(DataFrame)的数据进行按行或按列操作时用apply()
df.apply(lambda x:x.max()-x.min(),axis=1) # axis=1 对行数据进行操作
0 72
1 90
2 52
3 58
4 72
dtype: int64
df.apply(lambda x:x.max()-x.min(),axis=0) # axis=0 对列数据进行操作
a 73
b 52
c 73
d 73
e 93
dtype: int64
2、当我们要对数据框(DataFrame)的每一个数据进行操作时用applymap(),返回结果是DataFrame格式
df.applymap(lambda x:1 if x>60 else 0) # applymap() 对每一个数据进行操作
a | b | c | d | e | |
---|---|---|---|---|---|
0 | 1 | 0 | 0 | 0 | 1 |
1 | 0 | 0 | 0 | 1 | 0 |
2 | 0 | 0 | 0 | 0 | 0 |
3 | 1 | 0 | 1 | 0 | 0 |
4 | 1 | 1 | 1 | 0 | 1 |
3、当我们要对Series的每一个数据进行操作时用map()
df["a"].map(lambda x : 1 if x >60 else 0)
0 1
1 0
2 0
3 1
4 1
Name: a, dtype: int64
总结
apply() 函数可以在DataFrame或Series上用自定义函数,可以在行或者列上进行操作。
applymap()函数只适用于DataFrame,可以在每个元素上应用自定义函数。
map()函数只适用于Series,用于将每个元素映射到另一个值。
pandas合并连接
在pandas中,有很多种方法可以合并和拼接数据。常见的方法包括:append()、concat()、merge()。
追加(Append)
append()函数用于将一个DataFrame或Series对象追加到另一个DataFrame中。
import pandas as pd
df1 = pd.DataFrame({
"A":["a","b"],
"B":[1,2]
})
df1
A | B | |
---|---|---|
0 | a | 1 |
1 | b | 2 |
df2 = pd.DataFrame({
"A":["b","c","d"],
"B":[2,3,4]
})
df2
A | B | |
---|---|---|
0 | b | 2 |
1 | c | 3 |
2 | d | 4 |
df1.append(df2,ignore_index=True)
C:\Users\Alwen\AppData\Local\Temp\ipykernel_2976\2717680053.py:1: FutureWarning: The frame.append method is deprecated and will be removed from pandas in a future version. Use pandas.concat instead.
df1.append(df2,ignore_index=True)
A | B | |
---|---|---|
0 | a | 1 |
1 | b | 2 |
2 | b | 2 |
3 | c | 3 |
4 | d | 4 |
合并(Concat)
concat()函数用于沿指定轴将多个对象(比如Series、DataFrame)堆叠在一起。可以沿行或列方向进行拼接。
# 上下堆叠的例子
df1 = pd.DataFrame({
"A":["a","b"],
"B":[1,2]
})
df1
A | B | |
---|---|---|
0 | a | 1 |
1 | b | 2 |
df2 = pd.DataFrame({
"A":["b","c","d"],
"B":[2,3,4]
})
df2
A | B | |
---|---|---|
0 | b | 2 |
1 | c | 3 |
2 | d | 4 |
pd.concat([df1,df2],axis=0) # 上下拼接 按照列进行拼接
A | B | |
---|---|---|
0 | a | 1 |
1 | b | 2 |
0 | b | 2 |
1 | c | 3 |
2 | d | 4 |
# 左右堆叠的列子
df1 = pd.DataFrame({"A":["a","b"]})
df1
A | |
---|---|
0 | a |
1 | b |
df2 = pd.DataFrame({
"B":[1,2],
"C":[3,4]
})
df2
B | C | |
---|---|---|
0 | 1 | 3 |
1 | 2 | 4 |
pd.concat([df1,df2],axis=1) # 左右拼接 按照行拼接
A | B | C | |
---|---|---|---|
0 | a | 1 | 3 |
1 | b | 2 | 4 |
连接(Merge)
merge()函数用于根据一个或多个键将两个DataFrame的行连接起来。类似SQL中的JOIN操作。
数据连接1(pd.merge)
inner 和 outer连接
df1 = pd.DataFrame({
"A":["a","b","c"],
"B":[1,2,3]
})
df1
A | B | |
---|---|---|
0 | a | 1 |
1 | b | 2 |
2 | c | 3 |
df2 = pd.DataFrame({
"A":["b","c","d"],
"B":[2,3,4]
})
df2
A | B | |
---|---|---|
0 | b | 2 |
1 | c | 3 |
2 | d | 4 |
pd.merge(df1,df2,how="inner")
A | B | |
---|---|---|
0 | b | 2 |
1 | c | 3 |
pd.merge(df1,df2,how="outer")
A | B | |
---|---|---|
0 | a | 1 |
1 | b | 2 |
2 | c | 3 |
3 | d | 4 |
数据连接2(pd.merge)
左右连接 left right
df1 = pd.DataFrame({
"A":["a","b","c"],
"B":[1,2,3]
})
df1
A | B | |
---|---|---|
0 | a | 1 |
1 | b | 2 |
2 | c | 3 |
df2 = pd.DataFrame({
"A":["b","c","d"],
"C":[2,3,4]
})
df2
A | C | |
---|---|---|
0 | b | 2 |
1 | c | 3 |
2 | d | 4 |
pd.merge(df1,df2,how = "left",on="A") # 左连接
A | B | C | |
---|---|---|---|
0 | a | 1 | NaN |
1 | b | 2 | 2.0 |
2 | c | 3 | 3.0 |
pd.merge(df1,df2,how="right",on="A") # 右连接
A | B | C | |
---|---|---|---|
0 | b | 2.0 | 2 |
1 | c | 3.0 | 3 |
2 | d | NaN | 4 |
pd.merge(df1,df2,how="inner",on="A") # 内连接
A | B | C | |
---|---|---|---|
0 | b | 2 | 2 |
1 | c | 3 | 3 |
pd.merge(df1,df2,how="outer",on = "A") # 外连接
A | B | C | |
---|---|---|---|
0 | a | 1.0 | NaN |
1 | b | 2.0 | 2.0 |
2 | c | 3.0 | 3.0 |
3 | d | NaN | 4.0 |
补充1个小技巧
df1[df1["A"].isin(df2["A"])] # 返回在df1中列"A"的值在df2中国也存在的行
A | B | |
---|---|---|
1 | b | 2 |
2 | c | 3 |
df1[~df1["A"].isin(df2["A"])] # 返回在df1中列"A"的值在df2中不存在的行
A | B | |
---|---|---|
0 | a | 1 |
pandas分组聚合
分组聚合(group by)顾名思义就是分2步:
1.先分组:根据某列数据的值进行分组。用groupby()对某列进行分组。
2.后聚合:将结果应用聚合函数进行计算。在agg()函数里应用聚合函数被计算结果。如:sum()、mean()、count()、max()、min()等,用于对每个分组进行聚合计算。
import pandas as pd
import numpy as np
import random
df = pd.DataFrame({
"A":["a","b","a","b","a","b"],
"B":["L","L","M","N","M","M"],
"C":[107,177,139,3,52,38],
"D":[22,59,38,50,60,82]
})
df
A | B | C | D | |
---|---|---|---|---|
0 | a | L | 107 | 22 |
1 | b | L | 177 | 59 |
2 | a | M | 139 | 38 |
3 | b | N | 3 | 50 |
4 | a | M | 52 | 60 |
5 | b | M | 38 | 82 |
单列分组
1.对单列分组后应用sum聚合函数
df.groupby("A").sum()
C | D | |
---|---|---|
A | ||
a | 298 | 120 |
b | 218 | 191 |
2.对单列分组后应用单个指定的聚合函数
df.groupby("A").agg({"C":"min",}).rename(columns={"C":"C_min"})
C_min | |
---|---|
A | |
a | 52 |
b | 3 |
3.对单列分组后应用多个指定的聚合函数
df.groupby("A").agg({"C":"max","D":"min"}).rename(columns={"C":"C_max","D":"D_min"})
C_max | D_min | |
---|---|---|
A | ||
a | 139 | 22 |
b | 177 | 50 |
两列分组
1.对多列分组后应用sum聚合函数
df.groupby(["A","B"]).sum()
C | D | ||
---|---|---|---|
A | B | ||
a | L | 107 | 22 |
M | 191 | 98 | |
b | L | 177 | 59 |
M | 38 | 82 | |
N | 3 | 50 |
2.对两列进行group后,都应用max聚合函数
df.groupby(["A","B"]).agg({"C":"max"}).rename(columns={"C":"C_max"})
C_max | ||
---|---|---|
A | B | |
a | L | 107 |
M | 139 | |
b | L | 177 |
M | 38 | |
N | 3 |
3.对两列进行分组group后,应用max、min聚合函数。
df.groupby(["A","B"]).agg({"C":"max","D":"min"}).rename(columns={"C":"C_MAX","D":"D_MIN"})
C_MAX | D_MIN | ||
---|---|---|---|
A | B | ||
a | L | 107 | 22 |
M | 139 | 38 | |
b | L | 177 | 59 |
M | 38 | 82 | |
N | 3 | 50 |
补充1:应用自定义的聚合函数
df = pd.DataFrame({
"A":["a","b","a","b","a","b"],
"B":["L","L","M","N","M","M"],
"C":[107,177,139,3,52,38],
"D":[22,59,38,50,60,82]
})
df
A | B | C | D | |
---|---|---|---|---|
0 | a | L | 107 | 22 |
1 | b | L | 177 | 59 |
2 | a | M | 139 | 38 |
3 | b | N | 3 | 50 |
4 | a | M | 52 | 60 |
5 | b | M | 38 | 82 |
## 使用自定义的聚合函数计算每个分组的最大值和最小值
def custom_agg(x):
return x.max() - x.min()
result = df[["B","C"]].groupby("B").agg({"C":custom_agg})
result
C | |
---|---|
B | |
L | 70 |
M | 101 |
N | 0 |
补充2:开窗函数(类似于SQL里面的over partition by):
使用transform函数计算每个分组的均值
# 使用transform函数计算每个分组的均值
df["B_C_std"] = df[["B","C"]].groupby("B")["C"].transform("mean")
df
A | B | C | D | B_C_std | |
---|---|---|---|---|---|
0 | a | L | 107 | 22 | 142.000000 |
1 | b | L | 177 | 59 | 142.000000 |
2 | a | M | 139 | 38 | 76.333333 |
3 | b | N | 3 | 50 | 3.000000 |
4 | a | M | 52 | 60 | 76.333333 |
5 | b | M | 38 | 82 | 76.333333 |
补充3:分组聚合拼接字符串pandas实现类似group_concat功能
df = pd.DataFrame({
"姓名":["张三","张三","张三","李四","李四","李四"],
"科目":["语文","数学","英语","语文","数学","英语"]
})
df
姓名 | 科目 | |
---|---|---|
0 | 张三 | 语文 |
1 | 张三 | 数学 |
2 | 张三 | 英语 |
3 | 李四 | 语文 |
4 | 李四 | 数学 |
5 | 李四 | 英语 |
补充:按某列分组,将另一列文本拼接合并
按名称分组,把每个人的科目拼接到一个字符串
# 对整个group对象中的所有列应用join连接元素
(df.astype(str) # # 先将数据全转为字符
.groupby("姓名") #分组
.agg(lambda x : ",".join(x)))[["科目"]] # join 连接元素
科目 | |
---|---|
姓名 | |
张三 | 语文,数学,英语 |
李四 | 语文,数学,英语 |
pandas 数据重塑
数据重塑,顾名思义就是给数据做各种变形,主要有以下几种:
1.df.pivot 数据变形
2.df.pivot_table 数据透视表
3.df.stack/unstack 数据堆叠
4.df.melt 数据融合
5.df.cross 数据交叉表
df.pivot 数据变形
根据索引(index)、列(column)(values)值,对原有DataFrame(数据框)进行变形重塑,俗称长表转宽表
import pandas as pd
import numpy as np
df = pd.DataFrame({
"姓名":["张三","张三","张三","李四","李四","李四"],
"科目":["语文","数学","英语","语文","数学","英语"],
"成绩":[91,80,100,80,100,96]
})
df
姓名 | 科目 | 成绩 | |
---|---|---|---|
0 | 张三 | 语文 | 91 |
1 | 张三 | 数学 | 80 |
2 | 张三 | 英语 | 100 |
3 | 李四 | 语文 | 80 |
4 | 李四 | 数学 | 100 |
5 | 李四 | 英语 | 96 |
# 长转宽:使用df.pivot以姓名为index,以各科目为columns,来统计各科成绩:
df.pivot(index = "姓名",columns="科目",values="成绩")
科目 | 数学 | 英语 | 语文 |
---|---|---|---|
姓名 | |||
张三 | 80 | 100 | 91 |
李四 | 100 | 96 | 80 |
pd.melt() 数据融合
df1 = pd.pivot(df,index="姓名",columns="科目",values="成绩").reset_index()
df1
科目 | 姓名 | 数学 | 英语 | 语文 |
---|---|---|---|---|
0 | 张三 | 80 | 100 | 91 |
1 | 李四 | 100 | 96 | 80 |
# 宽表变长表:使用pd.melt以姓名为标识变量的列id_var,以各科目为value_vars,来统计各科成绩
df1.melt(id_vars=["姓名"],value_vars=["语文","数学","英语"])
姓名 | 科目 | value | |
---|---|---|---|
0 | 张三 | 语文 | 91 |
1 | 李四 | 语文 | 80 |
2 | 张三 | 数学 | 80 |
3 | 李四 | 数学 | 100 |
4 | 张三 | 英语 | 100 |
5 | 李四 | 英语 | 96 |
pd.pivot_table() 数据透视表
import random
random.seed(1024)
df = pd.DataFrame({
"专业":np.repeat(["数学与应用数学","计算机","统计学"],4),
"班级":["1班","1班","2班","2班"]*3,
"科目":["高数","线代"]*6,
"平均分":[random.randint(60,100) for i in range(12)],
"及格人数":[random.randint(30,50) for i in range(12)]
})
df
专业 | 班级 | 科目 | 平均分 | 及格人数 | |
---|---|---|---|---|---|
0 | 数学与应用数学 | 1班 | 高数 | 85 | 33 |
1 | 数学与应用数学 | 1班 | 线代 | 62 | 43 |
2 | 数学与应用数学 | 2班 | 高数 | 95 | 50 |
3 | 数学与应用数学 | 2班 | 线代 | 87 | 40 |
4 | 计算机 | 1班 | 高数 | 61 | 50 |
5 | 计算机 | 1班 | 线代 | 72 | 44 |
6 | 计算机 | 2班 | 高数 | 100 | 45 |
7 | 计算机 | 2班 | 线代 | 60 | 32 |
8 | 统计学 | 1班 | 高数 | 74 | 49 |
9 | 统计学 | 1班 | 线代 | 66 | 36 |
10 | 统计学 | 2班 | 高数 | 75 | 46 |
11 | 统计学 | 2班 | 线代 | 99 | 39 |
各个专业对应科目的及格人数和平均分
pd.pivot_table(df,
index =["专业","科目"],
values = ["及格人数","平均分"],
aggfunc={"及格人数":np.sum,"平均分":"mean"}
)
及格人数 | 平均分 | ||
---|---|---|---|
专业 | 科目 | ||
数学与应用数学 | 线代 | 83 | 74.5 |
高数 | 83 | 90.0 | |
统计学 | 线代 | 75 | 82.5 |
高数 | 95 | 74.5 | |
计算机 | 线代 | 76 | 66.0 |
高数 | 95 | 80.5 |
补充说明
df.pivot_table()和df.pivot()都是Pandas中用于将长表转换为宽表的方法,但是它们在使用方式和功能上有一些区别。
1.使用方式:
df.pivot()方法接受三个参数:index、columns和values,分别指定新表的索引、列和值。
df.pivot_table()方法接受多个参数,其中最重要的是index、columns和values,用于指定新表的索引、列和值。此外,还可以使用aggfunc参数指定对重复值进行聚合操作的函数,默认为均值。
2.处理重复值:
df.pivot()方法在长表中存在重复值时会引发错误。因此,如果长表中存在重复值,就需要先进行去重操作,或者使用其他方法来处理重复值。
df.pivot_table()方法可以在长表中存在重复值的情况下进行透视操作,并可以使用aggfunc参数指定对重复值进行聚合操作的函数,默认为均值。
3.聚合操作:
df.pivot()方法不支持对重复值进行聚合操作,它只是简单地将长表中的数据转换为宽表。
df.pivot_table()方法支持对重复值进行聚合操作。可以使用aggfunc参数来指定聚合函数,例如求均值、求和、计数等。
总的来说,df.pivot()方法适用于长表中不存在重复值的情况,而df.pivot_table()方法适用于长表中存在重复值的情况,并且可以对重复值进行聚合操作。根据具体的数据结构和分析需求,选择合适的方法进行转换操作。
数据堆叠(Stack/Unstack)
import pandas as pd
import numpy as np
import random
df = pd.DataFrame({
"专业":np.repeat(["数学与应用数学","计算机","统计学","物理学"],6),
"班级":["1班","2班","3班"]*8,
"科目":["高数","线代"]*12,
"平均分":[random.randint(60,100) for i in range(24)],
"及格人数":[random.randint(30,50) for i in range(24)]
})
df2 = pd.pivot_table(df,index=["专业","科目"],values = ["及格人数","平均分"],
aggfunc={"及格人数":np.sum , "平均分":np.mean}
)
df2
及格人数 | 平均分 | ||
---|---|---|---|
专业 | 科目 | ||
数学与应用数学 | 线代 | 106 | 82.333333 |
高数 | 105 | 81.333333 | |
物理学 | 线代 | 132 | 84.666667 |
高数 | 119 | 87.666667 | |
统计学 | 线代 | 110 | 84.000000 |
高数 | 115 | 85.333333 | |
计算机 | 线代 | 121 | 85.333333 |
高数 | 109 | 84.666667 |
stacked = df2.stack()
专业 科目
数学与应用数学 线代 及格人数 106.000000
平均分 82.333333
高数 及格人数 105.000000
平均分 81.333333
物理学 线代 及格人数 132.000000
平均分 84.666667
高数 及格人数 119.000000
平均分 87.666667
统计学 线代 及格人数 110.000000
平均分 84.000000
高数 及格人数 115.000000
平均分 85.333333
计算机 线代 及格人数 121.000000
平均分 85.333333
高数 及格人数 109.000000
平均分 84.666667
dtype: float64
“压缩”后的DataFrame或Series(具有MultiIndex作为索引),stack()的逆操作是unstack(),默认情况下取消最后压缩的那个级别:堆叠stack(),顾名思义就是把透视结果到一起。接下来我们把透视后堆叠的数据一步步展开unstack():
stacked.unstack()
及格人数 | 平均分 | ||
---|---|---|---|
专业 | 科目 | ||
数学与应用数学 | 线代 | 106.0 | 82.333333 |
高数 | 105.0 | 81.333333 | |
物理学 | 线代 | 132.0 | 84.666667 |
高数 | 119.0 | 87.666667 | |
统计学 | 线代 | 110.0 | 84.000000 |
高数 | 115.0 | 85.333333 | |
计算机 | 线代 | 121.0 | 85.333333 |
高数 | 109.0 | 84.666667 |
stacked.unstack(level=1)
科目 | 线代 | 高数 | |
---|---|---|---|
专业 | |||
数学与应用数学 | 及格人数 | 106.000000 | 105.000000 |
平均分 | 82.333333 | 81.333333 | |
物理学 | 及格人数 | 132.000000 | 119.000000 |
平均分 | 84.666667 | 87.666667 | |
统计学 | 及格人数 | 110.000000 | 115.000000 |
平均分 | 84.000000 | 85.333333 | |
计算机 | 及格人数 | 121.000000 | 109.000000 |
平均分 | 85.333333 | 84.666667 |
stacked.unstack(level=0)
专业 | 数学与应用数学 | 物理学 | 统计学 | 计算机 | |
---|---|---|---|---|---|
科目 | |||||
线代 | 及格人数 | 106.000000 | 132.000000 | 110.000000 | 121.000000 |
平均分 | 82.333333 | 84.666667 | 84.000000 | 85.333333 | |
高数 | 及格人数 | 105.000000 | 119.000000 | 115.000000 | 109.000000 |
平均分 | 81.333333 | 87.666667 | 85.333333 | 84.666667 |
数据交叉表(pd.crosstab)
交叉表显示了每个变量的不同类别组合中观察到的频率或计数。通俗的说,就是根据不同列的数据统计了频数。
df = pd.DataFrame({
"High":["高","高","高","中","中","中","低","低","低","高","低"],
"Weight":["重","轻","中","中","轻","重","重","轻","中","重","轻"]
})
df
High | Weight | |
---|---|---|
0 | 高 | 重 |
1 | 高 | 轻 |
2 | 高 | 中 |
3 | 中 | 中 |
4 | 中 | 轻 |
5 | 中 | 重 |
6 | 低 | 重 |
7 | 低 | 轻 |
8 | 低 | 中 |
9 | 高 | 重 |
10 | 低 | 轻 |
pd.crosstab(df["High"],df["Weight"])
Weight | 中 | 轻 | 重 |
---|---|---|---|
High | |||
中 | 1 | 1 | 1 |
低 | 1 | 2 | 1 |
高 | 1 | 1 | 2 |
双层crosstab
df = pd.DataFrame({
"High":["高","高","高","中","中","中","低","低","低","高","低"],
"Weight":["重","轻","中","中","轻","重","重","轻","中","重","轻"],
"Size":["大","中","小","中","中","大","中","小","小","大","小"]
})
df
High | Weight | Size | |
---|---|---|---|
0 | 高 | 重 | 大 |
1 | 高 | 轻 | 中 |
2 | 高 | 中 | 小 |
3 | 中 | 中 | 中 |
4 | 中 | 轻 | 中 |
5 | 中 | 重 | 大 |
6 | 低 | 重 | 中 |
7 | 低 | 轻 | 小 |
8 | 低 | 中 | 小 |
9 | 高 | 重 | 大 |
10 | 低 | 轻 | 小 |
pd.crosstab(df["High"],[df["Size"],df["Weight"]],rownames=["High"],colnames=["Size","Weight"])
Size | 中 | 大 | 小 | |||
---|---|---|---|---|---|---|
Weight | 中 | 轻 | 重 | 重 | 中 | 轻 |
High | ||||||
中 | 1 | 1 | 0 | 1 | 0 | 0 |
低 | 0 | 0 | 1 | 0 | 1 | 2 |
高 | 0 | 1 | 0 | 2 | 1 | 0 |
另一种 宽表转长表 pd.wide_to_long()
np.random.seed(123)
df = pd.DataFrame({
"A1970":{0:"a",1:"b",2:"c"},
"A1980":{0:"d",1:"e",2:"f"},
"B1970":{0:2.5,1:1.2,2:0.7},
"B1980":{0:3.2,1:1.3,2:0.1},
"X":dict(zip(range(3),np.random.randn(3)))
})
df["id"] = df.index
df
A1970 | A1980 | B1970 | B1980 | X | id | |
---|---|---|---|---|---|---|
0 | a | d | 2.5 | 3.2 | -1.085631 | 0 |
1 | b | e | 1.2 | 1.3 | 0.997345 | 1 |
2 | c | f | 0.7 | 0.1 | 0.282978 | 2 |
把id列用作标识列
pd.wide_to_long(df,["A","B"],i="id",j="year")
X | A | B | ||
---|---|---|---|---|
id | year | |||
0 | 1970 | -1.085631 | a | 2.5 |
1 | 1970 | 0.997345 | b | 1.2 |
2 | 1970 | 0.282978 | c | 0.7 |
0 | 1980 | -1.085631 | d | 3.2 |
1 | 1980 | 0.997345 | e | 1.3 |
2 | 1980 | 0.282978 | f | 0.1 |
df = pd.DataFrame({
"famid":[1,1,1,2,2,2,3,3,3],
"birth":[1,2,3,1,2,3,1,2,3],
"ht1":[2.8,2.9,2.2,2,1.8,1.9,2.2,2.3,2.1],
"ht2":[3.4,3.8,2.9,3.2,2.8,2.4,3.3,3.4,2.9]
})
df
famid | birth | ht1 | ht2 | |
---|---|---|---|---|
0 | 1 | 1 | 2.8 | 3.4 |
1 | 1 | 2 | 2.9 | 3.8 |
2 | 1 | 3 | 2.2 | 2.9 |
3 | 2 | 1 | 2.0 | 3.2 |
4 | 2 | 2 | 1.8 | 2.8 |
5 | 2 | 3 | 1.9 | 2.4 |
6 | 3 | 1 | 2.2 | 3.3 |
7 | 3 | 2 | 2.3 | 3.4 |
8 | 3 | 3 | 2.1 | 2.9 |
把 famid,birth两列作为标识列
l = pd.wide_to_long(df,stubnames="ht",i = ["famid","birth"],j="age")
l
ht | |||
---|---|---|---|
famid | birth | age | |
1 | 1 | 1 | 2.8 |
2 | 3.4 | ||
2 | 1 | 2.9 | |
2 | 3.8 | ||
3 | 1 | 2.2 | |
2 | 2.9 | ||
2 | 1 | 1 | 2.0 |
2 | 3.2 | ||
2 | 1 | 1.8 | |
2 | 2.8 | ||
3 | 1 | 1.9 | |
2 | 2.4 | ||
3 | 1 | 1 | 2.2 |
2 | 3.3 | ||
2 | 1 | 2.3 | |
2 | 3.4 | ||
3 | 1 | 2.1 | |
2 | 2.9 |
pandas 文本数据
import pandas as pd
1.cat()拼接字符串
d = pd.DataFrame(["a","b","c"],columns=['A'])
d
A | |
---|---|
0 | a |
1 | b |
2 | c |
将某列元素拼接一列特定字符串
d["A"].str.cat(["A","B","C"],sep=",")
0 a,A
1 b,B
2 c,C
Name: A, dtype: object
将某列的元素合并为一个字符串
d["A"].str.cat(sep=",")
'a,b,c'
2.split()切分字符串
import numpy as np
import pandas as pd
d = pd.DataFrame(["a_b_c","c_d_e",np.nan,"f_g_h"],columns=["A"])
d
A | |
---|---|
0 | a_b_c |
1 | c_d_e |
2 | NaN |
3 | f_g_h |
将某列的字符串元素进行切分
d["A"].str.split("_")
0 [a, b, c]
1 [c, d, e]
2 NaN
3 [f, g, h]
Name: A, dtype: object
3.get()获取指定位置的字符串
d = pd.DataFrame(["a_b_c","c_d_e",np.nan,"f_g_h"],columns=["A"])
d
A | |
---|---|
0 | a_b_c |
1 | c_d_e |
2 | NaN |
3 | f_g_h |
d["A"].get(3)
'f_g_h'
4.join()对每个字符都用给定的字符串拼接起来(不常用)
d = pd.DataFrame(["a_b_c","c_d_e",np.nan,"f_g_h"],columns=["A"])
d
A | |
---|---|
0 | a_b_c |
1 | c_d_e |
2 | NaN |
3 | f_g_h |
d["A"].str.join("!")
0 a!_!b!_!c
1 c!_!d!_!e
2 NaN
3 f!_!g!_!h
Name: A, dtype: object
5.contains()是否包含表达式(很常用)
d["A"].str.contains("d")
0 False
1 True
2 NaN
3 False
Name: A, dtype: object
d.fillna("0")[d.fillna("0")["A"].str.contains("d")]
A | |
---|---|
1 | c_d_e |
表示或的关系用"A|B",表示且用"A.B"|"B.A"
d.fillna("0")[d.fillna("0")["A"].str.contains("c|d")]
A | |
---|---|
0 | a_b_c |
1 | c_d_e |
6. replace()替换
d["A"].str.replace("_",",")
0 a,b,c
1 c,d,e
2 NaN
3 f,g,h
Name: A, dtype: object
7.repeat()重复
d["A"].str.repeat(3)
0 a_b_ca_b_ca_b_c
1 c_d_ec_d_ec_d_e
2 NaN
3 f_g_hf_g_hf_g_h
Name: A, dtype: object
8. pad()左右补齐
d["A"].str.pad(10,fillchar="*")
0 *****a_b_c
1 *****c_d_e
2 NaN
3 *****f_g_h
Name: A, dtype: object
d["A"].str.pad(10,side="right",fillchar="&")
0 a_b_c&&&&&
1 c_d_e&&&&&
2 NaN
3 f_g_h&&&&&
Name: A, dtype: object
9.center()中间补齐
d["A"].str.center(10,fillchar="?")
0 ??a_b_c???
1 ??c_d_e???
2 NaN
3 ??f_g_h???
Name: A, dtype: object
10.ljust()右边补齐
d["A"].str.ljust(10,fillchar="?")
0 a_b_c?????
1 c_d_e?????
2 NaN
3 f_g_h?????
Name: A, dtype: object
11.rjsut()左边补齐
d["A"].str.rjust(10,fillchar="?")
0 ?????a_b_c
1 ?????c_d_e
2 NaN
3 ?????f_g_h
Name: A, dtype: object
12.zfill()左边补0
d["A"].str.zfill(10)
0 00000a_b_c
1 00000c_d_e
2 NaN
3 00000f_g_h
Name: A, dtype: object
13.wrap()在指定的位置加回车符号
d["A"].str.wrap(3)
0 a_b\n_c
1 c_d\n_e
2 NaN
3 f_g\n_h
Name: A, dtype: object
14.slice()按给定点的开始结束位置切割字符串
d["A"].str.slice(1,3)
0 _b
1 _d
2 NaN
3 _g
Name: A, dtype: object
15.slice_repalce()使用给定的字符串,替换指定的位置的字符
d["A"].str.slice_replace(1,3,"?")
0 a?_c
1 c?_e
2 NaN
3 f?_h
Name: A, dtype: object
d["A"].str.slice_replace(0,3,"?")
0 ?_c
1 ?_e
2 NaN
3 ?_h
Name: A, dtype: object
16.count()计算给定单词出现的次数
d["A"].str.count("b")
0 1.0
1 0.0
2 NaN
3 0.0
Name: A, dtype: float64
17.startswith()判断是否以给定的字符串开头
d["A"].str.startswith("a")
0 True
1 False
2 NaN
3 False
Name: A, dtype: object
18.endswith()判断是否以给定的字符串结束
d["A"].str.endswith("e")
0 False
1 True
2 NaN
3 False
Name: A, dtype: object
19.findall()查找所有符合正则表达式的字符,以数组形式返回
d["A"].str.findall("[a-z]")
0 [a, b, c]
1 [c, d, e]
2 NaN
3 [f, g, h]
Name: A, dtype: object
20.match()检测是否全部匹配给定的字符串或表达式
d["A"].str.match("[d-z]")
0 False
1 False
2 NaN
3 True
Name: A, dtype: object
21.extact()抽取匹配的字符串出来,注意要加上括号,把你需要抽取的东西标注上
d["A"].str.extract("([d-z])")
0 | |
---|---|
0 | NaN |
1 | d |
2 | NaN |
3 | f |
22.len()计算字符串的长度
d["A"].str.len()
0 5.0
1 5.0
2 NaN
3 5.0
Name: A, dtype: float64
23.strip()去除前后的空白字符
df = pd.DataFrame(["a_b ","d_e ",np.nan,"f_g "],columns=["B"])
df
B | |
---|---|
0 | a_b |
1 | d_e |
2 | NaN |
3 | f_g |
df["B"].str.strip()
0 a_b
1 d_e
2 NaN
3 f_g
Name: B, dtype: object
24.rstrip()去除后面的空白字符
df["B"].str.rstrip()
0 a_b
1 d_e
2 NaN
3 f_g
Name: B, dtype: object
25.lstrip()去除前面的空白字符
df["B"].str.lstrip()
0 a_b
1 d_e
2 NaN
3 f_g
Name: B, dtype: object
26.partition()把字符串数组切割成为DataFrame,注意切割只是切割称为三部分,分隔符前,分隔符,分隔符后
d["A"].str.partition("_")
0 | 1 | 2 | |
---|---|---|---|
0 | a | _ | b_c |
1 | c | _ | d_e |
2 | NaN | NaN | NaN |
3 | f | _ | g_h |
27.rpartition()从右切起
d["A"].str.rpartition("_")
0 | 1 | 2 | |
---|---|---|---|
0 | a_b | _ | c |
1 | c_d | _ | e |
2 | NaN | NaN | NaN |
3 | f_g | _ | h |
28.lower()全部小写
d["A"].str.lower()
0 a_b_c
1 c_d_e
2 NaN
3 f_g_h
Name: A, dtype: object
29.upper()全部大写
d["A"].str.upper()
0 A_B_C
1 C_D_E
2 NaN
3 F_G_H
Name: A, dtype: object
30.find()从左边开始,查找给定字符串的所在位置
d["A"].str.find("d")
0 -1.0
1 2.0
2 NaN
3 -1.0
Name: A, dtype: float64
31.rfind()从右边开始,查找给定字符串的所在位置
d["A"].str.rfind("c")
0 4.0
1 0.0
2 NaN
3 -1.0
Name: A, dtype: float64
32.index()查找给定字符串的位置,注意,如果不存在这个字符串,那么会报错
d["A"].str.index("_")
0 1.0
1 1.0
2 NaN
3 1.0
Name: A, dtype: float64
33.rindex()从右边开始查找,给定字符串的位置
d["A"].str.rindex("_")
0 3.0
1 3.0
2 NaN
3 3.0
Name: A, dtype: float64
d["A"].str.rindex("_")
0 3.0
1 3.0
2 NaN
3 3.0
Name: A, dtype: float64
34.capitalize()首字符大写
d["A"].str.capitalize()
0 A_b_c
1 C_d_e
2 NaN
3 F_g_h
Name: A, dtype: object
35.swapcase() 大小写互换
d["A"].str.capitalize().str.swapcase()
0 a_B_C
1 c_D_E
2 NaN
3 f_G_H
Name: A, dtype: object
36.isalnum()是否全部是数字和字母组成
d["A"].str.isalnum()
0 False
1 False
2 NaN
3 False
Name: A, dtype: object
37.isalpha()是否全部是字母
d["A"].str.isalpha()
0 False
1 False
2 NaN
3 False
Name: A, dtype: object
38.isdigit()是否全部都是数字
d["A"].str.isdigit()
0 False
1 False
2 NaN
3 False
Name: A, dtype: object
39.isspace()是否为空格
d["A"].str.isspace()
0 False
1 False
2 NaN
3 False
Name: A, dtype: object
40.islower()是否全部小写
d["A"].str.islower()
0 True
1 True
2 NaN
3 True
Name: A, dtype: object
41.isupper()是否全部大写
d["A"].str.isupper()
0 False
1 False
2 NaN
3 False
Name: A, dtype: object
42.istitle()是否只有首字母为大写,其他字母为小写
d["A"].str.istitle()
0 False
1 False
2 NaN
3 False
Name: A, dtype: object
43.isnumeric()是否是数字
d["A"].str.isnumeric()
0 False
1 False
2 NaN
3 False
Name: A, dtype: object
44.isdecimal()是否全部是数字
d["A"].str.isdecimal()
0 False
1 False
2 NaN
3 False
Name: A, dtype: object
pandas 时序数据
在Pandas中,时间序列(Time Series)是一种特殊的数据类型,用于处理时间相关的数据。Pandas提供了丰富的功能和方法,方便对时间序列数据进行处理和分析。下面是一些针对时间序列的常用操作:
创建时间序列数据
方式1:使用to_datetime创建时间序列:直接传入列表即可。
import pandas as pd
# 将列表转换为时间戳
date_range = pd.to_datetime(["2024-01-01","2024-01-02","2024-01-03"])
date_range
DatetimeIndex(['2024-01-01', '2024-01-02', '2024-01-03'], dtype='datetime64[ns]', freq=None)
方式2:使用pd.date_range()创建一段连续的时间范围:使用指定参数即可
date_range = pd.date_range(start = "2024-01-01",end = "2024-12-31",freq = "D")
date_range
DatetimeIndex(['2024-01-01', '2024-01-02', '2024-01-03', '2024-01-04',
'2024-01-05', '2024-01-06', '2024-01-07', '2024-01-08',
'2024-01-09', '2024-01-10',
...
'2024-12-22', '2024-12-23', '2024-12-24', '2024-12-25',
'2024-12-26', '2024-12-27', '2024-12-28', '2024-12-29',
'2024-12-30', '2024-12-31'],
dtype='datetime64[ns]', length=366, freq='D')
其中,start 是起始日期,end是结束日期,freq是频率,这里设置为D表示每天。
方式3:使用Timestamp()函数创建一个特定的时间戳:使用指定参数即可。
timestamp = pd.Timestamp(year =2024,month =1,day =1,hour=12,minute=12,second =45)
timestamp
Timestamp('2024-01-01 12:12:45')
方式4:使用datetime模块创建时间戳:使用指定参数即可
from datetime import datetime
timestamp = datetime(2024,1,1,12,30,45)
timestamp
datetime.datetime(2024, 1, 1, 12, 30, 45)
print(timestamp)
2024-01-01 12:30:45
时长数据计算
计算一下两个时间数据之差
# 创建两个固定时间
start_time = pd.Timestamp("2024-01-01 12:00:00")
end_time = pd.Timestamp("2024-01-02 14:30:00")
print(start_time)
print(end_time)
2024-01-01 12:00:00
2024-01-02 14:30:00
# 计算时间差
time_diff = end_time- start_time
time_diff
Timedelta('1 days 02:30:00')
一个固定时间加上pd.Timedelta类型的时间差
pd.Timestamp("2024-01-02 14:30:00") + pd.Timedelta("1 days 02:30:00")
Timestamp('2024-01-03 17:00:00')
时间索引
接下来,我们看看日期做索引的情况
将日期作为索引创建时间序列
data = [1,2,3,4,5]
dates = pd.date_range(start = "2024-01-01",periods=5,freq="D")
ts = pd.Series(data,index=dates)
ts
2024-01-01 1
2024-01-02 2
2024-01-03 3
2024-01-04 4
2024-01-05 5
Freq: D, dtype: int64
其中,periods是时间序列的长度,freq是频率,这里设置为D表示每天。
时间序列的索引和切片:使用日期进行索引:
ts["2024-01-01"]
1
使用日期范围进行切片
ts["2024-01-01":"2024-01-05"]
2024-01-01 1
2024-01-02 2
2024-01-03 3
2024-01-04 4
2024-01-05 5
Freq: D, dtype: int64
也可以使用切片操作对数据进行访问
ts[1:4]
2024-01-02 2
2024-01-03 3
2024-01-04 4
Freq: D, dtype: int64
时间序列的重采样:将时间序列从高频率转换为低频率:
ts.resample("W").mean()
2024-01-07 3.0
Freq: W-SUN, dtype: float64
其中,W表示按周进行重采样,mean()表示计算每周的平均值。
时间序列的滚动计算:计算滚动平均值:
ts.rolling(window = 3).mean()
2024-01-01 NaN
2024-01-02 NaN
2024-01-03 2.0
2024-01-04 3.0
2024-01-05 4.0
Freq: D, dtype: float64
其中,window = 3 表示窗口大小为3,即计算每3个数据的平均值。
时间序列的时间偏移:将时间序列向前或向后移动:
ts.shift(1)
2024-01-01 NaN
2024-01-02 1.0
2024-01-03 2.0
2024-01-04 3.0
2024-01-05 4.0
Freq: D, dtype: float64
其中,1 表示向后移动1个时间单位。
时间访问器dt
在Pandas中,可以使用dt访问器来访问时间戳或时间序列中的各个时间部分,例如年、月、日、小时、分钟、秒等。通过使用dt访问器,你可以方便地提取和操作时间信息。
下面是一些常用的dt访问器的示例:
#创建一个时间序列
timestamps = pd.Series(pd.date_range("2024-01-01",periods=5,freq = "D"))
timestamps
0 2024-01-01
1 2024-01-02
2 2024-01-03
3 2024-01-04
4 2024-01-05
dtype: datetime64[ns]
# 提取年份
year = timestamps.dt.year
year
0 2024
1 2024
2 2024
3 2024
4 2024
dtype: int64
# 提取月份
month = timestamps.dt.month
month
0 1
1 1
2 1
3 1
4 1
dtype: int64
# 提取日期
day = timestamps.dt.day
day
0 1
1 2
2 3
3 4
4 5
dtype: int64
# 提取小时
hour = timestamps.dt.hour
hour
0 0
1 0
2 0
3 0
4 0
dtype: int64
# 提取分钟
minute = timestamps.dt.minute
minute
0 0
1 0
2 0
3 0
4 0
dtype: int64
# 提取秒数
second = timestamps.dt.second
second
0 0
1 0
2 0
3 0
4 0
dtype: int64
# 获取季度
quarter = timestamps.dt.quarter
quarter
0 1
1 1
2 1
3 1
4 1
dtype: int64
# 获取周数
week = timestamps.dt.isocalendar().week
week
0 1
1 1
2 1
3 1
4 1
Name: week, dtype: UInt32
# 获取星期几的名称
day_name = timestamps.dt.day_name()
day_name
0 Monday
1 Tuesday
2 Wednesday
3 Thursday
4 Friday
dtype: object
# 获取该日期是一年中的第几天
day_of_year = timestamps.dt.dayofyear
day_of_year
0 1
1 2
2 3
3 4
4 5
dtype: int64
# 获取该日期是一周中的第几天(星期一为1,星期日为7)
day_of_week = timestamps.dt.dayofweek +1
day_of_week
0 1
1 2
2 3
3 4
4 5
dtype: int64
# 获取该日期是一个月中的第几天
day_of_month = timestamps.dt.day
day_of_month
0 1
1 2
2 3
3 4
4 5
dtype: int64
# 获取该日期所在月份的最后一天
end_of_month = timestamps.dt.daysinmonth
end_of_month
0 31
1 31
2 31
3 31
4 31
dtype: int64
时长转化
import numpy as np
# 创建时间戳序列
ts = pd.Series(pd.to_timedelta(np.arange(10),unit="m"))
ts
0 0 days 00:00:00
1 0 days 00:01:00
2 0 days 00:02:00
3 0 days 00:03:00
4 0 days 00:04:00
5 0 days 00:05:00
6 0 days 00:06:00
7 0 days 00:07:00
8 0 days 00:08:00
9 0 days 00:09:00
dtype: timedelta64[ns]
# 提取时间戳中的秒数
seconds = ts.dt.seconds
seconds
0 0
1 60
2 120
3 180
4 240
5 300
6 360
7 420
8 480
9 540
dtype: int64
seconds = ts.dt.to_pytimedelta()
seconds
array([datetime.timedelta(0), datetime.timedelta(seconds=60),
datetime.timedelta(seconds=120), datetime.timedelta(seconds=180),
datetime.timedelta(seconds=240), datetime.timedelta(seconds=300),
datetime.timedelta(seconds=360), datetime.timedelta(seconds=420),
datetime.timedelta(seconds=480), datetime.timedelta(seconds=540)],
dtype=object)
print(seconds)
[datetime.timedelta(0) datetime.timedelta(seconds=60)
datetime.timedelta(seconds=120) datetime.timedelta(seconds=180)
datetime.timedelta(seconds=240) datetime.timedelta(seconds=300)
datetime.timedelta(seconds=360) datetime.timedelta(seconds=420)
datetime.timedelta(seconds=480) datetime.timedelta(seconds=540)]
Pandas窗口数据
pandas提供了窗口函数(Window Functions)用于在数据上执行滑动窗口操作,可以对数据进行滚动计算、滑动统计等操作。
下面是一些常用的窗口函数:
滚动计算函数:
移动平均值(Moving Average)
import pandas as pd
data = {"column":[1,2,3,4,5,6,7,8,9,20]}
df = pd.DataFrame(data)
df
column | |
---|---|
0 | 1 |
1 | 2 |
2 | 3 |
3 | 4 |
4 | 5 |
5 | 6 |
6 | 7 |
7 | 8 |
8 | 9 |
9 | 20 |
df["MA"] = df["column"].rolling(window=3).mean()
df
column | MA | |
---|---|---|
0 | 1 | NaN |
1 | 2 | NaN |
2 | 3 | 2.000000 |
3 | 4 | 3.000000 |
4 | 5 | 4.000000 |
5 | 6 | 5.000000 |
6 | 7 | 6.000000 |
7 | 8 | 7.000000 |
8 | 9 | 8.000000 |
9 | 20 | 12.333333 |
其中,window = 3表示窗口大小为3,即计算每3个数据的平均值。
滚动求和(Rolling Sum):
df["Sum"] = df["column"].rolling(window = 5).sum()
df
column | MA | Sum | |
---|---|---|---|
0 | 1 | NaN | NaN |
1 | 2 | NaN | NaN |
2 | 3 | 2.000000 | NaN |
3 | 4 | 3.000000 | NaN |
4 | 5 | 4.000000 | 15.0 |
5 | 6 | 5.000000 | 20.0 |
6 | 7 | 6.000000 | 25.0 |
7 | 8 | 7.000000 | 30.0 |
8 | 9 | 8.000000 | 35.0 |
9 | 20 | 12.333333 | 50.0 |
其中,window=5 表示窗口大小为5,即计算每5个数据的和。
滑动统计函数:滑动取最大值
df["Max"] = df["column"].rolling(window=7).max()
df
column | MA | Sum | Max | |
---|---|---|---|---|
0 | 1 | NaN | NaN | NaN |
1 | 2 | NaN | NaN | NaN |
2 | 3 | 2.000000 | NaN | NaN |
3 | 4 | 3.000000 | NaN | NaN |
4 | 5 | 4.000000 | 15.0 | NaN |
5 | 6 | 5.000000 | 20.0 | NaN |
6 | 7 | 6.000000 | 25.0 | 7.0 |
7 | 8 | 7.000000 | 30.0 | 8.0 |
8 | 9 | 8.000000 | 35.0 | 9.0 |
9 | 20 | 12.333333 | 50.0 | 20.0 |
其中,window=7表示窗口大小为7,即计算每7个数据的最大值。
滑动最小值(Rolling Minimum)
df["Min"] = df["column"].rolling(window=7).min()
df
column | MA | Sum | Max | Min | |
---|---|---|---|---|---|
0 | 1 | NaN | NaN | NaN | NaN |
1 | 2 | NaN | NaN | NaN | NaN |
2 | 3 | 2.000000 | NaN | NaN | NaN |
3 | 4 | 3.000000 | NaN | NaN | NaN |
4 | 5 | 4.000000 | 15.0 | NaN | NaN |
5 | 6 | 5.000000 | 20.0 | NaN | NaN |
6 | 7 | 6.000000 | 25.0 | 7.0 | 1.0 |
7 | 8 | 7.000000 | 30.0 | 8.0 | 2.0 |
8 | 9 | 8.000000 | 35.0 | 9.0 | 3.0 |
9 | 20 | 12.333333 | 50.0 | 20.0 | 4.0 |
其中,window = 7 表示窗口大小为7,即计算每7个数据的最小值。
滑动标准差(Rolling Standard Deviation)
df["Std"] = df["column"].rolling(window=5).std()
df
column | MA | Sum | Max | Min | Std | |
---|---|---|---|---|---|---|
0 | 1 | NaN | NaN | NaN | NaN | NaN |
1 | 2 | NaN | NaN | NaN | NaN | NaN |
2 | 3 | 2.000000 | NaN | NaN | NaN | NaN |
3 | 4 | 3.000000 | NaN | NaN | NaN | NaN |
4 | 5 | 4.000000 | 15.0 | NaN | NaN | 1.581139 |
5 | 6 | 5.000000 | 20.0 | NaN | NaN | 1.581139 |
6 | 7 | 6.000000 | 25.0 | 7.0 | 1.0 | 1.581139 |
7 | 8 | 7.000000 | 30.0 | 8.0 | 2.0 | 1.581139 |
8 | 9 | 8.000000 | 35.0 | 9.0 | 3.0 | 1.581139 |
9 | 20 | 12.333333 | 50.0 | 20.0 | 4.0 | 5.700877 |
其中,window = 5表示窗口大小为5,即计算每5个数据的标准差。
自定义窗口函数:可以使用rolling().apply()方法来应用自定义的窗口函数:
def custom_function(data):
# 自定义的窗口函数逻辑
return max(data)-min(data)
df["Result"] = df["column"].rolling(window=3).apply(custom_function)
df
column | MA | Sum | Max | Min | Std | Result | |
---|---|---|---|---|---|---|---|
0 | 1 | NaN | NaN | NaN | NaN | NaN | NaN |
1 | 2 | NaN | NaN | NaN | NaN | NaN | NaN |
2 | 3 | 2.000000 | NaN | NaN | NaN | NaN | 2.0 |
3 | 4 | 3.000000 | NaN | NaN | NaN | NaN | 2.0 |
4 | 5 | 4.000000 | 15.0 | NaN | NaN | 1.581139 | 2.0 |
5 | 6 | 5.000000 | 20.0 | NaN | NaN | 1.581139 | 2.0 |
6 | 7 | 6.000000 | 25.0 | 7.0 | 1.0 | 1.581139 | 2.0 |
7 | 8 | 7.000000 | 30.0 | 8.0 | 2.0 | 1.581139 | 2.0 |
8 | 9 | 8.000000 | 35.0 | 9.0 | 3.0 | 1.581139 | 2.0 |
9 | 20 | 12.333333 | 50.0 | 20.0 | 4.0 | 5.700877 | 12.0 |
其中,custom_function是自定义的窗口函数,data是窗口中的数据,result是窗口函数的计算结果。
以上是Pandas窗口函数的一些常用操作和示例代码。需要主意的是,在使用窗口函数时,需要根据实际需求选择合适的窗口大小和窗口函数,并确保数据的顺序和窗口的大小的一致性。
Pandas 数据读写
pandas提供了多种的读取数据的方法,包括读取CSV,Excel,SQL数据库等。
CSV
写出csv文件
import pandas as pd
import numpy as np
data = np.random.rand(10,10) # 生成一个10行10列的随机数矩阵
columns = ["col" + str(i) for i in range(10)] # 列名为col0,col1,...,col9
df = pd.DataFrame(data,columns=columns)
df
col0 | col1 | col2 | col3 | col4 | col5 | col6 | col7 | col8 | col9 | |
---|---|---|---|---|---|---|---|---|---|---|
0 | 0.352091 | 0.178000 | 0.461874 | 0.385439 | 0.529171 | 0.166393 | 0.638849 | 0.909912 | 0.377631 | 0.384622 |
1 | 0.966381 | 0.427036 | 0.104144 | 0.824068 | 0.683486 | 0.402117 | 0.728079 | 0.647733 | 0.371709 | 0.749912 |
2 | 0.261888 | 0.506005 | 0.136369 | 0.835917 | 0.257780 | 0.489983 | 0.702113 | 0.794416 | 0.512957 | 0.115354 |
3 | 0.030669 | 0.653736 | 0.956061 | 0.723672 | 0.727005 | 0.606782 | 0.904017 | 0.873490 | 0.199487 | 0.718366 |
4 | 0.165038 | 0.963646 | 0.445542 | 0.934715 | 0.602317 | 0.512891 | 0.905490 | 0.258992 | 0.222218 | 0.632665 |
5 | 0.181801 | 0.307962 | 0.215758 | 0.275811 | 0.345049 | 0.901163 | 0.051008 | 0.521878 | 0.562531 | 0.964238 |
6 | 0.030284 | 0.813831 | 0.924085 | 0.755061 | 0.938092 | 0.680196 | 0.797757 | 0.203038 | 0.242113 | 0.130894 |
7 | 0.345255 | 0.650669 | 0.305902 | 0.461865 | 0.195045 | 0.791088 | 0.836632 | 0.737000 | 0.562482 | 0.177634 |
8 | 0.339321 | 0.991851 | 0.822393 | 0.856865 | 0.636982 | 0.936672 | 0.989712 | 0.796993 | 0.942633 | 0.277127 |
9 | 0.205519 | 0.544493 | 0.676010 | 0.132137 | 0.052513 | 0.154118 | 0.638838 | 0.882306 | 0.421493 | 0.985456 |
df.to_csv("./output/foo.csv") # 请注意需要在你的代码文件夹目录下创建一个output 文件夹才能写入
读入刚刚写出的文件
pd.read_csv("./output/foo.csv")
Unnamed: 0 | col0 | col1 | col2 | col3 | col4 | col5 | col6 | col7 | col8 | col9 | |
---|---|---|---|---|---|---|---|---|---|---|---|
0 | 0 | 0.352091 | 0.178000 | 0.461874 | 0.385439 | 0.529171 | 0.166393 | 0.638849 | 0.909912 | 0.377631 | 0.384622 |
1 | 1 | 0.966381 | 0.427036 | 0.104144 | 0.824068 | 0.683486 | 0.402117 | 0.728079 | 0.647733 | 0.371709 | 0.749912 |
2 | 2 | 0.261888 | 0.506005 | 0.136369 | 0.835917 | 0.257780 | 0.489983 | 0.702113 | 0.794416 | 0.512957 | 0.115354 |
3 | 3 | 0.030669 | 0.653736 | 0.956061 | 0.723672 | 0.727005 | 0.606782 | 0.904017 | 0.873490 | 0.199487 | 0.718366 |
4 | 4 | 0.165038 | 0.963646 | 0.445542 | 0.934715 | 0.602317 | 0.512891 | 0.905490 | 0.258992 | 0.222218 | 0.632665 |
5 | 5 | 0.181801 | 0.307962 | 0.215758 | 0.275811 | 0.345049 | 0.901163 | 0.051008 | 0.521878 | 0.562531 | 0.964238 |
6 | 6 | 0.030284 | 0.813831 | 0.924085 | 0.755061 | 0.938092 | 0.680196 | 0.797757 | 0.203038 | 0.242113 | 0.130894 |
7 | 7 | 0.345255 | 0.650669 | 0.305902 | 0.461865 | 0.195045 | 0.791088 | 0.836632 | 0.737000 | 0.562482 | 0.177634 |
8 | 8 | 0.339321 | 0.991851 | 0.822393 | 0.856865 | 0.636982 | 0.936672 | 0.989712 | 0.796993 | 0.942633 | 0.277127 |
9 | 9 | 0.205519 | 0.544493 | 0.676010 | 0.132137 | 0.052513 | 0.154118 | 0.638838 | 0.882306 | 0.421493 | 0.985456 |
Excel
写出excel文件
df.to_excel("./output/foo.xlsx",sheet_name="Sheet1",index=None)
读取excel 文件
pd.read_excel("./output/foo.xlsx","Sheet1",index_col=None,na_values=["NA"])
col0 | col1 | col2 | col3 | col4 | col5 | col6 | col7 | col8 | col9 | |
---|---|---|---|---|---|---|---|---|---|---|
0 | 0.352091 | 0.178000 | 0.461874 | 0.385439 | 0.529171 | 0.166393 | 0.638849 | 0.909912 | 0.377631 | 0.384622 |
1 | 0.966381 | 0.427036 | 0.104144 | 0.824068 | 0.683486 | 0.402117 | 0.728079 | 0.647733 | 0.371709 | 0.749912 |
2 | 0.261888 | 0.506005 | 0.136369 | 0.835917 | 0.257780 | 0.489983 | 0.702113 | 0.794416 | 0.512957 | 0.115354 |
3 | 0.030669 | 0.653736 | 0.956061 | 0.723672 | 0.727005 | 0.606782 | 0.904017 | 0.873490 | 0.199487 | 0.718366 |
4 | 0.165038 | 0.963646 | 0.445542 | 0.934715 | 0.602317 | 0.512891 | 0.905490 | 0.258992 | 0.222218 | 0.632665 |
5 | 0.181801 | 0.307962 | 0.215758 | 0.275811 | 0.345049 | 0.901163 | 0.051008 | 0.521878 | 0.562531 | 0.964238 |
6 | 0.030284 | 0.813831 | 0.924085 | 0.755061 | 0.938092 | 0.680196 | 0.797757 | 0.203038 | 0.242113 | 0.130894 |
7 | 0.345255 | 0.650669 | 0.305902 | 0.461865 | 0.195045 | 0.791088 | 0.836632 | 0.737000 | 0.562482 | 0.177634 |
8 | 0.339321 | 0.991851 | 0.822393 | 0.856865 | 0.636982 | 0.936672 | 0.989712 | 0.796993 | 0.942633 | 0.277127 |
9 | 0.205519 | 0.544493 | 0.676010 | 0.132137 | 0.052513 | 0.154118 | 0.638838 | 0.882306 | 0.421493 | 0.985456 |
HDF
写出hdf文件
df.to_hdf("./output/foo.h5","df")
---------------------------------------------------------------------------
ImportError Traceback (most recent call last)
D:\AppGallery\Software\Anaconda3\lib\site-packages\pandas\compat\_optional.py in import_optional_dependency(name, extra, errors, min_version)
137 try:
--> 138 module = importlib.import_module(name)
139 except ImportError:
D:\AppGallery\Software\Anaconda3\lib\importlib\__init__.py in import_module(name, package)
126 level += 1
--> 127 return _bootstrap._gcd_import(name[level:], package, level)
128
D:\AppGallery\Software\Anaconda3\lib\importlib\_bootstrap.py in _gcd_import(name, package, level)
D:\AppGallery\Software\Anaconda3\lib\importlib\_bootstrap.py in _find_and_load(name, import_)
D:\AppGallery\Software\Anaconda3\lib\importlib\_bootstrap.py in _find_and_load_unlocked(name, import_)
D:\AppGallery\Software\Anaconda3\lib\importlib\_bootstrap.py in _load_unlocked(spec)
D:\AppGallery\Software\Anaconda3\lib\importlib\_bootstrap_external.py in exec_module(self, module)
D:\AppGallery\Software\Anaconda3\lib\importlib\_bootstrap.py in _call_with_frames_removed(f, *args, **kwds)
D:\AppGallery\Software\Anaconda3\lib\site-packages\tables\__init__.py in <module>
23 # Necessary imports to get versions stored on the cython extension
---> 24 from .utilsextension import (
25 get_pytables_version, get_hdf5_version, blosc_compressor_list,
tables/utilsextension.pyx in init tables.utilsextension()
ImportError: cannot import name typeDict
During handling of the above exception, another exception occurred:
ImportError Traceback (most recent call last)
~\AppData\Local\Temp\ipykernel_19720\2349841611.py in <module>
----> 1 df.to_hdf("./output/foo.h5","df")
D:\AppGallery\Software\Anaconda3\lib\site-packages\pandas\core\generic.py in to_hdf(self, path_or_buf, key, mode, complevel, complib, append, format, index, min_itemsize, nan_rep, dropna, data_columns, errors, encoding)
2761 # Argument 3 to "to_hdf" has incompatible type "NDFrame"; expected
2762 # "Union[DataFrame, Series]" [arg-type]
-> 2763 pytables.to_hdf(
2764 path_or_buf,
2765 key,
D:\AppGallery\Software\Anaconda3\lib\site-packages\pandas\io\pytables.py in to_hdf(path_or_buf, key, value, mode, complevel, complib, append, format, index, min_itemsize, nan_rep, dropna, data_columns, errors, encoding)
309 path_or_buf = stringify_path(path_or_buf)
310 if isinstance(path_or_buf, str):
--> 311 with HDFStore(
312 path_or_buf, mode=mode, complevel=complevel, complib=complib
313 ) as store:
D:\AppGallery\Software\Anaconda3\lib\site-packages\pandas\io\pytables.py in __init__(self, path, mode, complevel, complib, fletcher32, **kwargs)
570 raise ValueError("format is not a defined argument for HDFStore")
571
--> 572 tables = import_optional_dependency("tables")
573
574 if complib is not None and complib not in tables.filters.all_complibs:
D:\AppGallery\Software\Anaconda3\lib\site-packages\pandas\compat\_optional.py in import_optional_dependency(name, extra, errors, min_version)
139 except ImportError:
140 if errors == "raise":
--> 141 raise ImportError(msg)
142 else:
143 return None
ImportError: Missing optional dependency 'pytables'. Use pip or conda to install pytables.
pd.read_hdf("./output/foo.h5","df").head()
Mysql
写出到mysql里
from sqlalchemy import create_engine
mysql_engine = create_engine("mysql+pymysql://admin:123456@localhost/mydb")
pust_table_name='rand_numberic_table'
df.to_sql(pust_table_name,mysql_engine,if_exists="replace",index = False) # 注意mysql_engine 一定要配置正确
10
读入刚刚写出的文件
df = pd.read_sql("""
select col0,col1 from rand_numberic_table;
""", mysql_engine)
df
col0 | col1 | |
---|---|---|
0 | 0.352091 | 0.178000 |
1 | 0.966381 | 0.427036 |
2 | 0.261888 | 0.506005 |
3 | 0.030669 | 0.653736 |
4 | 0.165038 | 0.963646 |
5 | 0.181801 | 0.307962 |
6 | 0.030284 | 0.813831 |
7 | 0.345255 | 0.650669 |
8 | 0.339321 | 0.991851 |
9 | 0.205519 | 0.544493 |
Pandas 表格样式
Pandas 的样式是一个可视化的方法,像Excel一样对特定数据进行加粗、标红、北京标黄等,为了让数据更加清晰醒目,突出数据的逻辑和特征。
假如我们有这样一个DataFrame,我们需要通过表格样式给它做各种标注:
# 读取数据
import pandas as pd
import numpy as np
df = pd.DataFrame({
"A":["孙云","郑成","冯敏","王忠","郑花","孙华","赵白","王花","黄成","钱明","孙宇"],
"B":[79,70,39,84,87,26,29,47,32,22,99],
"C":[28,77,84,26,29,47,32,22,99,76,44],
"D":[18,53,78,4,36,88,79,47,54,25,14]
})
df
A | B | C | D | |
---|---|---|---|---|
0 | 孙云 | 79 | 28 | 18 |
1 | 郑成 | 70 | 77 | 53 |
2 | 冯敏 | 39 | 84 | 78 |
3 | 王忠 | 84 | 26 | 4 |
4 | 郑花 | 87 | 29 | 36 |
5 | 孙华 | 26 | 47 | 88 |
6 | 赵白 | 29 | 32 | 79 |
7 | 王花 | 47 | 22 | 47 |
8 | 黄成 | 32 | 99 | 54 |
9 | 钱明 | 22 | 76 | 25 |
10 | 孙宇 | 99 | 44 | 14 |
字体颜色
首先来看一个对文字标注颜色的例子:eg:我们想把成绩超过80的分数用红色标注出来
我们需要先定义一个函数,根据田间反悔哦不同的颜色
def color_negative_red(val):
color = "red" if val > 80 else "black"
return "color: %s"% color
应用这个自定义函数后就可以得到:
df.set_index("A").style.applymap(color_negative_red)
B | C | D | |
---|---|---|---|
A | |||
孙云 | 79 | 28 | 18 |
郑成 | 70 | 77 | 53 |
冯敏 | 39 | 84 | 78 |
王忠 | 84 | 26 | 4 |
郑花 | 87 | 29 | 36 |
孙华 | 26 | 47 | 88 |
赵白 | 29 | 32 | 79 |
王花 | 47 | 22 | 47 |
黄成 | 32 | 99 | 54 |
钱明 | 22 | 76 | 25 |
孙宇 | 99 | 44 | 14 |
背景高亮
接着eg. 我们假设有学生没有去考试,想看看哪些学生没有考试,把这部南非进行北京高亮显示
数据如下:
df1 = df.copy()
df1
A | B | C | D | |
---|---|---|---|---|
0 | 孙云 | 79 | 28 | 18 |
1 | 郑成 | 70 | 77 | 53 |
2 | 冯敏 | 39 | 84 | 78 |
3 | 王忠 | 84 | 26 | 4 |
4 | 郑花 | 87 | 29 | 36 |
5 | 孙华 | 26 | 47 | 88 |
6 | 赵白 | 29 | 32 | 79 |
7 | 王花 | 47 | 22 | 47 |
8 | 黄成 | 32 | 99 | 54 |
9 | 钱明 | 22 | 76 | 25 |
10 | 孙宇 | 99 | 44 | 14 |
df1.iloc[1,1] = np.nan
df1.iloc[2,1] = np.nan
df1
A | B | C | D | |
---|---|---|---|---|
0 | 孙云 | 79.0 | 28 | 18 |
1 | 郑成 | NaN | 77 | 53 |
2 | 冯敏 | NaN | 84 | 78 |
3 | 王忠 | 84.0 | 26 | 4 |
4 | 郑花 | 87.0 | 29 | 36 |
5 | 孙华 | 26.0 | 47 | 88 |
6 | 赵白 | 29.0 | 32 | 79 |
7 | 王花 | 47.0 | 22 | 47 |
8 | 黄成 | 32.0 | 99 | 54 |
9 | 钱明 | 22.0 | 76 | 25 |
10 | 孙宇 | 99.0 | 44 | 14 |
换句话说,就是用背景高亮标记出空置,应用.highlight_null()即可将空值高亮显示,同时用null_color参数可以指定该高亮的颜色。
# 把空值设置高亮
df1.style.highlight_null(null_color="blue")
A | B | C | D | |
---|---|---|---|---|
0 | 孙云 | 79.000000 | 28 | 18 |
1 | 郑成 | nan | 77 | 53 |
2 | 冯敏 | nan | 84 | 78 |
3 | 王忠 | 84.000000 | 26 | 4 |
4 | 郑花 | 87.000000 | 29 | 36 |
5 | 孙华 | 26.000000 | 47 | 88 |
6 | 赵白 | 29.000000 | 32 | 79 |
7 | 王花 | 47.000000 | 22 | 47 |
8 | 黄成 | 32.000000 | 99 | 54 |
9 | 钱明 | 22.000000 | 76 | 25 |
10 | 孙宇 | 99.000000 | 44 | 14 |
极值背景高亮
接着我们想看看eg.标记出每个科目的最高分数
换句话说,需要查找DataFrame每一列的最大值,通过highlight_max()方法用于将最大值高亮显示,并通过color参数修改高亮颜色
# 设置极大值高亮
df.set_index("A").style.highlight_max(color = "red")
B | C | D | |
---|---|---|---|
A | |||
孙云 | 79 | 28 | 18 |
郑成 | 70 | 77 | 53 |
冯敏 | 39 | 84 | 78 |
王忠 | 84 | 26 | 4 |
郑花 | 87 | 29 | 36 |
孙华 | 26 | 47 | 88 |
赵白 | 29 | 32 | 79 |
王花 | 47 | 22 | 47 |
黄成 | 32 | 99 | 54 |
钱明 | 22 | 76 | 25 |
孙宇 | 99 | 44 | 14 |
通过highlight_min()方法可以将最小值高亮显示
df.set_index("A").style.highlight_min(color = "yellow")
B | C | D | |
---|---|---|---|
A | |||
孙云 | 79 | 28 | 18 |
郑成 | 70 | 77 | 53 |
冯敏 | 39 | 84 | 78 |
王忠 | 84 | 26 | 4 |
郑花 | 87 | 29 | 36 |
孙华 | 26 | 47 | 88 |
赵白 | 29 | 32 | 79 |
王花 | 47 | 22 | 47 |
黄成 | 32 | 99 | 54 |
钱明 | 22 | 76 | 25 |
孙宇 | 99 | 44 | 14 |
同时显示极大值和极小值,并使用指定颜色:通过highlight_min()方法和highlight_max()方法再指定颜色
df.set_index("A").style.highlight_min(color = "green").highlight_max(color = "red")
B | C | D | |
---|---|---|---|
A | |||
孙云 | 79 | 28 | 18 |
郑成 | 70 | 77 | 53 |
冯敏 | 39 | 84 | 78 |
王忠 | 84 | 26 | 4 |
郑花 | 87 | 29 | 36 |
孙华 | 26 | 47 | 88 |
赵白 | 29 | 32 | 79 |
王花 | 47 | 22 | 47 |
黄成 | 32 | 99 | 54 |
钱明 | 22 | 76 | 25 |
孙宇 | 99 | 44 | 14 |
横向比较
再来看看横向对比的例子eg.需要标记出每个学生的单科最高分数:通过参数axis,横向对比大小,并把最大值进行高亮显示即可。
df.set_index("A").style.highlight_max(axis =1,color ="red")
B | C | D | |
---|---|---|---|
A | |||
孙云 | 79 | 28 | 18 |
郑成 | 70 | 77 | 53 |
冯敏 | 39 | 84 | 78 |
王忠 | 84 | 26 | 4 |
郑花 | 87 | 29 | 36 |
孙华 | 26 | 47 | 88 |
赵白 | 29 | 32 | 79 |
王花 | 47 | 22 | 47 |
黄成 | 32 | 99 | 54 |
钱明 | 22 | 76 | 25 |
孙宇 | 99 | 44 | 14 |
同样的,也可以通过参数subset,选定一列最大值进行高亮显示。
# 指定列进行比较
df.set_index("A").style.highlight_max(subset = ["B"],color = "yellow")
B | C | D | |
---|---|---|---|
A | |||
孙云 | 79 | 28 | 18 |
郑成 | 70 | 77 | 53 |
冯敏 | 39 | 84 | 78 |
王忠 | 84 | 26 | 4 |
郑花 | 87 | 29 | 36 |
孙华 | 26 | 47 | 88 |
赵白 | 29 | 32 | 79 |
王花 | 47 | 22 | 47 |
黄成 | 32 | 99 | 54 |
钱明 | 22 | 76 | 25 |
孙宇 | 99 | 44 | 14 |
背景渐变
eg.用不同的颜色标注成绩,背景颜色越深,成绩越高
通过调用background_gradient()方法,从而创建一个渐变的背景效果。
df.style.background_gradient()
A | B | C | D | |
---|---|---|---|---|
0 | 孙云 | 79 | 28 | 18 |
1 | 郑成 | 70 | 77 | 53 |
2 | 冯敏 | 39 | 84 | 78 |
3 | 王忠 | 84 | 26 | 4 |
4 | 郑花 | 87 | 29 | 36 |
5 | 孙华 | 26 | 47 | 88 |
6 | 赵白 | 29 | 32 | 79 |
7 | 王花 | 47 | 22 | 47 |
8 | 黄成 | 32 | 99 | 54 |
9 | 钱明 | 22 | 76 | 25 |
10 | 孙宇 | 99 | 44 | 14 |
同样地,针对单个列,指定颜色系列如下:
df.style.background_gradient(subset=["B"],cmap = "BuGn")
A | B | C | D | |
---|---|---|---|---|
0 | 孙云 | 79 | 28 | 18 |
1 | 郑成 | 70 | 77 | 53 |
2 | 冯敏 | 39 | 84 | 78 |
3 | 王忠 | 84 | 26 | 4 |
4 | 郑花 | 87 | 29 | 36 |
5 | 孙华 | 26 | 47 | 88 |
6 | 赵白 | 29 | 32 | 79 |
7 | 王花 | 47 | 22 | 47 |
8 | 黄成 | 32 | 99 | 54 |
9 | 钱明 | 22 | 76 | 25 |
10 | 孙宇 | 99 | 44 | 14 |
刚才我们时默认颜色渐变的范围了,接着我们来看如何指定颜色渐变的范围,来展现成绩的高低
通过调用background_gradient(low = 0.5,high = 0)
df.style.background_gradient(low=0.5,high = 0)
A | B | C | D | |
---|---|---|---|---|
0 | 孙云 | 79 | 28 | 18 |
1 | 郑成 | 70 | 77 | 53 |
2 | 冯敏 | 39 | 84 | 78 |
3 | 王忠 | 84 | 26 | 4 |
4 | 郑花 | 87 | 29 | 36 |
5 | 孙华 | 26 | 47 | 88 |
6 | 赵白 | 29 | 32 | 79 |
7 | 王花 | 47 | 22 | 47 |
8 | 黄成 | 32 | 99 | 54 |
9 | 钱明 | 22 | 76 | 25 |
10 | 孙宇 | 99 | 44 | 14 |
接着我们看看如何对特定范围内的值进行标注
eg.假如需要把60分以上的分数用颜色标注出来
通过参数vmin和参数vmax设置渐变的最小值和最大值,就可以展现出来
df.style.background_gradient(vmin = 60,vmax=100)
A | B | C | D | |
---|---|---|---|---|
0 | 孙云 | 79 | 28 | 18 |
1 | 郑成 | 70 | 77 | 53 |
2 | 冯敏 | 39 | 84 | 78 |
3 | 王忠 | 84 | 26 | 4 |
4 | 郑花 | 87 | 29 | 36 |
5 | 孙华 | 26 | 47 | 88 |
6 | 赵白 | 29 | 32 | 79 |
7 | 王花 | 47 | 22 | 47 |
8 | 黄成 | 32 | 99 | 54 |
9 | 钱明 | 22 | 76 | 25 |
10 | 孙宇 | 99 | 44 | 14 |
eg.用此次考试成绩表,添加标题
通过.set_caption()方法DataFrame即可设置标题。
# 添加标题
df.style.set_caption("三年级二班学生成绩表")
A | B | C | D | |
---|---|---|---|---|
0 | 孙云 | 79 | 28 | 18 |
1 | 郑成 | 70 | 77 | 53 |
2 | 冯敏 | 39 | 84 | 78 |
3 | 王忠 | 84 | 26 | 4 |
4 | 郑花 | 87 | 29 | 36 |
5 | 孙华 | 26 | 47 | 88 |
6 | 赵白 | 29 | 32 | 79 |
7 | 王花 | 47 | 22 | 47 |
8 | 黄成 | 32 | 99 | 54 |
9 | 钱明 | 22 | 76 | 25 |
10 | 孙宇 | 99 | 44 | 14 |
通过以上内容的学习,我们快速学习Pandas样式的基本操作,接下来,再用两个案例详细说明一下
案例一:将目标分数小于60的值,用红色机械能高亮显示
# 将学生没有及格的科目标记为红色
df.set_index("A").style.applymap(lambda x: "background-color:red" if x < 60 else "")
B | C | D | |
---|---|---|---|
A | |||
孙云 | 79 | 28 | 18 |
郑成 | 70 | 77 | 53 |
冯敏 | 39 | 84 | 78 |
王忠 | 84 | 26 | 4 |
郑花 | 87 | 29 | 36 |
孙华 | 26 | 47 | 88 |
赵白 | 29 | 32 | 79 |
王花 | 47 | 22 | 47 |
黄成 | 32 | 99 | 54 |
钱明 | 22 | 76 | 25 |
孙宇 | 99 | 44 | 14 |
df.style.applymap(lambda x: "background-color:red" if x < 60 else "",subset=pd.IndexSlice[:,["B","C","D"]])
A | B | C | D | |
---|---|---|---|---|
0 | 孙云 | 79 | 28 | 18 |
1 | 郑成 | 70 | 77 | 53 |
2 | 冯敏 | 39 | 84 | 78 |
3 | 王忠 | 84 | 26 | 4 |
4 | 郑花 | 87 | 29 | 36 |
5 | 孙华 | 26 | 47 | 88 |
6 | 赵白 | 29 | 32 | 79 |
7 | 王花 | 47 | 22 | 47 |
8 | 黄成 | 32 | 99 | 54 |
9 | 钱明 | 22 | 76 | 25 |
10 | 孙宇 | 99 | 44 | 14 |
案例二:标记总分低于120分的分数
将每个学生的分数,进行加总和计算平均数,并保留两位小数,把分数低于120的学生,用红色进行标记即可。
# 通过使用.assign()来计算学生三门课程的总分和平均值。
(df.set_index("A").assign(sum_s = df.set_index("A").sum(axis = 1))
.style.applymap(lambda x: "background-color:red" if x <120 else "",subset = pd.IndexSlice[:,["sum_s"]])
.format({"avg":"{:.2f}"}))
B | C | D | sum_s | |
---|---|---|---|---|
A | ||||
孙云 | 79 | 28 | 18 | 125 |
郑成 | 70 | 77 | 53 | 200 |
冯敏 | 39 | 84 | 78 | 201 |
王忠 | 84 | 26 | 4 | 114 |
郑花 | 87 | 29 | 36 | 152 |
孙华 | 26 | 47 | 88 | 161 |
赵白 | 29 | 32 | 79 | 140 |
王花 | 47 | 22 | 47 | 116 |
黄成 | 32 | 99 | 54 | 185 |
钱明 | 22 | 76 | 25 | 123 |
孙宇 | 99 | 44 | 14 | 157 |
pandas 可视化
一图胜千言:A picture is worth a thousand words。
常见的可视化图如下几种:
1.line:折线图
2.pie:饼图
3.bar:柱状图
4.hist:直方图
5.box:箱型图
6.area:面积图
7.scatter:散点图
# 用于处理解决中文乱码问题和负号问题
import matplotlib.pyplot as plt
plt.rcParams["font.sans-serif"]=["SimHei"] # 指定显示的字体,解决中文乱码
plt.rcParams["axes.unicode_minus"] = False # 显示负号
line:折线图
折线图一般用于描述数据的趋势:
import pandas as pd
import numpy as np
import random
df = pd.DataFrame({
"A":["a","b","c","d","e","f","g","h","i"],
"B":["L","L","M","L","M","M","M","L","L"],
"C":[107,177,139,38,52,38,87,38,56],
"D":[22,59,38,59,59,82,89,48,88]
}).set_index("A")
df
B | C | D | |
---|---|---|---|
A | |||
a | L | 107 | 22 |
b | L | 177 | 59 |
c | M | 139 | 38 |
d | L | 38 | 59 |
e | M | 52 | 59 |
f | M | 38 | 82 |
g | M | 87 | 89 |
h | L | 38 | 48 |
i | L | 56 | 88 |
一组数据的折线图如下:
df["C"].plot.line()
<AxesSubplot:xlabel='A'>
df[["C","D"]].plot.line()
<AxesSubplot:xlabel='A'>
pie:饼图
饼图一般用于展示数据的占比关系
np.random.seed(123)
df1 = pd.Series(3*np.random.rand(4),index=["A","B","C","D"],name = "占比")
df1
A 2.089408
B 0.858418
C 0.680554
D 1.653944
Name: 占比, dtype: float64
查看以上四个数据的占比情况
df1.plot.pie()
<AxesSubplot:ylabel='占比'>
bar:柱状图
柱状图一般用于类别型数据的对比分析
一组数据的柱状图
df["C"].plot.bar()
<AxesSubplot:xlabel='A'>
两组数据的柱状图
df[["C","D"]].plot.bar()
<AxesSubplot:xlabel='A'>
横向柱状图
df.plot.barh()
<AxesSubplot:ylabel='A'>
其他几种柱状图
df.assign(a = df.C-70).plot.bar()
<AxesSubplot:xlabel='A'>
df.plot.bar(stacked =True)
<AxesSubplot:xlabel='A'>
df.plot.barh(stacked =True)
<AxesSubplot:ylabel='A'>
df.head(5).plot.barh(stacked =True,colormap = "cool")
<AxesSubplot:ylabel='A'>
hist:直方图
直方图适合展现连续型数据的分布情况
np.random.seed(123)
df2 = pd.DataFrame({
"a":np.random.randn(1000)+1,
"b":np.random.randn(1000),
"c":np.random.randn(1000)-1
})
df2
a | b | c | |
---|---|---|---|
0 | -0.085631 | -0.748827 | -2.774224 |
1 | 1.997345 | 0.567595 | -2.201377 |
2 | 1.282978 | 0.718151 | 0.096257 |
3 | -0.506295 | -0.999381 | -0.138963 |
4 | 0.421400 | 0.474898 | -2.520367 |
... | ... | ... | ... |
995 | 1.634763 | 0.845701 | -1.075335 |
996 | 2.069919 | -1.119923 | -1.946199 |
997 | 0.090673 | -0.359297 | 1.040432 |
998 | 1.470264 | -1.609695 | 0.015917 |
999 | -0.111430 | 0.013570 | -2.633788 |
1000 rows × 3 columns
df2["a"].plot.hist()
<AxesSubplot:ylabel='Frequency'>
多组数据的直方图
df2.plot.hist()
<AxesSubplot:ylabel='Frequency'>
指定分箱数量的直方图
# 堆叠,指定分箱数量
df2.plot.hist(stacked = True,bins =30)
<AxesSubplot:ylabel='Frequency'>
box:箱型图
箱型图用于展示数据的分布、识别异常值以及比较不同组之间的差异。
一组数据的箱型图
df.boxplot("C")
<AxesSubplot:>
两列数据来画两个箱型图
df.boxplot(["C","D"])
<AxesSubplot:>
横向箱线图
df.boxplot(["C","D"],vert = False)
<AxesSubplot:>
area:面积图
面积图是一种有效的数据可视化工具,用于展示数据的趋势、比较不同组之间的差异的以及理解数据的部分与整体关系。广泛应用于统计学、经济学、市场调研、环境科学等领域,并为数据包分析和决策提供了重要的支持。
np.random.seed(123)
df4 = pd.DataFrame(np.random.rand(10,4),columns=["a","b","c","d"])
df4
a | b | c | d | |
---|---|---|---|---|
0 | 0.696469 | 0.286139 | 0.226851 | 0.551315 |
1 | 0.719469 | 0.423106 | 0.980764 | 0.684830 |
2 | 0.480932 | 0.392118 | 0.343178 | 0.729050 |
3 | 0.438572 | 0.059678 | 0.398044 | 0.737995 |
4 | 0.182492 | 0.175452 | 0.531551 | 0.531828 |
5 | 0.634401 | 0.849432 | 0.724455 | 0.611024 |
6 | 0.722443 | 0.322959 | 0.361789 | 0.228263 |
7 | 0.293714 | 0.630976 | 0.092105 | 0.433701 |
8 | 0.430863 | 0.493685 | 0.425830 | 0.312261 |
9 | 0.426351 | 0.893389 | 0.944160 | 0.501837 |
一组数据的面积图
df4["a"].plot.area()
<AxesSubplot:>
多组数据的面积图
df4[["a","b","c","d"]].plot.area()
<AxesSubplot:>
scatter:散点图
散点图显示两个连续型变量之间的关系和探索离群值。对于相关性,散点图有助于显示两个变量之间的线性关系的强度。对于回归,散点图常常会添加拟合线。
np.random.seed(123)
df = pd.DataFrame(np.random.randn(10,2),columns=["B","C"]).cumsum()
df
B | C | |
---|---|---|
0 | -1.085631 | 0.997345 |
1 | -0.802652 | -0.508949 |
2 | -1.381252 | 1.142487 |
3 | -3.807932 | 0.713575 |
4 | -2.541995 | -0.153166 |
5 | -3.220881 | -0.247875 |
6 | -1.729492 | -0.886777 |
7 | -2.173474 | -1.321128 |
8 | 0.032456 | 0.865658 |
9 | 1.036510 | 1.251844 |
pd.DataFrame(np.random.randn(10,2),columns=["B","C"])
B | C | |
---|---|---|
0 | 0.737369 | 1.490732 |
1 | -0.935834 | 1.175829 |
2 | -1.253881 | -0.637752 |
3 | 0.907105 | -1.428681 |
4 | -0.140069 | -0.861755 |
5 | -0.255619 | -2.798589 |
6 | -1.771533 | -0.699877 |
7 | 0.927462 | -0.173636 |
8 | 0.002846 | 0.688223 |
9 | -0.879536 | 0.283627 |
用一列数据来画散点图
df["A"] = pd.Series(list(range(len(df))))
df
B | C | A | |
---|---|---|---|
0 | -1.085631 | 0.997345 | 0 |
1 | -0.802652 | -0.508949 | 1 |
2 | -1.381252 | 1.142487 | 2 |
3 | -3.807932 | 0.713575 | 3 |
4 | -2.541995 | -0.153166 | 4 |
5 | -3.220881 | -0.247875 | 5 |
6 | -1.729492 | -0.886777 | 6 |
7 | -2.173474 | -1.321128 | 7 |
8 | 0.032456 | 0.865658 | 8 |
9 | 1.036510 | 1.251844 | 9 |
df.assign(avg = df.mean(1)).plot.scatter(x = "C",y = "B")
<AxesSubplot:xlabel='C', ylabel='B'>
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 【自荐】一款简洁、开源的在线白板工具 Drawnix