Pandas

📅 2026/8/3 20:26:21 👁️ 阅读次数 📝 编程学习
Pandas

Pandas

一、Pandas介绍

Python在数据处理上独步天下:代码灵活、开发快速;尤其是Python的Pandas包,无论是在数据分析领域、还是大数据开发场承中都具有显著的优势:

  • Pandas是Python的一个第三方包,也是商业和工程领域最流行的结构化数据工具集,用于数据清洗、处理以及分析
  • Pandas在数据处理上具有独特的优势:
    • 底层是基于Numpy构建的,所以运行速度特别的快
    • 有专门的处理缺失数据(处理思路:删,填)的API
    • 强大而灵活的分组、聚合、转换功能

image-20260715160236612

适用场景:

  • 数据量大到Excel严重卡顿,且又都是单机数据的时候,我们使用Pandas

    • Pandas用于处理单机数据(小数据集(相对于大数据来说)

      image-20260715160353660

  • 在大数据ETL数据仓库中,对数据进行清洗及处理的环节使用Pandas

二、Pandas数据结构与数据类型

image-20260715163228317

image-20260715163603599

Pandas中 没有行的概念

image-20260715163825399

(1)Series对象

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

image-20260716170906681

  • 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

image-20260717111413807

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

image-20260717113432525

#场景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

image-20260717113758066

#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

image-20260717171418837

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()
    

image-20260717174233251

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()

image-20260718173208807

(2)索引操作

1. 直接使用行列索引(先列后行)

获取'2018-02-27'这天的'close'的结果

# 直接使用行列索引名字的方式(先列后行)
data['open']['2018-02-27']
# 23.53# 不支持的操作  尝试用,先行后列
# 错误
data['2018-02-27']['open']
# 错误
data[:1, :2]

2. 结合loc或者iloc使用索引

image-20260718173801225

获取从'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()  # 查看各列的描述性统计信息

image-20260723172634764

(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的形式输出
      • 'index' : dict like {index -> {column -> value}}

        • index 以index:{columns:values}...的形式输出
      • 'columns' : dict like {column -> {index -> value}}

        ,默认该格式

        • colums 以columns:{index:values}的形式输出
      • '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()

image-20260728210725793

(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

image-20260728210900752

  • 方式二: 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[起始行下标:结束行下标:步长] , 遵循顾头不顾尾原则(包含起始行,不包含结束行),步长默认为1

    df4 = 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参数默认为False
    
    df2.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:不替换修改原数据,生成新的对象
  • 如果缺失值没有使用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:替换后的值
# 把一些其它值标记的缺失值,替换成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: DataFrame
    • right: 另一个DataFrame
    • on: 指定的共同键
    • 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

image-20260801191315657

right

image-20260801191329759

默认内连接

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

image-20260801191416413

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

image-20260801191529532

右连接

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

image-20260801191541403

满 外连接

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

image-20260801191552464

(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)小结

  • 交叉表与透视表的作用【知道】
    • 交叉表:计算一列数据对于另外一列数据的分组个数
    • 透视表:指定某一列对另一列的关系