Pandas
一、Pandas介绍
Python在数据处理上独步天下:代码灵活、开发快速;尤其是Python的Pandas包,无论是在数据分析领域、还是大数据开发场承中都具有显著的优势:
- Pandas是Python的一个第三方包,也是商业和工程领域最流行的结构化数据工具集,用于数据清洗、处理以及分析
- Pandas在数据处理上具有独特的优势:
- 底层是基于Numpy构建的,所以运行速度特别的快
- 有专门的处理缺失数据(处理思路:删,填)的API
- 强大而灵活的分组、聚合、转换功能

适用场景:
-
数据量大到Excel严重卡顿,且又都是单机数据的时候,我们使用Pandas
-
Pandas用于处理单机数据(小数据集(相对于大数据来说)
![image-20260715160353660]()
-
-
在大数据ETL数据仓库中,对数据进行清洗及处理的环节使用Pandas
二、Pandas数据结构与数据类型


Pandas中 没有行的概念

(1)Series对象
Series也是Panlas中的最基本的数据结构对象,下文中简称s对象;是DataFrame的列对象,series本身也具有索引。
Seriles是一种类似于一维数组的对象,由下面两个部分组成:

- values:一组数据(numpy.ndarray类型)
- index:相关的数据索引标签;如果没有为数据指定索引,于是会自动创建一个0到N-1(N为数据的长度)的整数型索
1. Series对象入门
Pandas中有两大核心对象,分别是:DataFrame和Series,其中,Series 一> 一列数据, DataFrame 一> 多列数据
1.1 创建Series对象
# 导包
import pandas as pd#1.创建Series对象,采用:默认自增索引。
s1 = pd.Series([1,2,3,4,5])
print(s1)
'''
0 1
1 2
2 3
3 4
4 5
'''#2.创建Series对象,采用:自定义索引.
s2 = pd.Series([1, 2, 3, 4, 5], index=['a', 'b', 'c', 'd', 'e'])
print(s2)
'''
a 1
b 2
c 3
d 4
e 5
'''#3,使用字典元组创建Series对象。
#元组形式
s3 = pd.Series((11, 22, 33, 44, 55))
print(s3)
'''
0 11
1 22
2 33
3 44
4 55
dtype: int64'''
#字典形式,
s4 = pd.Series({'a': 1, 'b': 3, 'c': 5})
print(s4)
'''
a 1
b 3
c 5
dtype: int64
'''#4.使用numpy - 创建Series对象.
s5 = pd.Series(np.arange(5))
print(s5)
'''
0 0
1 1
2 2
3 3
4 4
dtype: int64
'''
1.2 Series对象属性
#1.构建Series对象,索引为:A-F,值为:0-5
# s6 = pd.Series(data=[0, 1, 2, 3, 4, 5], index=['A', 'B', 'C', 'D', 'E', 'F'])
'''def __init__(self,data=None,index=None,dtype: Dtype | None = None,
'''#加入列表推导式
s6 = pd.Series(data=[i for i in range(6)], index=[i for i in 'ABCDEF'])
print(s6)
'''
A 0
B 1
C 2
D 3
E 4
F 5
dtype: int64
'''#2.获取Series对象的索引列(的值)
print(s6.index) # Index(['A', 'B','C','D','E','F'],dtype='object')#3.获取Series对象的值列(的值)
print(s6.values) # [0 1 2 3 4 5]#4.Series支持根据 索引获取元素,即:Series对象[索引值]
print(s6['D']) #3#5.根据索引,修改Series对象的元素值
s6['D'] = 9
print(s6['D']) #9
(2)DataFrame对象
1.创建DataFrame对象
DataFrame是一个类似于二维数组或表格(如excel)的对象,既有行索引,又有列索引
- 行索引,表明不同行,横向索引,叫index,0轴,axis=0
- 列索引,表名不同列,纵向索引I,叫columns,1轴,axis=1

DataFrame的创建有很多种方式
读取文件数据返回df:pd.read_csv('csv格式数据文件路径’)的方式获取了df对象使用字典、列表、元组创建df:接下来就展示如何使用字典、列表+元组、numpy创建对象
#场景1:通过字典+列表的方式实现。
# 准备数据集,每个键值对等于一列数据
info = {'name': ['水冷哥', '深情哥', '紫琪', '德华'],'gender': ['女', '男', '保密', '保密'],'age': [81, 80, 66, 55]
}
'''self,data=None,index: Axes | None = None,columns: Axes | None = None,dtype: Dtype | None = None,copy: bool | None = None,
'''
#2.把上述的数据集,封装成DataFrame对象。
df1 = pd.DataFrame(data=info)# 3.打印结果
df1
'''
0,水冷哥,女,81
1,深情哥,男,80
2,紫琪,保密,66
3,德华,保密,55
'''
#场景2:通过 列表+元组 的方式实现.
#1.准备数据集,每个元组=1行数据
info = [('刘亦菲', '女', 39),('迪丽热巴', '女', 31),('王志奇', '未知', 66)
]
#2。把上述的数据集,封装成DataFrame对象。
df2 = pd.DataFrame(data=info, columns=['姓名', '性别', '年龄'])
df2

#场景3:通过 numpy的ndarray - pandas DataFrame 的方式实现.
#1.创建numpy的 ndarray对象.
arr1 = np.arange(12).reshape(3, 4)
arr1
#2.把上述的ndarry对象,封装成DataFrame对象.
df3 = pd.DataFrame(data=arr1, columns=['a', 'b', 'c', 'd'])
df3

#2.修改DataFrame对象的 列名 和索引列值.
column_names = ['语文', '数学', '英语', '政治', '体育']
index_names = ['同学' + str(i) for i in range(score_df.shape[0])]
#index_names=['同学0',‘同学1',"同学2',"同学3',"同学4',"同学5',‘同学6',‘同学7,‘同学8',‘同学9'#3,具体的修改DataFrame对象 列名 和 索引值的动作。
score_df.columns = column_names
score_df.index = index_names#rename函数也可以,
# score_df.rename(index={0:'网学0', 1:'同学1'}, columns={0: 'AI课程', 1:'大数课程'}, inplace=True)# score_df.rename(
# index={i:index_names[i] for i in range(score_df.shape[0])},
# columns={i: column_names[i] for i in range(score_df.shape[1])},
# inplace=True)#4。打印修改后的结果。
score_df

2. DataFrame对象属性
-
基本属性
#shape维度,即:行列数 print(score_df.shape) #(10,5) #index:索引列 print(score_df.index) #columns:列名 print(score_df.columns) # data:数据 print(score_df.values) -
行列转置
# 行列转置 T score_df.T![image-20260717172048033]()
3. DataFrame对象方法
#1.查看df对象
score_df
-
head(n),查看前n行数据
# score_df.head() #默认是5条 score_df.head(3) #指定数据条数 -
tai(n),查看后n行数据
score_df.tail() #默认是5条 score_df.tail(2) #指定数据条数 -
info(),查看df对象的详细信息
#3.info(),查看df对象的详细信息 score_df.info()![image-20260717174944249]()
-
查看df对象的 描述性 统计信息
#4. describe(),查看df对象的 描述性 统计信息 score_df.describe()

4. DatatFrame索引的设置
-
reset_index() 重置索引列.
# 5.reset_index() 重置索引列. # score_df.reset_index(drop=False) #drop=False,默认值,不删除原索引列。 score_df.reset_index(drop=True) #drop=True,删除原索引列.![image-20260717175414472]()
-
set_index():重新设置索引.
# 6.set_index():重新设置索引. # score_df.set_index('语文') # 语文成绩充当索引列。#语文,英语充当索引列。 score_df.set_index(['语文', '英语'])
二、Pandas的数据类型
| Pandas数据类型 | 说明 | 对应的Python类型 |
|---|---|---|
| Object | 字符串类型 | string |
| int | 整数类型 | int |
| float | 浮点数类型 | float |
| datetime | 日期时间类型 | datetime包中的datetime类型 |
| timedelta | 时间差类型 | datetime包中的timedelta类型 |
| category | 分类类型 | 无原生类型,可以自定义 |
| bool | 布尔类型 | bool (True,False) |
| nan,NAN,NaN | 空值类型 | None |
可以通过下列API查看s对象或df对象中数据的类型
s1.dtypes
df1.dtypes
df1.info() # s对象没有info()方法
-
几个特殊类型演示
- datetime类型
import pandas as pddf2 = pd.DataFrame(['2026-07-18','2026-07-19','2026-07-19'],dtype='datetime64[ns]') print(df2) print(df2.dtypes) '''0 0 2026-07-18 1 2026-07-19 2 2026-07-19 0 datetime64[ns] dtype: object '''- timedelta类型
import pandas as pd# 计算两个日期之间的差值 start_date = pd.to_datetime('2026-07-18') end_date = pd.to_datetime('2026-08-18') delta = end_date - start_date print(delta) # 31 days 00:00:00 print(type(delta)) # <class 'pandas._libs.tslibs.timedeltas.Timedelta'>- category类型
类型用于表示分类数据,通常用于有限集合中的数据类型,例如性别、颜色、产品类型等。这种类型的优点在于占用更少的内存,并且对分类数据的操作更快。
import pandas as pd# 创建一个category类型的Series categories = pd.Series(['apple', 'banana', 'apple', 'orange'], dtype='category') print(categories) print(type(categories)) ''' 0 apple 1 banana 2 apple 3 orange dtype: category Categories (3, object): ['apple', 'banana', 'orange'] <class 'pandas.core.series.Series'> '''
三、Pandas基本数据操作
(1)数据集
为了更好的理解基本操作,读取一个真实的股票数据。
# 1. 读取文件
data = pd.read_csv("./data/stock_day.csv")# 2. 移除一些不需要的字段
data = data.drop(["ma5","ma10","ma20","v_ma5","v_ma10","v_ma20"], axis=1) # 0:列,1:行
# 3. 查看处理后的数据
data # 查看数据
data.info()
'''
<class 'pandas.core.frame.DataFrame'>
Index: 643 entries, 2018-02-27 to 2015-03-02
Data columns (total 8 columns):# Column Non-Null Count Dtype
--- ------ -------------- ----- 0 open 643 non-null float641 high 643 non-null float642 close 643 non-null float643 low 643 non-null float644 volume 643 non-null float645 price_change 643 non-null float646 p_change 643 non-null float647 turnover 643 non-null float64
dtypes: float64(8)
memory usage: 45.2+ KB
'''
data.describe()

(2)索引操作
1. 直接使用行列索引(先列后行)
获取'2018-02-27'这天的'close'的结果
# 直接使用行列索引名字的方式(先列后行)
data['open']['2018-02-27']
# 23.53# 不支持的操作 尝试用,先行后列
# 错误
data['2018-02-27']['open']
# 错误
data[:1, :2]
2. 结合loc或者iloc使用索引

获取从'2018-02-27':'2018-02-22','open'的结果
#场景2:结合 1oc根据:行索引和 列名来获取元素.
#格式:df.1oc[行索引,列名]
#格式:df.ioc[行号,列索引]
data.loc['2018-02-27', 'high'] # 获取一条数据
data.loc['2018-02-27':'2018-02-22', 'open']'''
2018-02-27 23.53
2018-02-26 22.80
2018-02-23 22.88
'''
# Name: open, dtype: float64# 场景3:结合i0c根据:行号和列索引来获取元素
# 获取前3天数据,前5列的结果
data.iloc[0:3, 0:5]'''open high close low
2018-02-27 23.53 25.88 24.16 23.53
2018-02-26 22.80 23.78 23.53 22.80
2018-02-23 22.88 23.37 22.82 22.71
'''
(3)赋值操作
对DataFrame当中的close列进行重新赋值为1
# 2.赋值操作
data['close'] = 1
# 或者
data.close = 1 # 效果同上,更简单,但是有弊端,如果 字段有空格等,该方式不行,例如:df.max value 必须成 df['max value
data
(4)排序操作
排序有两种形式,一种对于索引进行排序,一种对于内容进行排序
1. DataFrame排序
- 使用df.sort_values(by=, ascending=)
- 单个键或者多个键进行排序,
- 参数:
- by:指定排序参考的键
- ascending:默认升序
- ascending=False:降序
- ascending=True:升序
# 按照开盘价大小进行排序 , 使用ascending指定按照大小排序
data.sort_values(by="open", ascending=True)
# 按照多个键进行排序
# 基于开盘价格降序排列,价格一样,基于当日最高价格(high) 降序排列。
df.sort_values(by=['open', 'high'], ascending=[False, False])
- 使用df.sort_index给索引进行排序
这个股票的日期索引原来是从大到小,现在重新排序,从小到大
# 对索引进行排序
data.sort_index(ascending=True) # 默认升序
2. Series排序
- 使用series.sort_values(ascending=True)进行排序
series排序时,只有一列,不需要参数
data['p_change'].sort_values(ascending=True).head()
'''
2015-09-01 -10.03
2015-09-14 -10.02
2016-01-11 -10.02
2015-07-15 -10.02
2015-08-26 -10.01
Name: p_change, dtype: float64
'''
- 使用series.sort_index()进行排序
与df一致
# 对索引进行排序
data['p_change'].sort_index().head()
'''
2015-03-02 2.62
2015-03-03 1.44
2015-03-04 1.57
2015-03-05 2.02
2015-03-06 8.51
Name: p_change, dtype: float64
'''
四、Dataframe运算
(1)算法运算
- add(other)
进行数学运算加上具体的一个数字
import pandas as pd
df = pd.read_csv('./data/stock_day.csv')
#2.针对于cLose列值+2处理.
df.close.add(2) # 效果同下
# df.close + 2 Series对象 和 数值运算,则 Series中的每个数值都会和该数字进行运算.
'''
2018-02-27 24.53
2018-02-26 23.80
2018-02-23 23.88
2018-02-22 23.25
2018-02-14 22.49
'''
- sub(other)
进行数学运算减去具体的一个数字
#3。针对于Low列的值-10处理
# df.low.sub(10)
df.low - 10 #效果同上
(2)逻辑运算符
1. 逻辑运算符号
- 例如筛选df["open"] > 23的日期数据
- df["open"] > 23返回逻辑结果
df["open"] > 232018-02-27 True
2018-02-26 False
2018-02-23 False
2018-02-22 False
2018-02-14 False
# 逻辑判断的结果可以作为筛选的依据
df[df["open"] > 23].head()
- 完成多个逻辑判断,
#需求2:筛选出 open列值>23,且<24的数据.
df[(df.open > 23) & (df.open < 24)] # 细节:多组判断记得加 小括号。df[(df['open'] >23) & (df['open']< 24)] #标准写法。
2. 逻辑运算函数
- query(expr)
- expr:查询字符串
通过query使得刚才的过程更加方便简单
df.query("open<24 & open>23").head()
- isin(values)
例如判断'open'是否为23.53和23.85
#4.固定值的筛选,isin
#需求:查询 open价格为 23.53,23.67价格数据.
df[df.open.isin([23.53, 23.67])]
df[(df.open == 23.53) | (df.open == 23.67)]# df.query('open == 23.53 | open == 23.67')
(3)统计运算
1. describe
综合分析: 能够直接得出很多统计结果,count, mean, std, min, max 等
# 计算平均值、标准差、最大值、最小值
df.describe() # 查看各列的描述性统计信息

(4)统计函数
Numpy当中已经详细介绍,在这里我们演示min(最小值), max(最大值), mean(平均值), median(中位数), var(方差), std(标准差),mode(众数)结果:
count |
Number of non-NA observations |
|---|---|
sum |
Sum of values |
mean |
Mean of values |
median |
Arithmetic median of values |
min |
Minimum |
max |
Maximum |
mode |
Mode(众数) |
abs |
Absolute Value |
prod |
Product of values(乘积) |
std |
Bessel-corrected sample standard deviation |
var |
Unbiased variance |
idxmax |
compute the index labels with the maximum |
idxmin |
compute the index labels with the minimum |
对于单个函数去进行统计的时候,坐标轴还是按照默认列“columns” (axis=0, default),如果要对行“index” 需要指定(axis=1)
- sum()、mean()
df.sum() #针对于每列(DataFrame对象)进行求和.
df.high.sum() #针对于 high列(Series对象)进行求和.
df.mean() #针对于每列(DataFrame对象)进行求平均值。
- max()、min()
# 使用统计函数:0 代表列求结果, 1 代表行求统计结果
df.max(0)open 34.99
high 36.35
close 35.21
low 34.01
volume 501915.41
price_change 3.03
p_change 10.03
turnover 12.56
my_price_change 3.41
dtype: float64
- std()、var()
# 方差
df.var(0)open 1.545255e+01
high 1.662665e+01
close 1.554572e+01
low 1.437902e+01
volume 5.458124e+09
price_change 8.072595e-01
p_change 1.664394e+01
turnover 4.323800e+00
my_price_change 6.409037e-01
dtype: float64# 标准差
df.std(0)open 3.930973
high 4.077578
close 3.942806
low 3.791968
volume 73879.119354
price_change 0.898476
p_change 4.079698
turnover 2.079375
my_price_change 0.800565
dtype: float64
- median():中位数
中位数为将数据从小到大排列,在最中间的那个数为中位数。如果没有中间数,取中间两个数的平均值。
df = pd.DataFrame({'COL1' : [2,3,4,5,4,2], 'COL2' : [0,1,2,3,4,2]})df.median()COL1 3.5
COL2 2.0
dtype: float64
- idxmax()、idxmin()
# 求出最大值的位置
df.idxmax(axis=0)open 2015-06-15
high 2015-06-10
close 2015-06-12
low 2015-06-12
volume 2017-10-26
price_change 2015-06-09
p_change 2015-08-28
turnover 2017-10-26
my_price_change 2015-07-10
dtype: object# 求出最小值的位置
df.idxmin(axis=0)open 2015-03-02
high 2015-03-02
close 2015-09-02
low 2015-03-02
volume 2016-07-06
price_change 2015-06-15
p_change 2015-09-01
turnover 2016-07-06
my_price_change 2015-06-15
dtype: object
1. 累计统计函数
| 函数 | 作用 |
|---|---|
cumsum |
计算前1/2/3/…/n个数的和 |
cummax |
计算前1/2/3/…/n个数的最大值 |
cummin |
计算前1/2/3/…/n个数的最小值 |
cumprod |
计算前1/2/3/…/n个数的积 |
以上这些函数可以对series和dataframe操作
这里我们按照时间的从前往后来进行累计
- 排序
# 排序之后,进行累计求和
df = df.sort_index()
- 对p_change进行求和
stock_rise = df['p_change']
# plot方法集成了前面直方图、条形图、饼图、折线图
stock_rise.cumsum()2015-03-02 2.62
2015-03-03 4.06
2015-03-04 5.63
2015-03-05 7.65
2015-03-06 16.16
2015-03-09 16.37
2015-03-10 18.75
2015-03-11 16.36
2015-03-12 15.03
2015-03-13 17.58
2015-03-16 20.34
2015-03-17 22.42
2015-03-18 23.28
2015-03-19 23.74
2015-03-20 23.48
2015-03-23 23.74
如果要使用plot函数,需要导入matplotlib.
import matplotlib.pyplot as plt
# plot显示图形
stock_rise.cumsum().plot()
# 需要调用show,才能显示出结果
plt.show()
(5)apply自定义运算
背景:目前我们用的都是Pandas提供好的函数,例如:count(,max(,min()...
如果要传入一些自定义的逻辑,此时就需要用到 appLy()函数了
格式:df.apply(自定义函数,axis=0) #8一>列,1一>行
- apply(func, axis=0)
- func:自定义函数
- axis=0:默认是列,axis=1为行进行运算
- 同时获取多个列的,最大值-最小值的函数
#需求:同时 获取到多列的最大值 和最小值的差值. 例如:open列,close列
# df.open.max() - df.open.min()
# df.close.max() - df.close.min()
#思路1:分解版
#1.自定义函数 my_func,接收 某列的数据,计算该列的最大值和最小值,返回差值。
def my_func(col):return col.max() - col.min()#2.获取到open列和close列.
df[['open', 'close']]
# df.loc[:,['open','close']]
# df.iloc[:, [0, 2]]
# df.iloc[:, 0:3:2]#3.通过appLy(函数,调用上述的自定义函数,作用到 指定的列。
df[['open','close']].apply(my_func, axis=1) # axis=1, 表示对 行 进行操作.
df[['open','close']].apply(my_func, axis=0) # axis=e, 表示对 列 进行操作.
df[['open','close']].apply(my_func) #效果同上,默认是axis=0, 底层把df的各列分别传入函数,计算结果.#思路2:合并版,通过飞ambda函数实现.
df[['open', 'close']].apply(lambda col:col.max() - col.min())'''
open 22.74
close 22.85
dtype: float64
'''
五、文件读取与存储
我们的数据大部分存在于文件当中,所以pandas会支持复杂的IO操作,pandas的API支持众多的文件格式,如CSV、SQL、XLS、JSON、HDF5。
(1)CSV
1. read_csv
- pandas.read_csv(filepath_or_buffer, sep =',', usecols )
- filepath_or_buffer:文件路径
- sep :分隔符,默认用","隔开
- usecols:指定读取的列名,列表形式
- 举例:读取之前的股票的数据
# 读取文件,并且指定只获取'open', 'close'指标
data = pd.read_csv("./data/stock_day.csv", usecols=['open', 'close'])open close
2018-02-27 23.53 24.16
2018-02-26 22.80 23.53
2018-02-23 22.88 22.82
2018-02-22 22.25 22.28
2018-02-14 21.49 21.92
2. to_csv
- DataFrame.to_csv(path_or_buf=None, sep=', ’, columns=None, header=True, index=True, mode='w', encoding=None)
- path_or_buf :文件路径
- sep :分隔符,默认用","隔开
- columns :选择需要的列索引
- header :boolean or list of string, default True
- index:是否写进行索引,是否写进列索引值
- mode:'w':重写, 'a' 追加
- 举例:保存读取出来的股票数据
- 保存'open'列的数据,然后读取查看结果
# 选取10行数据保存,便于观察数据
data[:10].to_csv("./data/test.csv", columns=['open'])# 读取,查看结果
pd.read_csv("./data/test.csv")Unnamed: 0 open
0 2018-02-27 23.53
1 2018-02-26 22.80
2 2018-02-23 22.88
3 2018-02-22 22.25
4 2018-02-14 21.49
5 2018-02-13 21.40
6 2018-02-12 20.70
7 2018-02-09 21.20
8 2018-02-08 21.79
9 2018-02-07 22.69
会发现将索引存入到文件当中,变成单独的一列数据。如果需要删除,可以指定index参数,删除原来的文件,重新保存一次。
#2.把读取到的数据,写到文件中。
data[:10].to_csv('./data/my_file1.csv', sep=',', index=False)
print('写入成功!')#3.特殊的csV文件一)tsV文件.
#区别:csV文件一以,做分割,tsv文件 一是以tab键分隔的.
df[:5].to_csv('./data/my_file2.tsv', sep='\t', index=True)
print('写入成功!')#4。读取tsv文件.
#参1:文件路径,参2:分隔符,参3:把索引为0的列(第1列)设置为索引.
df2 = pd.read_csv('./data/my_file2.tsv', sep='\t', index_col=0)
df2
(2)MySQL
以MySQL数据库为例,此时默认你已经在本地安装好了MySQL数据库。如果想利用pandas和MySQL数据库进行交互,需要先安装与数据库交互所需要的python包
pip install pymysql==1.0.2 -i https://pypi.tuna.tsinghua.edu.cn/simple/
# 如果后边的代码运行提示找不到sqlalchemy的包,和pymysql一样进行安装即可
pip install sqlalchemy==2.0.0 -i https://pypi.tuna.tsinghua.edu.cn/simple/
- 准备要写入数据库的数据
import pandas as pd
df = pd.read_csv('./csv示例文件.csv', sep=',', index_col=[0])
df
- 创建数据库操作引擎对象并指定数据库
# 需要安装pymysql,部分版本需要额外安装sqlalchemy
# 导入sqlalchemy的数据库引擎
from sqlalchemy import create_engine# 创建数据库引擎,传入uri规则的字符串
engine = create_engine('mysql+pymysql://root:123456@127.0.0.1:3306/test?charset=utf8')
# mysql+pymysql://root:123456@127.0.0.1:3306/test?charset=utf8
# mysql 表示数据库类型
# pymysql 表示python操作数据库的包
# root:123456 表示数据库的账号和密码,用冒号连接
# 127.0.0.1:3306/test 表示数据库的ip和端口,以及名叫test的数据库
# charset=utf8 规定编码格式
- 将数据写入MySQL数据库
# df.to_sql()方法将df数据快速写入数据库
df.to_sql('test_pdtosql', engine, index=False, if_exists='append')
# 第一个参数为数据表的名称
# 第二个参数engine为数据库交互引擎
# index=False 表示不添加自增主键
# if_exists='append' :如果数据表存在,则如何处理(append一追加数据;replace一覆盖数据)
-
从数据库中加载数据:
- 读取整张表, 返回dataFrame
from sqlalchemy import create_engine engine = create_engine('mysql+pymysql://root:root@127.0.0.1:3306/test?charset=utf8')# 指定表名,传入数据库连接引擎对象 pd.read_sql('test_pdtosql', engine)- 使用SQL语句获取数据,返回dataframe
# 传入sql语句,传入数据库连接引擎对象 pd.read_sql('select name,AKA from test_pdtosql', engine)
(3)JSON
JSON是我们常用的一种数据交换格式,前面在前后端的交互经常用到,也会在存储的时候选择这种格式。所以我们需要知道Pandas如何进行读取和存储JSON格式。
1. read_json
-
pandas.read_json(path_or_buf=None, orient=None, typ='frame', lines=False)
-
将JSON格式准换成默认的Pandas DataFrame格式
-
orient : string,Indication of expected JSON string format.
-
'split' : dict like
- split 将索引总结到索引,列名到列名,数据到数据。将三部分都分开了
-
'records' : list like [{column -> value}, ... , {column -> value}]
- records 以
columns:values的形式输出
- records 以
-
'index' : dict like {index -> {column -> value}}
- index 以
index:{columns:values}...的形式输出
- index 以
-
'columns' : dict like {column -> {index -> value}}
,默认该格式
- colums 以
columns:{index:values}的形式输出
- colums 以
-
'values' : just the values array
- values 直接输出值
-
-
lines : boolean, default False
- 按照每行读取json对象
-
typ : default ‘frame’, 指定转换成的对象类型series或者dataframe
-
2. read_json案例
- 数据介绍
这里使用一个新闻标题讽刺数据集,格式为json。is_sarcastic:1讽刺的,否则为0;headline:新闻报道的标题;article_link:链接到原始新闻文章。存储格式为:
{"article_link": "https://www.huffingtonpost.com/entry/versace-black-code_us_5861fbefe4b0de3a08f600d5", "headline": "former versace store clerk sues over secret 'black code' for minority shoppers", "is_sarcastic": 0}
{"article_link": "https://www.huffingtonpost.com/entry/roseanne-revival-review_us_5ab3a497e4b054d118e04365", "headline": "the 'roseanne' revival catches up to our thorny political mood, for better and worse", "is_sarcastic": 0}
- 读取
orient指定存储的json格式,lines指定按照行去变成一个样本
#参1:文件路径,参2:读取的格式,参3:是否按行读取。
json_read = pd.read_json("./data/Sarcasm_Headlines_Dataset.json", orient="records", lines=True)
3. to_json
- DataFrame.to_json(path_or_buf=None,orient=None,lines=False)
- 将Pandas 对象存储为json格式
- path_or_buf=None:文件地址
- orient:存储的json形式,
- lines:一个对象存储为一行
4. 案例
# 把上述的数据,写到json文件中。
# json_df.to_json('./data/my_file3.json', orient='records') # 结果: [{},{},{}...]
# json_df.to_json('./data/my_file3.json', orient='records', lines=True) 结果为:让逐行形式
# json_df.to_json('./data/my_file3.json')#格式为:columns:{...}json_df.to_json('./data/my_file3.json', orient='records', lines=True) #结果为:{} {} {} ·····逐行形式
- 存储文件
json_read.to_json("./data/test.json", orient='records')
结果
[{"article_link":"https:\/\/www.huffingtonpost.com\/entry\/versace-black-code_us_5861fbefe4b0de3a08f600d5","headline":"former versace store clerk sues over secret 'black code' for minority shoppers","is_sarcastic":0},{"article_link":"https:\/\/www.huffingtonpost.com\/entry\/roseanne-revival-review_us_5ab3a497e4b054d118e04365","headline":"the 'roseanne' revival catches up to our thorny political mood, for better and worse","is_sarcastic":0},{"article_link":"https:\/\/local.theonion.com\/mom-starting-to-fear-son-s-web-series-closest-thing-she-1819576697","headline":"mom starting to fear son's web series closest thing she will have to grandchild","is_sarcastic":1},{"article_link":"https:\/\/politics.theonion.com\/boehner-just-wants-wife-to-listen-not-come-up-with-alt-1819574302","headline":"boehner just wants wife to listen, not come up with alternative debt-reduction ideas","is_sarcastic":1},{"article_link":"https:\/\/www.huffingtonpost.com\/entry\/jk-rowling-wishes-snape-happy-birthday_us_569117c4e4b0cad15e64fdcb","headline":"j.k. rowling wishes snape happy birthday in the most magical way","is_sarcastic":0},{"article_link":"https:\/\/www.huffingtonpost.com\/entry\/advancing-the-worlds-women_b_6810038.html","headline":"advancing the world's women","is_sarcastic":0},....]
- 修改lines参数为True
json_read.to_json("./data/test.json", orient='records', lines=True)
结果
{"article_link":"https:\/\/www.huffingtonpost.com\/entry\/versace-black-code_us_5861fbefe4b0de3a08f600d5","headline":"former versace store clerk sues over secret 'black code' for minority shoppers","is_sarcastic":0}
{"article_link":"https:\/\/www.huffingtonpost.com\/entry\/roseanne-revival-review_us_5ab3a497e4b054d118e04365","headline":"the 'roseanne' revival catches up to our thorny political mood, for better and worse","is_sarcastic":0}
{"article_link":"https:\/\/local.theonion.com\/mom-starting-to-fear-son-s-web-series-closest-thing-she-1819576697","headline":"mom starting to fear son's web series closest thing she will have to grandchild","is_sarcastic":1}
{"article_link":"https:\/\/politics.theonion.com\/boehner-just-wants-wife-to-listen-not-come-up-with-alt-1819574302","headline":"boehner just wants wife to listen, not come up with alternative debt-reduction ideas","is_sarcastic":1}
{"article_link":"https:\/\/www.huffingtonpost.com\/entry\/jk-rowling-wishes-snape-happy-birthday_us_569117c4e4b0cad15e64fdcb","headline":"j.k. rowling wishes snape happy birthday in the most magical way","is_sarcastic":0}...
六、DataFrame数据的增删改查操作
- 导包并加载数据:
import pandas as pddf = pd.read_csv('../数据集/1960-2019全球GDP数据.csv', encoding='gbk')
df2 = df[:5].copy()

(1)增加列
- 方式一: 通过直接赋值的方式添加新列
# 拷贝一份df
df3 = df2.copy()#写法1:固定值
df3['new col 1'] = 33#写法2:传入列表
# 新增列数据数量必须和行数相等
df3['new col 2'] = [1, 2, 3, 4, 5]
# 写法3:通过已有的列(Series)来计算新列的值.
df3['new col 3'] = df3.year * 2#写法4:通过函数来计算新列的值。
def my_fun1():return 25000df3['c4'] = my_fun1()
df3

- 方式二: df.assign函数添加列
# 1. 新列名=单个数据或一组数据,一组数据的数量必须和df的行数相同
df2.assign(new0=66)
# df2.assign(new1=[1, 2, 3, 4]) # 报错
df2.assign(new1=[1, 2, 3, 4, 5])# 2.1 新列名=Series对象,该s对象的索引和df索引一致
s = pd.Series([1, 2, 3, 4, 5])
df2.assign(new2=s)# 2.2 新列名=Series对象
df2.assign(new3=df2.year+df2.GDP)# 3. 新列名=自定义函数名
# 该自定义函数必须接收df作为参数
# 该自定义函数可以返回:
# 3.1.单个数据
# 3.2.一组数量和df的行数相同的数据
# 3.3.和df索引相同的Series对象
def foo(df):# 函数必须接收一个参数,该参数就是被传入的df对象print('='*10)print(df)print('='*5 + '上面输出的是传入的df')ret = df.index.values# 可以返回一个变量# return 'hahah'# 也可以返回一组变量return ret
df2.assign(new4=foo)解析:当我们使用函数的方式向df对象添加新列时,foo函数要求必须有一个参数,这个参数来自于调用assign的df对象,如上图所示
当我们给foo(df)定义一个df参数时,当assign方法开始执行,则系统会自动将df2对象作为参数传递给foo函数中的df参数
- df.assign函数可以同时添加多列
df2def foo(df):return 22def bar(df):return df.year + 1df2.assign(new0='hahaha',new1=[1, 2, 3, 4, 5],new2=pd.Series([1, 2, 3, 4, 5]),new3=df.year*2,new4=foo,new5=bar
)
(2)删除与去重
-
1- df.drop删除行数据
删除行 drop()函数,除非指定inplace=True,否则不会修改原始数据.
# df3.drop(index=[0, 2, 4]) # 不会修改原始数据,
df3.drop(index=[e], inplace=True) #会修改原始数据。
- 2- df.drop删除列数据
df4.drop(columns=['country'], inplace=True)
- 3- 使用del删除指定的列(不支持删除多列)
- 注意区别:
- del是直接永久删除原df中的列【慎重使用】
- drop是返回删除后的df或seires,原df或seires没有被修改
- 注意区别:
del df3['new col 3']
df3
# 重复运行本段代码将会报错,因为df3中的指定列在第一次运行时就被删除了
- 4- Dataframe数据去重(行去重)
# 添加一部分重复的数据
# df4 = df2.append(df2)(新版本不支持这个)df4 = df[:5].copy()
# 拼接df4 和 df4 一组合成 有重复数据的 DataFrame.
df5 = pd.concat([df4,df4])
# 实施去重操作
df5.drop_duplicates()
#如果设置inplace=True,则会修改原始数据.
- 5- series去重(列去重)
方式一:
df4.country.drop_duplicates()
# 返回结果如下
0 美国
1 英国
2 法国
3 中国
4 日本
Name: country, dtype: object方式二:
df4.country.unique()
# 返回结果如下
array(['美国', '英国', '法国', '中国', '日本'], dtype=object)
(3)修改DataFrame中的数据
- df.assign替换列
df = pd.read_csv('../数据集/1960-2019全球GDP数据.csv', encoding='gbk', )
df5 = df.head()
df5
df5 = df5.assign(GDP=66) # 可以接收单变量或列表、数组
df5
df # 此时原始的df不会发生改变
- 直接对原始的DF进行赋值修改处理
- 一般不建议直接修改操作
df = pd.read_csv('../数据集/1960-2019全球GDP数据.csv', encoding='gbk', )
df5 = df.head()
df5
df5['GDP'] = [5, 4, 3, 2, 1]
df5
df # 此时原始的df会发生改变
- replace函数替换数据
# 读取数据选取前5行作为一个新的df
df = pd.read_csv('../数据集/1960-2019全球GDP数据.csv', encoding='gbk', )
df6 = df.head()
df6
# series对象替换数据,返回的还是series对象,不会对原来的df造成修改
df6.year.replace(1960, 19600)
# 如果加上inplace=True参数,则会修改原始df
df6.country.replace('日本', '扶桑', inplace=True)
df6
# df也可以直接调用replace函数,用法和s.replace用法一致,只是返回的是df对象
df6.replace(1960, 19600)
df6备注:replace()是按照单元格元素值进行完全匹配
七、查询和排序dataFrame中的数据
-
1- 从前从后取多行数据
- head()
# 导包 import pandas as pd # 加载csv数据,指定gbk编码格式来读取文件,返回df df = pd.read_csv('../数据集/1960-2019全球GDP数据.csv', encoding='gbk') # 默认取前5行数据 df.head() df.head(10) # 取前10行- tail()
# 默认取后5行数据 df.tail() df2 = df.tail(15) # 倒数15行 df2 -
2- 获取一列或多列数据
- 获取一列数据
df[col_name]等同于df.col_name
#4.根据列名获取数据. df['year'] # 获取year列一 Series对象 df.year #获取year列 一> Series对象df[['year']] #获取year列 一> DataFrame对象- 获取多列数据
df[[col_name1,col_name2,...]]
df2[['country', 'GDP']] # 返回新的df - 获取一列数据
-
根据 行索引值来获取数据.
df[start:stop:step]:
df[start:stop:step]==df[起始行下标:结束行下标:步长], 遵循顾头不顾尾原则(包含起始行,不包含结束行),步长默认为1df4 = df.head(10) # 取原df前10行数据作为df4,默认自增索引由0到9 df4[0:3] # 取前3行 df4[:5:2] # 取前5行,步长为2 df4[1::3] # 取第2行到最后所有行,步长为3 -
查询函数获取子集: df.query()
df.query(判断表达式)可以依据判断表达式返回的符合条件的df子集- 与
df[布尔值向量]效果相同 - 特别注意
df.query()中传入的字符串格式
- 示例:
df3.query('country=="帕劳"') df3[df3['country']=='帕劳']- 查询中国, 美国 日本 三国 2015年至2019年的数据
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"]') -
排序函数
- sort_values函数: 按照指定的一列或多列的值进行排序
# 按GDP列的数值由小到大进行排序 df2.sort_values(['GDP']) # 按GDP列的数值由大到小进行排序 df2.sort_values(['GDP'], ascending=False) # 降序, ascending默认为True # 先对year年份进行由小到大排序,再对GDP由小到大排序 df2.sort_values(['year', 'GDP'])- rank函数:
- rank函数用法:
DataFrame.rank()或Series.rank() - rank函数返回值:以Series或者DataFrame的类型返回数据的排名(哪个类型调用返回哪个类型)
- rank函数包含有6个参数:
- axis:设置沿着哪个轴计算排名(0或者1),默认为0按纵轴计算排名
- numeric_only:是否仅仅计算数字型的columns,默认为False
- na_option :NaN值是否参与排序及如何排序,固定参数:keep top bottom
- keep: NaN值保留原有位置
- top: NaN值全部放在前边
- bottom: NaN值全部放在最后
- ascending:设定升序排还是降序排,默认True升序
- pct:是否以排名的百分比显示排名(所有排名与最大排名的百分比),默认False
- method:排名评分的计算方式,固定值参数,常用固定值如下:
- average : 默认值,排名评分不连续;数值相同的评分一致,都为平均值
- min : 排名评分不连续;数值相同的评分一致,都为最小值
- max : 排名评分不连续;数值相同的评分一致,都为最大值
- dense : 排名评分是连续的;数值相同的评分一致
df2 df2.rank() # 针对于每列进行排行 df2.rank(axis=0) df2.rank(numeric_only=True) # 只对数值类型的列进行统计 df2.rank(ascending=False) # 降序 df2.rank(pct=True) # 以最高分作为1,放回百分数形式的评分,pct参数默认为Falsedf2.rank(method='average') df2.rank(method='min') df2.rank(method='max') df2.rank(method='dense')rank使用详解
df7 = pd.DataFrame({'姓名':['小明', '小美', '小强', '小兰'],'成绩':[100, 90, 90, 80] })df7.rank() # 等价于df7.rank(method='average', ascending=True)df7['成绩排名'] = df7.成绩.rank(method='min', ascending=False) df7df7['成绩排名'] = df7.成绩.rank(method='max', ascending=False) df7df7['成绩排名'] = df7.成绩.rank(method='dense', ascending=False) df7 -
6- 聚合函数:
常用聚合函数有:
- min 最小值
- max 最大值
- mean 平均值
- sum 求和
- count 求个数
- min函数
df2.min()df2['year'].min()- max函数
df2.max() df2['year'].max()- mean 平均值
df2.mean() df2['year'].mean() df2['GDP'].mean()
八、高级处理-缺失值处理
(1)如何处理NAN
- 获取缺失值的标记方式(NaN或者其他标记方式)
- 如果缺失值的标记方式是NaN
- 判断数据中是否包含NaN:
- pd.isnull(df),
- pd.notnull(df)
- 存在缺失值nan:
- 1、删除存在缺失值的:dropna(axis='rows')
- 注:不会修改原数据,需要接受返回值
- 2、替换缺失值:fillna(value, inplace=True)
- value:替换成的值
- inplace:True:会修改原数据,False:不替换修改原数据,生成新的对象
- 1、删除存在缺失值的:dropna(axis='rows')
- 判断数据中是否包含NaN:
- 如果缺失值没有使用NaN标记,比如使用"?"
- 先替换‘?’为np.nan,然后继续处理
(2)电影数据的缺失值处理
- 电影数据文件获取
# 读取电影数据
movie = pd.read_csv("./dataset/movie.csv")
(3)判断缺失值是否存在
#2.判断某列(的某个值)是否有缺失值.
pd.isnull(movie_df) #判断df对象的 每列的 每个值 是否为空(缺失值)
pd.notnull(movie_df) #判断df对象的 每列的 每个值 是否不为空(非缺失值)#3.判断某列是否是 包含缺失值的列。
np.all(pd.notnull(movie_df))#整列都是True->结果是True,但凡有False-> 结果是False,说明该列有缺失
- pd.notnull()
pd.notnull(movie)Rank Title Genre Description Director Actors Year Runtime (Minutes) Rating Votes Revenue (Millions) Metascore
0 True True True True True True True True True True True True
1 True True True True True True True True True True True True
2 True True True True True True True True True True True True
3 True True True True True True True True True True True True
4 True True True True True True True True True True True True
5 True True True True True True True True True True True True
6 True True True True True True True True True True True True
7 True True True True True True True True True True False True
- np.all(pd.notnull(movie))
- pd.isnull()
(4)存在缺失值nan,并且是np.nan
- 1- 删除
pandas删除缺失值,使用dropna的前提是,缺失值的类型必须是np.nan
# 不修改原数据 加入inplace=True 即可,默认删:axis=0,删行,axis=1,删列.
movie.dropna()# 可以定义新的变量接受或者用原来的变量名
data = movie.dropna()# movie_df.dropna(axis=0) #删行
movie_df.dropna(axis=1) #删列
获取空值行 => ① row_with_null = movie.isnull().any(axis=1) ② moive[row_with_null]
- 2- 替换缺失值
# 替换存在缺失值的样本的两列
# 替换填充平均值,中位数movie['Revenue (Millions)'].fillna(movie['Revenue (Millions)'].mean(), inplace=True)
替换所有缺失值:
#5.1 获取每个列名
for col_name in movie.columns:#5.2判断某列是否有缺失值#movie_df[col_name]: 根据列名,找到 df中的菜个列 ->Series对象.#pd.notnull(某列数据):判断该列的每个值是否为非缺失值,True >不为空,FalLse >为空(缺失值)# np.all([True,False...]):里边的值全部为True > 结果为True,只要有一个为False >结果为False.if np.all(pd.notnull(movie[col_name])) == False:#5.3 走到这里,说明该列有缺失值。print(col_name)#打印列名#5.4打印这两列的平均值。print(movie[col_name].mean())#5.5 用该列的平均值来填充该列的缺失值,movie[col_name].fillna(movie[col_name].mean(), inplace=True)movie.info
(5)不是缺失值nan,有默认标记的(?)
数据是这样的:
wis = pd.read_csv("https://archive.ics.uci.edu/ml/machine-learning-databases/breast-cancer-wisconsin/breast-cancer-wisconsin.data")
以上数据在读取时,可能会报如下错误:
URLError: <urlopen error [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:833)>
解决办法:
# 全局取消证书验证
import ssl
ssl._create_default_https_context = ssl._create_unverified_context
# 尝试直接删除缺失值
wis.dropna() #?不是缺失值,所以直接删,删不掉。
处理思路分析:
- 1、先替换‘?’为np.nan
- df.replace(to_replace=, value=)
- to_replace:替换前的值
- value:替换后的值
- df.replace(to_replace=, value=)
# 把一些其它值标记的缺失值,替换成np.nan
wis = wis.replace(to_replace='?', value=np.nan)
- 2、在进行缺失值的处理
# 删除
wis = wis.dropna()
(6)小结
- isnull、notnull判断是否存在缺失值【知道】
- np.any(pd.isnull(movie)) # 里面如果有一个缺失值,就返回True
- np.all(pd.notnull(movie)) # 里面如果有一个缺失值,就返回False
- dropna删除np.nan标记的缺失值【知道】
- movie.dropna()
- fillna填充缺失值【知道】
- movie[i].fillna(value=movie[i].mean(), inplace=True)
- replace替换具体某些值【知道】
- wis.replace(to_replace="?", value=np.NaN)
九、高级处理-数据合并
(1)学习目标
- 应用pd.concat实现数据的合并 => union
- 应用pd.merge实现数据的合并 => join(行合并)
(2)pd.concat实现数据合并
- pd.concat([data1, data2], axis=1)
- 按照行或列进行合并,axis=0为列索引,axis=1为行索引
# 按照行索引进行
pd.concat([data, dummies], axis=1)
(3)pd.merge
- pd.merge(left, right, how='inner', on=None)
- 可以指定按照两组数据的共同键值对合并或者左右各自
left: DataFrameright: 另一个DataFrameon: 指定的共同键- how:按照什么方式连接
| Merge method | SQL Join Name | Description |
|---|---|---|
left |
LEFT OUTER JOIN |
Use keys from left frame only |
right |
RIGHT OUTER JOIN |
Use keys from right frame only |
outer |
FULL OUTER JOIN |
Use union of keys from both frames |
inner |
INNER JOIN |
Use intersection of keys from both frames |
内连接:
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

right

默认内连接
inner_result = pd.merge(left, right, on=['key1', 'key2'])

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

右连接
right_result = pd.merge(left, right, how='right', on=['key1', 'key2'])

满 外连接
outer_result = pd.merge(left, right, how='outer', on=['key1', 'key2'])

(4)小结
- pd.concat([数据1, 数据2], axis=**)【知道】
- pd.merge(left, right, how=, on=)【知道】
- how -- 以何种方式连接
- on -- 连接的键的依据是哪几个
十、高级处理-数据分组
(1)数据准备
- 加载优衣库的销售数据集,包含了不同城市优衣库门店的所有产品类别的销售记录,数据字段说明如下
- store_id 门店随机id
- city 城市
- channel 销售渠道 网购自提 门店购买
- gender_group 客户性别 男女
- age_group 客户年龄段
- wkd_ind 购买发生的时间(周末,周间)
- product 产品类别
- customer 客户数量
- revenue 销售金额
- order 订单数量
- quant 购买产品的数量
- unit_cost 成本(制作+运营)
# 导包 加载数据集
import pandas as pd
df = pd.read_csv('../数据集/uniqlo.csv')
(2)groupby分组聚合
#agg Aggregate(聚合的意思)
#格式:df.groupby(['分组字段1',‘分组字段2'...1.ag9('列名1':聚合函数名",‘列名2":聚合函数名'...)
-
1- df.groupby分组函数返回分组对象
【基于一列进行分组】
# 基于顾客性别分组
gs = df.groupby(['gender_group'])
# df.groupby('gender_group') #细节:如果分组列只有1个,中括号可以省略不写,
gs
gs['city']
# 返回结果如下
<pandas.core.groupby.generic.DataFrameGroupBy object at 0x000001B1DA988B80>
<pandas.core.groupby.generic.SeriesGroupBy object at 0x000001B1DB2B4FA0>
【基于多列进行分组】
# 基于顾客性别、不同城市分组
gs2 = df.groupby(['gender_group', 'city'])
gs2
# 返回结果如下
<pandas.core.groupby.generic.DataFrameGroupBy object at 0x000001B1DB24F1F0>
-
2- 分组后获取各个组内的数据
- 2.1 取出每组第一条或最后一条数据
gs2 = df.groupby(['gender_group', 'channel']) gs2.first() # 取出每组第一条数据 gs2.last() # 取出每组最后一条数据- 2.2 - 按分组依据获取其中一组
gs2.get_group(('Female', '线上'))![image-20260801195516663]()
-
3- 分组聚合
- 格式:分组后对多列分别使用不同的聚合函数
df.groupby(['列名1', '列名2']).agg({'指定列1':'聚合函数名', '指定列2':'聚合函数名', '指定列3':'聚合函数名' })- 按城市和线上线下划分,分别计算销售金额的平均值、成本的总和
df.groupby(['city', 'channel']).agg({'revenue':'mean', 'unit_cost':'sum' })![image-20260801195656203]()
(3)分组过滤操作
- 格式:
df.groupby(['列名1',...]).filter(lambda x: d osomething returun True or False
)
案例: 按城市分组,查询每组销售金额平均值大于200的全部数据
df.groupby(['city']).filter(lambda s: s['revenue'].mean() > 200)
df.groupby(['city'])['revenue'].filter(lambda s: s.mean() > 200)
十一、高级处理-交叉表与透视表
(1)学习目标
- 应用crosstab和pivot_table实现交叉表与透视表
(2)交叉表与透视表有什么作用?
-
交叉表:
交叉表用于计算一列数据对于另外一列数据的分组个数(用于统计分组频率的特殊透视表)
- pd.crosstab(value1, value2)
-
透视表:
透视表是将原有的DataFrame的列分别作为行索引和列索引,然后对指定的列应用聚集函数
- data.pivot_table()
- DataFrame.pivot_table([], index=[])
(3)交叉表
import pandas as pd# 创建一个示例数据集
data = {'性别': ['男', '女', '男', '女', '男', '女', '女', '男'],'购买': ['是', '否', '是', '是', '否', '否', '是', '否']
}df = pd.DataFrame(data)# 创建交叉表
crosstab = pd.crosstab(df['性别'], df['购买'])
print(crosstab)购买 否 是
性别
女 2 2
男 2 2
(4)透视表(用来简化分组写法)
import pandas as pddata = {'性别': ['男', '女', '男', '女', '男', '女'],'购买': ['是', '否', '是', '是', '否', '否'],'金额': [100, 150, 200, 130, 160, 120]
}
df = pd.DataFrame(data)# 创建透视表
pivot_table = pd.pivot_table(df, values='金额', index='性别', columns='购买', aggfunc='mean')
print(pivot_table)购买 否 是
性别
女 135.0 130.0
男 180.0 150.0
十二、案例分析
(1)数据准备
- 准备两列数据,星期数据以及涨跌幅是好是坏数据
- 进行交叉表计算
# 寻找星期几跟股票张得的关系
# 1、先把对应的日期找到星期几
date = pd.to_datetime(data.index).weekday
data['week'] = date# 2、假如把p_change按照大小去分个类0为界限
data['posi_neg'] = np.where(data['p_change'] > 0, 1, 0)# 通过交叉表找寻两列数据的关系
count = pd.crosstab(data['week'], data['posi_neg'])
但是我们看到count只是每个星期日子的好坏天数,并没有得到比例,该怎么去做?
- 对于每个星期一等的总天数求和,运用除法运算求出比例
# 算数运算,先求和
sum = count.sum(axis=1).astype(np.float32)# 进行相除操作,得出比例
pro = count.div(sum, axis=0)
(2)查看效果
使用plot画出这个比例,使用stacked的柱状图
pro.plot(kind='bar', stacked=True)
plt.show()
(3)使用pivot_table(透视表)实现
使用透视表,刚才的过程更加简单
# 通过透视表,将整个过程变成更简单一些
data.pivot_table(['posi_neg'], index='week')
(4)小结
- 交叉表与透视表的作用【知道】
- 交叉表:计算一列数据对于另外一列数据的分组个数
- 透视表:指定某一列对另一列的关系






