0


pandas

Pandas

文件读写

读取

  • pd.read_csv() 读取csv
  • pd.read_excel()读取excel
  • pd.read_txt() 读取文本文档
公共参数:
    header=None  从第几行开始读取
    index_col  指定行索引
    usecols  读取那几列 
    parse_dates  把给出的列转化为时间序列 
    nrows 读取的行数

在读取txt文件时经常遇到分隔符不是空格,read_table()有一个分隔参数叫sep自定义分隔符(可以写正则表达式)

写入

***一般在写入时把

index

设置为

False

,当索引没有使用意义时就要去掉***

普通写入
    to_csv  
    to_excel

以下需要安装tabulate包  
    to_markdown  
    to_latex

基本数据结构

Series

​ 是 一维 的数据结构

pd.Series(data,index,dtype,name)
参数:
    data = 值
    index = 索引
    dtype = 存储类型
    name = 序列名字
#示例
pd.Series(data =[100,'a',{'dict':5}],
          index = pd.Index(['id1',20,'thrid'],
              name='my_index'),
          dtype='object', 
          name ='my_name')
my_index
id1              10020                 a
thrid    {'dict':5}
Name: my_name, dtype:object

object类型

代表一种混合类型,目前pandas把 字符串数组 认为是object类型

Dataframe

​ 相当于 二维 数组,由Series组成

data =[[1,'a',1.2],[2,'b',2.2],[3,'c',3.2]]
df = pd.DataFrame(data=data,
                index =['row_%d'%i for i inrange(3)],
                columns=['col_0','col_1','col_2'])print(df)
       col_0 col_1  col_2
row_0      1     a    1.2
row_1      2     b    2.2
row_2      3     c    3.2

属性

  • df.values 查看值
  • df.index 查看行索引
  • df.dtypes 查看每列的类型
  • df.shape 查看形状维度
  • df.T转置

常用基本函数

  • df.head(n) 查看数据的n行
  • df.tail(n) 查看数据的n行
  • df.info() 返回表的信息概况(如果有中文会报错)
  • df.describe(n)汇总统计函数

统计函数

  • df.std() 标准差
  • df.var() 方差
  • df.corr() 于原始DataFrame列与列之间相关性的DataFrame对象。
  • df.quantile() 分位数 - 所谓四分位数;即把数值由小到大排列并分成四等份,处于三个分割点位置的数值就是四分位数。- 第1四分位数 (Q1),又称“较小四分位数”,等于该样本中所有数值由小到大排列后第25%的数字。- 第2四分位数 (Q2),又称“中位数”,等于该样本中所有数值由小到大排列后第50%的数字。- 第3四分位数 (Q3),又称“较大四分位数”,等于该样本中所有数值由小到大排列后第75%的数字。
  • df.count()非缺失值个数
  • df.idxmax() 最大值对应的索引

唯一值函数

  • df.unique()去掉重复值的数据输出
  • df.nunique() 数据中唯一数据的个数
  • df.value_counts() 得到重复值的数据和他出现的频数
  • df.drop_duplicates()多列去重- '''df.drop_duplicates参数 subset: 列名,可选,默认为None keep: {‘first’, ‘last’, False}, 默认值 ‘first’ first: 保留第一次出现的重复行,删除后面的重复行。 last: 删除重复项,除了最后一次出现。 False: 删除所有重复项。 inplace:布尔值,默认为False,是否直接在原数据上删除重复项或删除重复项后返回副本。(inplace=True表示直接在原来的DataFrame上删除重复项,而默认值False表示生成一个副本。)'''- df.duplicated()返回是否为唯一值的布尔列表,参数与drop_duplicates一致,如果元素是重复的都会标上True,否则False,drop_duplicates等价于把duplicated为True的对应行删除

替换函数

pandas中可以分为三类:

  映射替换,逻辑替换,数值替换

映射替换

  • df.replace(old, new[, max])- - old -- 将被替换的子字符串。- new -- 新字符串,用于替换old子字符串。- max -- 可选字符串, 替换不超过 max 次 可以直接给予 字典 来替换数据
  • 特殊方向替换- 指定method = ffill/bfill- 用 前面最近的未被替换掉 的值进行替换 用 后面最近的未被替换掉 的值进行替换
s = pd.Series(['a',1,'b',2,1,1,'a'])print('ffill:\n',s.replace([1,2],method='ffill'))print('\nbfill:\n',s.replace([1,2],method='bfill'))
ffill:0    a
1    a
2    b
3    b
4    b
5    b
6    a
dtype:object

bfill:0    a
1    b
2    b
3    a
4    a
5    a
6    a
dtype:object

逻辑替换

  • df.where(condition) 传入条件为 False 的对应进行替换
  • df.mask(condition) 传入条件为 True 的对应进行替换

传入的条件也可以是Serise对象,只要是序列一致的布尔序列即可

s_condition = pd.Series([True,False,False,True],index=s.index)
s.mask(s_condition,0)
00.0000011.234562100.0000030.00000
dtype: float64

数值替换

  • df.round(n) 返回小数位为n位的四舍五入的float值
  • df.abc() 取绝对值
  • df.clip(lower, upper, axis, inplace)- lower : float或array_like,默认为None 最小阈值。低于此阈值的所有值都将设置为它upper : float或array_like,默认为None 最大阈值。高于此阈值的所有值都将设置为它axis : int或string轴名称,可选 沿给定轴将对象与下部和上部对齐inplace : 布尔值,默认为False 是否对数据执行操作

排序函数

  • sort_values() 值排序

被排序的列可以是列表来进行多列排序

print('年龄用降序排序,工资用升序排序')print(s.head().sort_values(['年龄','工资(元)'],ascending=[False,True]))#因为在实操种可能有一些数据相同,索引就需要多列排序的操作,排在前面的先拍
年龄用降序排序,工资用升序排序
   序号   姓名  年龄  工资(元)
1   2   黄丽  32   3600
0   1   张茜  28   2900
4   5  曾丽萍  27   2500
3   4  邓大海  26   2200
2   3  李海涛  24   2800
  • sort_index() 索引排序

可以先指定索引列(level),字符串排序由字母顺序决定

print('以名字进行索引升序排序\n')
s.head().sort_index(level='姓名',ascending=True)#看得出来是A-Z是升序,Z-A是降序
以名字进行索引升序排序

序号    姓名    年龄    工资(元)
01    张茜    28290012    黄丽    32360023    李海涛    24280034    邓大海    26220045    曾丽萍    272500

apply方法

​ apply用与DataFrame的 行迭代列迭代

  • DataFrame.apply(func,axis,raw,result_type)- func: 应用于每一列或每一行的函数。 axis: {0 或 'index',1 或 'columns'},默认 0 沿其应用函数的轴: 0 或“索引”:将函数应用于每一列。 1 或“列”:将函数应用于每一行。 raw: 布尔值,默认为 False 确定行或列是否作为 Series 或 ndarray 对象传递: False: 将每一行或每一列作为一个系列传递给函数。 True:传递的函数将接收 ndarray 对象。如果您只是应用NumPy 缩减功能,这将获得更好的性能。 result_type {'expand', 'reduce', 'broadcast','None'},默认无 axis=1这些仅在(列)时起作用: 'expand' : 类似列表的结果将变成列。 'reduce' :如果可能,返回一个系列,而不是扩展类似列表的结果。这与“扩展”相反。 'broadcast' : 结果将被广播到DataFrame的原始形状,原始索引和列将被保留。 默认行为(None)取决于应用函数的返回值:类似列表的结果将作为这些结果的系列返回。但是,如果应用函数返回一个系列,这些将扩展为列。
df_demo = s[['年龄','工资(元)']]#先把需要遍历的列或行提取出来print('不用apply函数的平均值:\n',df_demo.mean())deffunc(x):
    res = x.mean()return res

print('\n使用了apply函数的平均值\n',df_demo.apply(func,axis=1))
不用apply函数的平均值:
 年龄         30.763889
工资(元)    3059.722222
dtype: float64

使用了apply函数的平均值
 0     1464.0
1     1816.0
2     1412.0
3     1113.0
4     1263.5
       ...  
67    1919.0
68    1617.0
69    1263.0
70    1917.5
71    2273.0
Length: 72, dtype: float64

apply的自由度很高但是代价是性能,所以一般少用apply

mad

​ **

mad

函数返回的是一个序列中偏离该序列均值的绝对值大小的均值**

例如序列1,3,7,10中,均值为5.25,每一个元素偏离的绝对值为4.25,2.25,1.75,4.75,这个偏离序列的均值为3.25。

print('mad函数输出\n',df_demo.mad())print('\n使用apply输出\n',df_demo.apply(lambda x:(x-x.mean()).abs().mean()))
mad函数输出
 年龄         5.515432
工资(元)    600.231481
dtype: float64

使用apply输出
 年龄         5.515432
工资(元)    600.231481
dtype: float64

窗口对象

​ 滑动窗口rolling 扩张窗口expanding 指数加权窗口ewm

滑动窗口

rolling

​ 滑动窗口将window参数设置为多少,就从源数据第一个元素向左边数 window参数-1(因为包括它本身) 然后进行运算,以此向后推

num5 = pd.Series([1,2,3,4,5,6])
roller = num5.rolling(window=2)print(roller.sum())'''
    当窗口为2时,从第一个源数据元素向左数 window-1 个位 就是1个位
    因为0索引左边没有任何数[本位数据为1],所以为缺失值(任何数与缺失值作运算都是缺失值)
    因为1索引向左边数是1(源数据)[本位数据为2],所以求和为3
    因为2索引向左边数是2(源数据)[本位数据为3],所以为5
'''
0     NaN
13.025.037.049.0511.0
dtype: float64

另类窗口函数

​ 他们的公共参数:periods=n

  • shift 向左取第n个元素的值
#shift:取向左第n个元素的值
num5 = pd.Series([1,3,6,10,15])print('shift:\n',num5.shift(periods=2))print('\n特殊用法(取负数)\n',num5.shift(-1))
shift:0    NaN
1    NaN
21.033.046.0
dtype: float64

特殊用法(取负数)03.016.0210.0315.04     NaN
dtype: float64
  • diff 与向左第n个元素做差(与numpy不同,后者表示n阶差分)
#diff:向左取n个元素做差
num5 = pd.Series([1,3,6,10,15])print('diff:\n',num5.diff(2))print('\n特殊用法(取负数):\n',num5.diff(-2))
diff:0    NaN
1    NaN
25.037.049.0
dtype: float64

特殊用法(取负数):0-5.01-7.02-9.03    NaN
4    NaN
dtype: float64
  • pct_change 与向左第n个元素相比计算增长量(n可以为负,表示反方向的类似操作)
#pct_change:与向左第n个元素相比计算增长量
num5 = pd.Series([1,3,6,10,15])print('pct_change:\n',num5.pct_change(2))print('\n特殊用法(取负数):\n',num5.pct_change(-2))
pct_change:0         NaN
1         NaN
25.00000032.33333341.500000
dtype: float64

特殊用法(取负数):0-0.8333331-0.7000002-0.6000003         NaN
4         NaN
dtype: float64

另类滑窗函数也可以用rolling函数来实现

扩展窗口

expanding

​ 累计窗口函数,与滑动窗口不同的是他的窗口会动态增大,从第一个开始向右边平移n个元素进行计算

num5 = pd.Series([1,3,6,10,15])
num5.expanding().mean()
01.00000012.00000023.33333335.00000047.000000
dtype: float64

索引器

基本索引

行索引

​ 一般的索引都是中括号

['列名']

来索引内容,结果返回Serise(参数<=1时**),如果**参数>1就返回DataFrame

#读取文件
df = pd.read_csv('C:\\Users\\Yuan\\Desktop\\pandas\\文件\\data\\learn_pandas.csv',usecols =['School','Grade','Name','Gender','Weight','Transfer'])
df['Name'].head()
0      Gaopeng Yang
1    Changqiang You
2           Mei Sun
3      Xiaojuan Sun
4       Gaojuan You
Name: Name, dtype:object

 此外,若要取出单列,且列名中不包含空格,则可以用 **

.列名

** 取出,这和 [列名] 是等价的:

列索引

 如果取出单个索引对应的元素,可以使用

[index]

,若

Series

只有单个值对应,则返回这个标量值,如果有多个值对应,则返回一个

Series
s = pd.Series([1,2,3,4,5,6],
            index=['a','b','a','a','a','c'])
s
a    1
b    2
a    3
a    4
a    5
c    6
dtype: int64
索引切片

​ 如果想要取出某两个索引之间的元素,并且这两个索引是在整个索引中 唯一出现 ,就可以使用 切片 (注意:索引切片会包含两个端点 )

s['c':'b':-2]
c    6
a    4
b    2
dtype: int64

如果前后端点的值存在 重复 ,即 非唯一值 ,那么需要经过 排序 才能使用切片

#错误案例try:
    s['a','b']except Exception as e:
    Err_Msg = e

Err_Msg
KeyError('key of type tuple not found and not a MultiIndex')

​ 如果使用整数切片,则会取出对应索引

位置

的值,注意这里的整数切片同 Python 中的切片一样 不包含右端点

s[1:-1:2]
b    2
a    4
dtype: int64

提示:

​ 如果不想陷入麻烦,那么请不要把纯浮点以及任何混合类型(字符串、整数、浮点类型等的混合作为索引,否则可能会在具体的操作时报错或者返回非预期的结果,并且在实际的数据分析中也不存在这样做的动机。

loc索引器

​ 是一种基于 元素 的索引器

  • 语法:df.loc[*,*]- 第一个 *代表行的选择,第二个 * 代表列的选择,如果省略第二个位置写作 loc[ * ] ,这个 * 是指行的筛选- 其中, * 的位置一共有五类合法对象​ 分别是:单个元素、元素列表、元素切片、布尔列表以及函数
df = pd.read_csv('C:\\Users\\Yuan\\Desktop\\pandas\\文件\\data\\learn_pandas.csv',usecols =['School','Grade','Name','Gender','Weight','Transfer'])
df.head()

SchoolGradeNameGenderWeightTransfer0Shanghai Jiao Tong UniversityFreshmanGaopeng YangFemale46.0N1Peking UniversityFreshmanChangqiang YouMale70.0N2Shanghai Jiao Tong UniversitySeniorMei SunMale89.0N3Fudan UniversitySophomoreXiaojuan SunFemale41.0N4Fudan UniversitySophomoreGaojuan YouMale74.0N

行和列

df_demo.loc['Qiang Sun','School']# 返回Series,因为第一个是索引列
Name
Qiang Sun              Tsinghua University
Qiang Sun              Tsinghua University
Qiang Sun    Shanghai Jiao Tong University
Name: School, dtype:object
df_demo.loc['Quan Zhao','School']# 返回单个元素
'Shanghai Jiao Tong University'

元素列表

df_demo.loc[['Qiang Sun','Quan Zhao'],['School','Gender']]#dataframe

SchoolGenderNameQiang SunTsinghua UniversityFemaleQiang SunTsinghua UniversityFemaleQiang SunShanghai Jiao Tong UniversityFemaleQuan ZhaoShanghai Jiao Tong UniversityFemale

切片

​ Series 使用字符串索引时提到,如果是唯一值的起点和终点字符,那么就可以使用切片,并且包含两个端点,如果不唯一则报错

#两个端点都包含
df_demo.loc['Gaojuan You':'Gaoqiang Qian','School':'Gender']

SchoolGradeGenderNameGaojuan YouFudan UniversitySophomoreMaleXiaoli QianTsinghua UniversityFreshmanFemaleQiang ChuShanghai Jiao Tong UniversityFreshmanFemaleGaoqiang QianTsinghua UniversityJuniorFemale
​ 需要注意的是,如果

DataFrame

使用整数索引,其使用整数切片的时候和上面字符串索引的要求一致,都是 元素 切片,包含两个端点、端点不允许有重复值

df_loc_slice_demo = df_demo.copy()# 复制下来
df_loc_slice_demo.index =range(df_demo.shape[0],0,-1)#把所以设置为全部元素记录数的降序
df_loc_slice_demo.loc[5:3]# 定位器切片,两个端点都包含
School    Grade    Gender    Weight    Transfer
5    Fudan University    Junior    Female    46.0    N
4    Tsinghua University    Senior    Female    50.0    N
3    Shanghai Jiao Tong University    Senior    Female    45.0    N
df_loc_slice_demo.loc[3:5]# 没有返回,说明不是整数位置切片,要根据索引排序来切片
School    Grade    Gender    Weight    Transfer

布尔索引

​  传入 **

loc

** 的布尔列表与

DataFrame

长度相同,且列表为 **

True

** 的位置所对应的行会被选中, **

False

** 则会被剔除

# 选出体重超过70kg的学生
df_demo.loc[df_demo.Weight>70].head()

SchoolGradeGenderWeightTransferNameMei SunShanghai Jiao Tong UniversitySeniorMale89.0NGaojuan YouFudan UniversitySophomoreMale74.0NXiaopeng ZhouShanghai Jiao Tong UniversityFreshmanMale74.0NXiaofeng SunTsinghua UniversitySeniorMale71.0NQiang ZhengShanghai Jiao Tong UniversitySeniorMale87.0N

  • 传入元素列表,也可以通过 isin 方法返回的布尔列表等价写出
# 选出所有大一和大四的同学信息
df_demo.loc[df_demo.Grade.isin(['Freshman','Senior'])].head()#isin是dataframe的一个方法

SchoolGradeGenderWeightTransferNameGaopeng YangShanghai Jiao Tong UniversityFreshmanFemale46.0NChangqiang YouPeking UniversityFreshmanMale70.0NMei SunShanghai Jiao Tong UniversitySeniorMale89.0NXiaoli QianTsinghua UniversityFreshmanFemale51.0NQiang ChuShanghai Jiao Tong UniversityFreshmanFemale52.0N

  • 对于复合条件而言,可以用 |(或), &(且), ~(取反) 的组合来实现
#选出复旦大学中体重超过70kg的大四学生,或者北大男生中体重超过80kg的非大四的学生
school1 = df_demo.School =='Fudan University'
grade1 = df_demo.Grade =='Senior'
weight1 = df_demo.Weight >70
FD = school1 & grade1 & weight1

school2 = df_demo.School =='Peking University'
grade2 = df_demo.Grade =='Senior'
weight2 = df_demo.Weight >80
BD = school2 &(~grade2)& weight2 # (~grade2)这里是取反

df_demo.loc[FD | BD]

SchoolGradeGenderWeightTransferNameQiang HanPeking UniversityFreshmanMale87.0NChengpeng ZhouFudan UniversitySeniorMale81.0NChangpeng ZhaoPeking UniversityFreshmanMale83.0NChengpeng QianFudan UniversitySeniorMale73.0Y

select_dtypes

  • DataFrame.select_dtypes参数:​ include : 标量(类型)​ exclude : 列表标量或类似列表的内容,包括/排除 的dtypes或字符串的选择。必须至少提供这些参数之一
* 要选择所有数字类型,请使用np.number或'number'

* 要选择字符串,您必须使用objectdtype,但请注意,这将返回所有object dtype 列

* 查看numpy dtype 层次结构

* 要选择日期时间,请np.datetime64使用'datetime'或 'datetime64'  
* 要选择时间增量,请np.timedelta64使用'timedelta'或 'timedelta64'  

* 要选择 Pandas 分类数据类型,请使用'category'  

* 要选择 Pandas datetimetz dtypes,请使用'datetimetz'(0.20.0 中的新功能)或'datetime64[ns, tz]'  
df_demo.select_dtypes(include=['float64','object']).head()

SchoolGradeGenderWeightTransferNameGaopeng YangShanghai Jiao Tong UniversityFreshmanFemale46.0NChangqiang YouPeking UniversityFreshmanMale70.0NMei SunShanghai Jiao Tong UniversitySeniorMale89.0NXiaojuan SunFudan UniversitySophomoreFemale41.0NGaojuan YouFudan UniversitySophomoreMale74.0N

字符串dtypes是不允许的,使用’object’代替

函数

​  必须以前面的四种合法形式之一为返回值,并且函数的输入值为DataFrame本身(支持使用 lambda 表达式)

defcondition(x):
    condition_1_1 = x.School =='Fudan University'
    condition_1_2 = x.Grade =='Senior'
    condition_1_3 = x.Weight >70
    condition_1 = condition_1_1 & condition_1_2 & condition_1_3

    condition_2_1 = x.School =='Peking University'
    condition_2_2 = x.Grade =='Senior'
    condition_2_3 = x.Weight >80
    condition_2 = condition_2_1 &(~condition_2_2)& condition_2_3# (~condition_2_2) 取反

    result = condition_1 | condition_2
    return result

df_demo.loc[condition]

SchoolGradeGenderWeightTransferNameQiang HanPeking UniversityFreshmanMale87.0NChengpeng ZhouFudan UniversitySeniorMale81.0NChangpeng ZhaoPeking UniversityFreshmanMale83.0NChengpeng QianFudan UniversitySeniorMale73.0Y

  • slice() 返回切片对象,主要作用在切片操作函数里的参数传递,由于函数无法返回(如 start: end: step )的切片形式,故返回切片时要用 slice 对象进行包装
df_demo.loc[lambda x:slice('Gaojuan You','Gaoqiang Qian')]#start:end:step

SchoolGradeGenderWeightTransferNameGaojuan YouFudan UniversitySophomoreMale74.0NXiaoli QianTsinghua UniversityFreshmanFemale51.0NQiang ChuShanghai Jiao Tong UniversityFreshmanFemale52.0NGaoqiang QianTsinghua UniversityJuniorFemale50.0N

对于 Series 也可以使用 loc 索引,其遵循的原则与 DataFrame 中用于行筛选的 loc[*] 完全一致

SettingWithCopyWarning

 在对表或者序列赋值时,应当在使用一层索引器后直接进行赋值操作,这样做是由于进行多次索引后赋值是赋在临时返回的 copy 副本上的,而没有真正修改元素从而报出

SettingWithCopyWarning

警告。

df_chain[df_chain.A!=0].B =1'''
   这样使用会出问题的原因就是索引后数据在内存中
   再去直接调用属性并赋值pandas就会报出警告并且'不执行'这个语句
   但是可以使用索引器来达到这个目的
'''
C:\Python310\lib\site-packages\pandas\core\generic.py:5516: SettingWithCopyWarning: 
A value is trying to be set on a copy of a slicefrom a DataFrame.
Try using .loc[row_indexer,col_indexer]= value instead

See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy
  self[name]= value

​ 但是可以使用索引器来达到这个目的

df_chain.loc[df_chain.A!=0,'B']=1
df_chain
    A    B
0001112-11

iloc索引器

针对位置进行筛选/查找,在相应的 * 位置处一共也有五类合法对象,分别是:整数、整数列表、整数切片、布尔列表以及函数,函数的返回值必须是前面的四类合法对象中的一个,其输入同样也为

DataFrame

本身

df_demo.iloc[1,1]# 第二行第二列
'Freshman'
df_demo.iloc[[0,1],[0,1]]# 前两行前两列

SchoolGradeNameGaopeng YangShanghai Jiao Tong UniversityFreshmanChangqiang YouPeking UniversityFreshman

  • 切片不包含结束端点
df_demo.iloc[1:4,2:4]# 切片不包含结束端点

GenderWeightNameChangqiang YouMale70.0Mei SunMale89.0Xiaojuan SunFemale41.0

  • 传入切片为返回值的函数
df_demo.iloc[lambda x:slice(1,4)]

SchoolGradeGenderWeightTransferNameChangqiang YouPeking UniversityFreshmanMale70.0NMei SunShanghai Jiao Tong UniversitySeniorMale89.0NXiaojuan SunFudan UniversitySophomoreFemale41.0N

  • 布尔列表​ 在使用布尔列表的时候要特别注意,不能传入 Series 而必须传入序列的 values,否则会报错。因此,在使用布尔筛选的时候还是应当优先考虑 loc 的方式
df_demo.iloc[(df_demo.Weight>80).values].head()# .values 将布尔的每个值传入索引器

SchoolGradeGenderWeightTransferNameMei SunShanghai Jiao Tong UniversitySeniorMale89.0NQiang ZhengShanghai Jiao Tong UniversitySeniorMale87.0NQiang HanPeking UniversityFreshmanMale87.0NChengpeng ZhouFudan UniversitySeniorMale81.0NFeng HanShanghai Jiao Tong UniversitySophomoreMale82.0N

Series

而言同样也可以通过 iloc 返回相应位置的值或子序列

query方法

​ pandas可以支持字符串形式传入 **

query

** 方法来查询数据,表达式执行结果必须返回布尔列表

​ 优点:使用query方法可以无需重复使用

DataFrame

的列名来索引,但一般使用的代码长度尽量较少(在不降低可读性的前提下)

df.query('((School == "Fudan University")&'' (Grade == "Senior")&'' (Weight > 70))|''((School == "Peking University")&'' (Grade != "Senior")&'' (Weight > 80))')

SchoolGradeNameGenderWeightTransfer38Peking UniversityFreshmanQiang HanMale87.0N66Fudan UniversitySeniorChengpeng ZhouMale81.0N99Peking UniversityFreshmanChangpeng ZhaoMale83.0N131Fudan UniversitySeniorChengpeng QianMale73.0Y

 在 query 表达式中,自动帮用户注册了所有来自

DataFrame

列名,所有属于该

Series

的方法都可以被调用,和正常的函数调用并没有区别

对于含有空格的列名,需要使用 ‘

col name

’ 的(加引号)方式进行引用。

  • 在 query 中还注册了若干英语的字面用法,帮助提高可读性,例如: or, and, or, is in, not in
df.query('(Grade notin["Freshman","Sophomore"])and(Gender =="Male")').head()

SchoolGradeNameGenderWeightTransfer2Shanghai Jiao Tong UniversitySeniorMei SunMale89.0N16Tsinghua UniversityJuniorXiaoqiang QinMale68.0N17Tsinghua UniversityJuniorPeng WangMale65.0N18Tsinghua UniversitySeniorXiaofeng SunMale71.0N21Shanghai Jiao Tong UniversitySeniorXiaopeng ShenMale62.0NaN

  • 字符串中出现与列表的比较时, ==!= 分别表示元素出现在列表或没有出现在列表,等价于 is innot in
df.query('Grade == ["Junior", "Senior"]').head()

SchoolGradeNameGenderWeightTransfer2Shanghai Jiao Tong UniversitySeniorMei SunMale89.0N7Tsinghua UniversityJuniorGaoqiang QianFemale50.0N9Peking UniversityJuniorJuan XuFemaleNaNN11Tsinghua UniversityJuniorXiaoquan LvFemale43.0N12Shanghai Jiao Tong UniversitySeniorPeng YouFemale48.0NaN

  • 对于 query 中的字符串,如果要引用外部变量,只需在变量名前加 @ 符号
low, high =70,80
df.query('Weight.between(@low, @high)').head()

SchoolGradeNameGenderWeightTransfer1Peking UniversityFreshmanChangqiang YouMale70.0N4Fudan UniversitySophomoreGaojuan YouMale74.0N10Shanghai Jiao Tong UniversityFreshmanXiaopeng ZhouMale74.0N18Tsinghua UniversitySeniorXiaofeng SunMale71.0N35Peking UniversityFreshmanGaoli ZhaoMale78.0N

随机抽样

​ 想要对样本或特征进随机抽样就可以用

sample

函数

sample(n , axis , frac , replace , weights)
    n:抽样数量  
    axis:抽样方向(0为行,1为列)
    frac:抽样比例(1为100%)
    replace:是否放回(True/False)
    weights:每个样本抽样的相对概率
df_sample = pd.DataFrame({'id':list('abcde'),'value':[1,2,3,4,90]})
df_sample

idvalue0a11b22c33d44e90
示例:

df_sample.sample(3, replace =True, weights = df_sample.value)'''
    抽样数量为3,有放回,"weights是把vaolue整列的记录数除以整列的和"
'''

idvalue4e904e904e90

多级索引

多级索引及其表的结构

  • 创建表便于学习
#先创建一个表,用来示例,之后会讲到
np.random.seed(0)
multi_index = pd.MultiIndex.from_product([list('ABCD'),df.Gender.unique()], names=('School','Gender'))# 以笛卡尔积创建行索引
multi_column = pd.MultiIndex.from_product([['Height','Weight'],df.Grade.unique()], names=('Indicator','Grade'))# 以笛卡尔积创建列索引
df_multi = pd.DataFrame(np.c_[(np.random.randn(8,4)*5+163).tolist(),(np.random.randn(8,4)*5+65).tolist()],index = multi_index,columns = multi_column).round(1)#创建表

df_multi
           Indicator    Height                                Weight
        Grade    Freshman    Senior    Sophomore    Junior    Freshman    Senior    Sophomore    Junior
School    Gender                                
    A    Female    171.8165.0167.9174.260.655.163.365.8
        Male    172.3158.1167.8162.271.271.063.163.5
    B    Female    162.5165.1163.7170.359.857.956.574.8
        Male    166.8163.6165.2164.762.562.858.768.9
    C    Female    170.5162.0164.6158.756.963.960.566.9
        Male    150.2166.3167.3159.362.459.164.967.1
    D    Female    174.3155.7163.2162.165.366.561.863.2
        Male    170.7170.3163.8164.961.663.260.956.4

​ 多级索引与单层索引的表一样,具备元素值,行索引,列索引三个部分,行索引和列索引都是**

MultiIndex

类型,只不过索引中的元素是元组型** 而不是单层索引中的标量

  • 索引的 名字和值属性 分别可以通过 namesvalues 获得
df_multi.index.names#名字就是最外层的索引
FrozenList(['School','Gender'])
df_multi.columns.names#名字就是最外层的索引
FrozenList(['Indicator','Grade'])
df_multi.index.values#值属性就是里面内层的索引
array([('A','Female'),('A','Male'),('B','Female'),('B','Male'),('C','Female'),('C','Male'),('D','Female'),('D','Male')],
      dtype=object)
df_multi.columns.values#值属性就是里面内层的索引
array([('Height','Freshman'),('Height','Senior'),('Height','Sophomore'),('Height','Junior'),('Weight','Freshman'),('Weight','Senior'),('Weight','Sophomore'),('Weight','Junior')], dtype=object)
  • 如果想要得到某一层的索引,则需要通过 get_level_values(n)获得
df_multi.index.get_level_values(0)# 里面的参数是层数,以0开始
Index(['A','A','B','B','C','C','D','D'], dtype='object', name='School')

多级索引中的loc索引器

# 先把索引设置成第一列和第二列
df_multi = df.set_index(['School','Grade'])
df_multi.head()

NameGenderWeightTransferSchoolGradeShanghai Jiao Tong UniversityFreshmanGaopeng YangFemale46.0NPeking UniversityFreshmanChangqiang YouMale70.0NShanghai Jiao Tong UniversitySeniorMei SunMale89.0NFudan UniversitySophomoreXiaojuan SunFemale41.0NSophomoreGaojuan YouMale74.0N

  • 由于多级索引中的单个元素以元组为单位,之前介绍的 lociloc 方法可以完全照搬,只需把标量的位置替换成对应的元组
df_sorted = df_multi.sort_index()#先排序
df_sorted.loc[('Fudan University','Junior')].head()
                        Name    Gender    Weight    Transfer
School            Grade                
Fudan University Junior    Yanli You    Female    48.0    N
                Junior    Chunqiang Chu    Male    72.0    N
                Junior    Changfeng Lv    Male    76.0    N
                Junior    Yanjuan Lv    Female    49.0    NaN
                Junior    Gaoqiang Zhou    Female    43.0    N
df_sorted.loc[[('Fudan University','Senior'),('Shanghai Jiao Tong University','Freshman')]].head()
                        Name    Gender    Weight    Transfer
School             Grade                
Fudan University Senior    Chengpeng Zheng    Female    38.0    N
                Senior    Feng Zhou    Female    47.0    N
                Senior    Gaomei Lv    Female    34.0    N
                Senior    Chunli Lv    Female    56.0    N
                Senior    Chengpeng Zhou    Male    81.0    N
df_sorted.loc[df_sorted.Weight >70].head()# 布尔列表也是可用的
                        Name    Gender    Weight    Transfer
School              Grade                
Fudan University Freshman    Feng Wang    Male    74.0    N
                 Junior    Chunqiang Chu    Male    72.0    N
                 Junior    Changfeng Lv    Male    76.0    N
                 Senior    Chengpeng Zhou    Male    81.0    N
                 Senior    Chengpeng Qian    Male    73.0    Y
df_sorted.loc[lambda x:('Fudan University','Junior')].head()
                    Name    Gender    Weight    Transfer
School            Grade                
Fudan University Junior    Yanli You    Female    48.0    N
            Junior    Chunqiang Chu    Male    72.0    N
            Junior    Changfeng Lv    Male    76.0    N
            Junior    Yanjuan Lv    Female    49.0    NaN
            Junior    Gaoqiang Zhou    Female    43.0    N
  • 当使用切片时需要注意,在单级索引中只要切片端点元素是唯一的,那么就可以进行切片,但在多级索引中,无论元组在索引中是否重复出现,都必须经过排序才能使用切片,否则报错
df_sorted.loc[('Fudan University','Senior'):].head()'''
    ('Fudan University', 'Senior')这是一个整体,代表这些行后面的所有内容(:)
'''
                        Name    Gender    Weight    Transfer
School              Grade                
Fudan University Senior    Chengpeng Zheng    Female    38.0    N
                 Senior    Feng Zhou    Female    47.0    N
                 Senior    Gaomei Lv    Female    34.0    N
                 Senior    Chunli Lv    Female    56.0    N
                 Senior    Chengpeng Zhou    Male    81.0    N
df_unique = df.drop_duplicates(subset=['School','Grade']).set_index(['School','Grade'])
df_unique.head()

NameGenderHeightWeightTransferTest_NumberTest_DateTime_RecordSchoolGradeShanghai Jiao Tong UniversityFreshmanGaopeng YangFemale158.946.0N12019/10/50:04:34Peking UniversityFreshmanChangqiang YouMale166.570.0N12019/9/40:04:20Shanghai Jiao Tong UniversitySeniorMei SunMale188.989.0N22019/9/120:05:22Fudan UniversitySophomoreXiaojuan SunFemaleNaN41.0N22020/1/30:04:08Tsinghua UniversityFreshmanXiaoli QianFemale158.051.0N12019/10/310:03:47

df_unique.sort_index().loc[('Fudan University','Senior'):].head()'''
    sort_index()先以索引进行排序
    loc[('Fudan University', 'Senior'):] 定位('Fudan University', 'Senior')这一行后输出这一行和后面所有内容
'''

NameGenderWeightTransferSchoolGradeFudan UniversitySeniorChengpeng ZhengFemale38.0NSophomoreXiaojuan SunFemale41.0NPeking UniversityFreshmanChangqiang YouMale70.0NJuniorJuan XuFemaleNaNNSeniorChangli LvFemale41.0N

  • 可对多层的元素进行交叉组合后索引, 但同时需要指定 loc 的列 ,全选则用 : 表示。其中,每一层需要选中的元素用列表存放,传入 loc 的形式为 [(level_0_list, level_1_list), cols]
res = df_multi.loc[(['Peking University','Fudan University'],['Sophomore','Junior']),:]'''
    ['Peking University', 'Fudan University']与['Sophomore', 'Junior']都是条件,但是必须指定列
    ['Peking University', 'Fudan University']是第一层索引
    ['Sophomore', 'Junior']是第二层索引
'''
res.head()
                        Name    Gender    Weight    Transfer
School                Grade                
Peking University Sophomore    Changmei Xu    Female    43.0    N
                Sophomore    Xiaopeng Qin    Male    NaN    N
                Sophomore    Mei Xu    Female    39.0    N
                Sophomore    Xiaoli Zhou    Female    55.0    N
                Sophomore    Peng Han    Female    34.0    NaN

IndexSlice对象

​ 引入

IndexSlice

对象就能解决对每层进行切片,也允许将切片和布尔列表混合使用这个问题

  • Slice 对象一共有两种形式:​ 第一种为 loc [ idx [ * , * ] ] 型​ 第二种为 loc [ idx [ * , * ] , idx [ * , * ] ]
# 构造一个索引不重复的表来学习
np.random.seed(0)
L1,L2 =['A','B','C'],['a','b','c']
mul_index1 = pd.MultiIndex.from_product([L1,L2],names=('Upper','Lower'))
L3,L4 =['D','E','F'],['d','e','f']
mul_index2 = pd.MultiIndex.from_product([L3,L4],names=('Big','Small'))
df_ex = pd.DataFrame(np.random.randint(-9,10,(9,9)),index=mul_index1,columns=mul_index2)

df_ex
        Big        D            E            F
        Small    d    e    f    d    e    f    d    e    f
Upper    Lower                                    
    A        a    36-9-6-6-209-5
            b    -33-8-3-258-44
            c    -107-466-99-6
    B        a    85-2-9-80-91-6
            b    29-7-9-9-5-4-3-1
            c    86-501-8-8-20
    C        a    -6-3259-95-63
            b    12-5-3-56-63-5
            c    -156-66478-4
  • 为了使用 silce 对象,先要进行定义
idx = pd.IndexSlice
  • loc [ idx [ * , * ] ] 型​ 这种情况并不能进行多层分别切片,前一个 * 表示的选择,后一个 * 表示的选择,与单纯的 loc 是类似的
df_ex.loc[idx['C':,('D','f'):]]'''
    idx:
        'C'行之后的所有
        ('D', 'f')列之后的所有
    如果不加冒号,这两个都会成为条件
'''
        Big        D    E            F
        Small    f    d    e    f    d    e    f
Upper    Lower                            
    C        a    259-95-63
               b    -5-3-56-63-5
            c    6-66478-4

另外,也支持布尔序列的索引

df_ex.loc[idx[:'A',lambda x:x.sum()>0]]# 列和大于0
            Big        D        F
            Small    d    e    e
Upper        Lower            
   A            a    369
                b    -33-4
                c    -109
  • loc [ idx [ * , * ] , idx [ * , * ] ] 型​ 这种情况能够分层进行切片,前一个 idx指代的是索引,后一个是索引
df_ex.loc[idx[:'A','b':], idx['E':,'e':]]'''
    :'A' - 第一层行索引切到A   ,  'b': - 第二层行索引从b开始后面的所有(这里被第一层A限制了,所有才只有b,c)
    'E': - 第一层列索引从E开始切到后面所有   ,   'e': - 第二层列索引从e开始切到后面所有(因为第一层切出两个,所以分别从两个的e开始切)
'''
            Big        E        F
            Small    e    f    e    f
Upper        Lower                
    A            b    -25-44
                c    669-6

此方法不支持使用函数

多级索引的构造

​ 常用的有

from_tuples , from_arrays , from_product

三种方法,他们都是 **

pd.MultiIndex

对象下的函数**

  • from_tuples根据传入由元组组成的列表进行构造
my_tuple =[('a','cat'),('a','dog'),('b','cat'),('b','dog')]
pd.MultiIndex.from_tuples(my_tuple, names=['First','Second'])
MultiIndex([('a','cat'),('a','dog'),('b','cat'),('b','dog')],
           names=['First','Second'])
  • from_arrays根据传入列表对相应层进行构造
my_array =[list('aabb'),['cat','dog']*2]
pd.MultiIndex.from_arrays(my_array, names=['First','Second'])
MultiIndex([('a','cat'),('a','dog'),('b','cat'),('b','dog')],
           names=['First','Second'])
  • from_product根据给定多个列表的笛卡尔积进行构造​ 笛卡尔积: 就是两个列表的每个元素与另一个列表的每个元素相乘(这里是组合)
my_list1 =['a','b']
my_list2 =['cat','dog']
pd.MultiIndex.from_product([my_list1,my_list2],names=['First','Second'])
MultiIndex([('a','cat'),('a','dog'),('b','cat'),('b','dog')],
           names=['First','Second'])

##索引的常用方法

的交换和删除

#创建一个3层索引便于学习
np.random.seed(0)
L1,L2,L3 =['A','B'],['a','b'],['alpha','beta']
mul_index1 = pd.MultiIndex.from_product([L1,L2,L3],names=('Upper','Lower','Extra'))
L4,L5,L6 =['C','D'],['c','d'],['cat','dog']
mul_index2 = pd.MultiIndex.from_product([L4,L5,L6],names=('Big','Small','Other'))
df_ex = pd.DataFrame(np.random.randint(-9,10,(8,8)),index=mul_index1,columns=mul_index2)

df_ex
                Big        C                D
                Small    c        d        c        d
                Other    cat    dog    cat    dog    cat    dog    cat    dog
Upper    Lower    Extra                                
    A        a    alpha    36-9-6-6-209
                   beta    -5-33-8-3-258
            b    alpha    -44-107-466
                beta    -99-685-2-9-8
    B        a    alpha    0-91-629-7-9
                beta    -9-5-4-3-186-5
            b    alpha    01-8-8-20-6-3
                beta    259-95-631

​ 索引层交换由

swaplevel

reorder_levels

完成,前者只能交换两个层,而后者可以交换任意层,两者都可以指定交换轴,即行索引或列索引

  • swaplevel 交换两个层
'''
    DataFrame.swaplevel(i=- 2, j=- 1, axis=0)
    相会交换索引中的i层和j层,默认是交换索引的两个最内层
    参数:        
        i, j: int 或 str
            交换的索引的两个层级。可以将级别名称作为字符串传递。
            
        axis:{0 或 'index',1 或 'columns'},默认 0
            交换级别的轴。0 或 'index' 表示按行,1 或 'columns' 表示按列。
'''
df_ex.swaplevel(0,2,axis=1).head()# 列索引的第一层和第三层交换
                Other    cat    dog    cat    dog    cat    dog    cat    dog
                Small    c    c    d    d    c    c    d    d
                Big        C    C    C    C    D    D    D    D
Upper    Lower    Extra                                
    A        a    alpha    36-9-6-6-209
                beta    -5-33-8-3-258
            b    alpha    -44-107-466
                beta    -99-685-2-9-8
    B        a    alpha    0-91-629-7-9
  • reorder_levels交换任意层级
'''
    DataFrame.reorder_levels(order, axis=0)
    使用输入顺序重新排列索引层级。 不能降低或复制层级
    参数
        order: int列表 或 str的列表
            代表新级别顺序的列表。通过数字(位置)或按键(标签)来参考水平。

        axis:{0 或 'index',1 或 'columns'},默认 0
            在哪里重新排序级别。
'''
df_ex.reorder_levels([2,0,1],axis=0).head()# 列表数字指代原来索引中的层
                Big        C                D
                Small    c        d        c        d
                Other    cat    dog    cat    dog    cat    dog    cat    dog
Extra    Upper    Lower                                
    alpha    A        a    36-9-6-6-209
    beta    A        a    -5-33-8-3-258
    alpha    A        b    -44-107-466
    beta    A        b    -99-685-2-9-8
    alpha    B        a    0-91-629-7-9

这里只涉及 行或列索引 内部的交换

  • 若想要删除某一层的索引,可以使用 droplevel 方法
df_ex.droplevel(1,axis=1)
                Big        C                D
                Other    cat    dog    cat    dog    cat    dog    cat    dog
Upper    Lower    Extra                                
    A        a    alpha    36-9-6-6-209
                beta    -5-33-8-3-258
            b    alpha    -44-107-466
                beta    -99-685-2-9-8
    B        a    alpha    0-91-629-7-9
                beta    -9-5-4-3-186-5
            b    alpha    01-8-8-20-6-3
                beta    259-95-631

属性的修改

  • rename_axis 可以对索引层的名字进行修改,常用的修改方式是传入字典的映射
df_ex.rename_axis(index={'Upper':'Changed_row'},columns={'Other':'Changed_Col'}).head()
                Big            C                D
                Small        c        d        c        d
                Changed_Col    cat    dog    cat    dog    cat    dog    cat    dog
Changed_row    Lower    Extra                                
        A        a    alpha    36-9-6-6-209
                    beta    -5-33-8-3-258
                b    alpha    -44-107-466
                    beta    -99-685-2-9-8
        B        a    alpha    0-91-629-7-9
  • rename可以对索引的值进行修改,如果是多级索引需要指定层号(level)
df_ex.rename(columns={'cat':'not_cat'},level=2).head()
                   Big        C                        D
                Small    c            d            c            d
                Other    not_cat    dog    not_cat    dog    not_cat    dog    not_cat    dog
Upper    Lower    Extra                                
    A        a    alpha    36-9-6-6-209
                beta    -5-33-8-3-258
            b    alpha    -44-107-466
                beta    -99-685-2-9-8
    B        a    alpha    0-91-629-7-9

​ 也可以给**

rename

传入函数其输入的值就是索引**

df_ex.rename(index=lambda x:str.upper(x),level=2).head()
                Big        C                D
                Small    c        d        c        d
                Other    cat    dog    cat    dog    cat    dog    cat    dog
Upper    Lower    Extra                                
    A        a    ALPHA    36-9-6-6-209
                BETA    -5-33-8-3-258
            b    ALPHA    -44-107-466
                BETA    -99-685-2-9-8
    B        a    ALPHA    0-91-629-7-9

​ 对于整个索引的元素替换,可以利用迭代器实现

'''
    iter():生成迭代器
    next() 返回迭代器的下一个项目
    next() 函数要和生成迭代器的 iter() 函数一起使用
'''
new_values = iter(list('abcdefgh'))
df_ex.rename(index=lambda x:next(new_values),level=2)
                Big        C                D
                Small    c        d        c        d
                Other    cat    dog    cat    dog    cat    dog    cat    dog
Upper    Lower    Extra                                
    A        a        a    36-9-6-6-209
                    b    -5-33-8-3-258
            b        c    -44-107-466
                    d    -99-685-2-9-8
    B        a        e    0-91-629-7-9
                    f    -9-5-4-3-186-5
            b        g    01-8-8-20-6-3
                    h    259-95-631
  • map达到更改索引值​ 它是定义在 Index 上的方法​ 它传入的不是层的标量值,而是直接传入索引的元组
df_temp = df_ex.copy()
new_idx = df_temp.index.map(lambda x:(x[0],x[1],str.upper(x[2])))print(new_idx)#Python upper() 方法将字符串中的小写字母转为大写字母。#把index放进map里面运行

df_temp.index = new_idx
df_temp.head()
MultiIndex([('A','a','ALPHA'),('A','a','BETA'),('A','b','ALPHA'),('A','b','BETA'),('B','a','ALPHA'),('B','a','BETA'),('B','b','ALPHA'),('B','b','BETA')],
           names=['Upper','Lower','Extra'])

                Big        C                D
                Small    c        d        c        d
                Other    cat    dog    cat    dog    cat    dog    cat    dog
Upper    Lower    Extra                                
    A        a    ALPHA    36-9-6-6-209
                    BETA    -5-33-8-3-258
            b    ALPHA    -44-107-466
                BETA    -99-685-2-9-8
    B        a    ALPHA    0-91-629-7-9

设置与重置

#构建新表便于学习
df_new = pd.DataFrame({'A':list('aacd'),'B':list('PQRT'),'C':[1,2,3,4]})
df_new

ABC0aP11aQ22cR33dT4

  • set_index设置索引​ 主要参数是append,表示是否保留原来的索引,直接把设定的索引添加到原来的索引内层
df_new.set_index('A')#直接把A列设置为索引层

BCAaP1aQ2cR3dT4

df_new.set_index('A', append=True)#列索引A被添加到内层

BCA0aP11aQ22cR33dT4
如果 想要添加索引的列 没有出现在其中,那么可以直接在参数中传入相应的 Series

my_index = pd.Series(list('WXYZ'), name='D')
df_new = df_new.set_index(['A', my_index])#my_index 插入了列名为D的列
df_new

BCADaWP1XQ2cYR3dZT4

  • reset_index重设索引​ 主要参数是drop,表示是否要把去掉的索引层丢弃,而不是添加到列中
df_new.reset_index(['D'])#没有丢弃去掉的索引,而是从第二层返回到了第一层

DBCAaWP1aXQ2cYR3dZT4

df_new.reset_index(['D'], drop=True)#直接丢弃去掉的索引

BCAaP1aQ2cR3dT4

如果 reset_index()不加参数 ,就是重置dataframe的索引,由默认索引(0…,A…)代替

变形

  • reindex更改行索引
  • reindex_like仿照传入的表索引作为自己的表索引没有给出值的用**np.nan**填充
  • reindex
df_reindex = pd.DataFrame({"Weight":[60,70,80],"Height":[176,180,179]},index=['1001','1003','1002'])print('原表')
df_reindex

原表
WeightHeight100160176100370180100280179

print('修改后')
df_reindex.reindex(index=['1001','1002','1003','1004'],columns=['Weight','Gender'])

修改后
WeightGender100160.0NaN100280.0NaN100370.0NaN1004NaNNaN

  • reindex_like
df_existed = pd.DataFrame(index=['1001','1002','1003','1004'],columns=['Weight','Gender'])print('原表')
df_existed

原表
WeightGender1001NaNNaN1002NaNNaN1003NaNNaN1004NaNNaN

print('修改后')
df_reindex.reindex_like(df_existed)

修改后
WeightGender100160.0NaN100280.0NaN100370.0NaN1004NaNNaN

运算

​ 经常会有一种利用集合运算来取出符合条件行的需求,对索引可以使用集合的运算

​ 由于集合的元素是互异的,但是索引中可能有相同的元素,先用 **

unique

**去重后再进行运算。

# 创建表
df_set_1 = pd.DataFrame([[0,1],[1,2],[3,4]],index = pd.Index(['a','b','a'],name='id1'))
df_set_2 = pd.DataFrame([[4,5],[2,6],[7,1]],index = pd.Index(['b','b','c'],name='id2'))# 去重
id1, id2 = df_set_1.index.unique(), df_set_2.index.unique()print(id1)print(id2)
Index(['a','b'], dtype='object', name='id1')
Index(['b','c'], dtype='object', name='id2')
id1.intersection(id2)#交集
Index(['b'], dtype='object')
id1.union(id2)#并集
Index(['a','b','c'], dtype='object')
id1.difference(id2)#返回一个新的Index,其中Index不在给出元组里面
Index(['a'], dtype='object')
id1.symmetric_difference(id2)#返回两个index中不一样的元素
Index(['a','c'], dtype='object')

分组

​ 明确三个要素:分组依据数据来源操作及其返回结果

df.groupby(分组依据)[数据来源].使用操作
#读取表演示
df = pd.read_csv('C:\\Users\\Yuan\\Desktop\\pandas\\文件\\data\\learn_pandas.csv')
df.head()

SchoolGradeNameGenderHeightWeightTransferTest_NumberTest_DateTime_Record0Shanghai Jiao Tong UniversityFreshmanGaopeng YangFemale158.946.0N12019/10/50:04:341Peking UniversityFreshmanChangqiang YouMale166.570.0N12019/9/40:04:202Shanghai Jiao Tong UniversitySeniorMei SunMale188.989.0N22019/9/120:05:223Fudan UniversitySophomoreXiaojuan SunFemaleNaN41.0N22020/1/30:04:084Fudan UniversitySophomoreGaojuan YouMale174.074.0N

#按照性别统计身高中位数
df.groupby('Gender')['Height'].median()
Gender
Female    159.6
Male      173.4
Name: Height, dtype: float64
  • 需要根据多个维度进行分组,只需在 groupby 中传入相应列名构成的列表即可
# 根据学校和性别进行分组
df.groupby(['School','Gender'])['Height'].mean()
School                         Gender
Fudan University               Female    158.776923
                               Male      174.212500
Peking University              Female    158.666667
                               Male      172.030000
Shanghai Jiao Tong University  Female    159.122500
                               Male      176.760000
Tsinghua University            Female    159.753333
                               Male      171.638889
Name: Height, dtype: float64
  • 也可以通过条件进行分组
condition = df.Weight > df.Weight.mean()
df.groupby(condition)['Height'].mean()
Weight
False159.034646True172.705357
Name: Height, dtype: float64
  • 由此可以看出是以分组依据的unique值来分组,传入的序列都会被去重
# 通过 drop_duplicates 就能知道具体的组类别
df[['School','Gender']].drop_duplicates()

SchoolGender0Shanghai Jiao Tong UniversityFemale1Peking UniversityMale2Shanghai Jiao Tong UniversityMale3Fudan UniversityFemale4Fudan UniversityMale5Tsinghua UniversityFemale9Peking UniversityFemale16Tsinghua UniversityMale

df.groupby([df['School'], df['Gender']])['Height'].mean()#以上方去去重字段分组
School                         Gender
Fudan University               Female    158.776923
                               Male      174.212500
Peking University              Female    158.666667
                               Male      172.030000
Shanghai Jiao Tong University  Female    159.122500
                               Male      176.760000
Tsinghua University            Female    159.753333
                               Male      171.638889
Name: Height, dtype: float64

Groupby对象

​ 可以先将分组依据定义成对象

gb = df.groupby(['School','Grade'])
gb
<pandas.core.groupby.generic.DataFrameGroupBy object at 0x000001C2A65BD420>
  • ngroups属性获取分组个数
gb.ngroups
16
  • groups获取 组名映射到主索引列表 的字典
res = gb.groups
res.keys()# 字典的值由于是索引,元素个数过多,此处只展示字典的键
dict_keys([('Fudan University','Freshman'),('Fudan University','Junior'),('Fudan University','Senior'),('Fudan University','Sophomore'),('Peking University','Freshman'),('Peking University','Junior'),('Peking University','Senior'),('Peking University','Sophomore'),('Shanghai Jiao Tong University','Freshman'),('Shanghai Jiao Tong University','Junior'),('Shanghai Jiao Tong University','Senior'),('Shanghai Jiao Tong University','Sophomore'),('Tsinghua University','Freshman'),('Tsinghua University','Junior'),('Tsinghua University','Senior'),('Tsinghua University','Sophomore')])
  • size统计每个组的元素个数(在DataFrame中是表长乘表宽)
gb.size()
School                         Grade    
Fudan University               Freshman      9
                               Junior       12
                               Senior       11
                               Sophomore     8
Peking University              Freshman     13
                               Junior        8
                               Senior        8
                               Sophomore     5
Shanghai Jiao Tong University  Freshman     13
                               Junior       17
                               Senior       22
                               Sophomore     5
Tsinghua University            Freshman     17
                               Junior       22
                               Senior       14
                               Sophomore    16
dtype: int64
  • get_group直接获取所在组对应的行,必须给出组的具体名字
gb.get_group(('Peking University','Freshman'))

SchoolGradeNameGenderHeightWeightTransferTest_NumberTest_DateTime_Record1Peking UniversityFreshmanChangqiang YouMale166.570.0N12019/9/40:04:2032Peking UniversityFreshmanGaopeng ShiFemale162.948.0N12019/9/120:04:5835Peking UniversityFreshmanGaoli ZhaoMale175.478.0N22019/10/80:03:3236Peking UniversityFreshmanXiaojuan QinMaleNaN79.0Y12019/12/100:04:1038Peking UniversityFreshmanQiang HanMale185.387.0N32020/1/70:03:5845Peking UniversityFreshmanQuan ChuFemale154.743.0N12019/11/280:04:4754Peking UniversityFreshmanXiaojuan ChuMale162.458.0Y32019/11/290:03:4257Peking UniversityFreshmanChangquan ChuFemale159.645.0N22019/12/90:04:1888Peking UniversityFreshmanXiaopeng HanFemale164.153.0N12019/12/180:05:2096Peking UniversityFreshmanChangmei FengFemale163.856.0N32019/11/80:04:4199Peking UniversityFreshmanChangpeng ZhaoMale181.383.0N22019/10/240:04:08140Peking UniversityFreshmanQiang ZhangFemale152.743.0N12019/11/300:05:27185Peking UniversityFreshmanChunmei WangFemale151.243.0N22019/12/100:04:24

聚合函数

内置聚合函数

max/min/mean/median/count/all/any/idxmax/idxmin
mad/nunique/skew/quantile/sum/std/var/sem/size/prod 
gb = df.groupby('Gender')['Height']
  • quantile给定数据的四分位数
'''
    所谓四分位数;即把数值由小到大排列并分成四等份,处于三个分割点位置的数值就是四分位数。

    第1四分位数 (Q1),又称“较小四分位数”,等于该样本中所有数值由小到大排列后第25%的数字。
    第2四分位数 (Q2),又称“中位数”,等于该样本中所有数值由小到大排列后第50%的数字。
    第3四分位数 (Q3),又称“较大四分位数”,等于该样本中所有数值由小到大排列后第75%的数字。
'''
gb.quantile(0.95)#给定数据(数组元素)的分位数
  • 这些聚合函数当传入的数据来源包含多个列时,将按照进行迭代计算
gb = df.groupby('Gender')[['Height','Weight']]
gb.max()
        Height    Weight
Gender        
Female    170.263.0
Male    193.989.0

groupby对象必须聚合后才会输出DataFrame

agg方法

​ 传入函数并运行的是数据源

  • 使用多个函数​ 当使用多个聚合函数时,需要用列表的形式把内置聚合函数对应的字符串传入,先前提到的所有字符串都是合法的
gb.agg(['sum','idxmax','skew'])
       Height                    Weight
        sum        idxmax    skew         sum      idxmax    skew
Gender                        
Female    21014.028-0.2192536469.028-0.268482
Male    8854.91930.4375353929.02-0.332393

从结果看,此时列索引为多级索引,第一层为数据源,第二层为使用的聚合方法,分别逐一队列使用聚合,因此结果为6列

  • 对特定的列使用特定的聚合函数​ 通过构造字典传入 agg 中实现​ 列名为键,聚合字符串或字符串列表为值
gb.agg({'Height':['mean','max'],'Weight':'count'})#列名为键,聚合字符串为值,但是这里只是数据来源,不是分组依据,还是对性别进行分组
        Height                Weight
         mean        max        count
Gender            
Female    159.19697170.2135
Male    173.62549193.954
  • 自定义函数​ 必须注意传入函数的参数是之前数据源中的列,逐列进行计算
gb.agg(lambda x: x.mean()-x.min())
    Height    Weight
Gender        
Female    13.7969713.918519
Male    17.9254921.759259

​ 由于传入的是,因此列上的方法和属性都是可以在函数中使用的,只需保证返回值是标量即可

defmy_func(s):#传入的是列
    res ='High'if s.mean()<= df[s.name].mean():
        res ='Low'return res

gb.agg(my_func)
        Height    Weight
Gender        
Female    Low        Low
Male    High    High
  • 聚合结果的重命名

  只需将上述函数的位置改写成元组,元组第一个元素为新名字第二个位置为原来的函数,也可以使用聚合字符串和自定义函数

gb.agg([('range',lambda x: x.max()-x.min()),('my_sum','sum')])
        Height            Weight
        range    my_sum    range    my_sum
Gender                
Female    24.821014.029.06469.0
Male    38.28854.938.03929.0
gb.agg({'Height':[('my_func', my_func),'sum'],'Weight':lambda x:x.max()})#Height对应两个聚合的元素
        Height                Weight
        my_func        sum<lambda>
Gender            
Female    Low            21014.063.0
Male    High        8854.989.0
  • 使用对一个或者多个列使用单个聚合的时,重命名需要加方括号
gb.agg([('my_sum','sum')])#必须加中括号
        Height    Weight
        my_sum    my_sum
Gender        
Female    21014.06469.0
Male    8854.93929.0
gb.agg({'Height':[('my_func', my_func),'sum'],'Weight':[('range',lambda x:x.max())]})
        Height                Weight
        my_func        sumrange
Gender            
Female    Low        21014.063.0
Male    High    8854.989.0

变换和过滤

#初始化
df = pd.read_csv('C:\\Users\\Yuan\\Desktop\\pandas\\文件\\data\\learn_pandas.csv')
gb = df.groupby('Gender')[['Height','Weight']]

transform方法

​ 传入的是数据源(与agg相同),按照进行计算,且不能通过传入字典来对指定列使用特定的变换,运行完成后将其给

DataFrame

填充

最常用的内置变换函数是累计函数:

cumcount / cumsum / cumprod / cummax / cummin

transform方法与这些是一样的

gb.cummax().head()#返回一个DataFrame或Series轴上的累积最大值
    Height    Weight
0158.946.01166.570.02188.989.03    NaN        46.04188.989.0

参数:

'''
    DataFrameGroupBy.transform(func,*args,engine = None,engine_kwargs = None,** kwargs)
        func:函数
        
        *args:传入函数从参数
        
        engine:引擎 默认None
            'cython':通过 cython 的 C 扩展运行函数。
            'numba': 通过从 numba.JIT 编译的代码运行函数。
            None:默认为'cython'或全局设置compute.use_numba

        engine_kwargs字典,默认None
            对于'cython'引擎,不接受engine_kwargs
                如果engine默认,那就不能接收字典
            对于'numba'引擎,引擎可以接受nopython,nogil 和parallel字典键。
                这些值必须是True或 False。引擎 的默认值engine_kwargs是并将应用
                于函数'numba'{'nopython': True, 'nogil': False, 'parallel': 
                False}
'''

示例:

gb.transform(lambda x:(x-x.mean())/x.std()).head()
        Height    Weight
0-0.058760-0.3548881-1.010925-0.35500022.1670632.0894983        NaN        -1.27978940.0531330.159631
  • transform只能返回同长度的序列,实际上也可以返回标量(函数运行后返回单个值),这会使得结果会被广播道整个组
gb.transform('mean').head()# 传入返回标量的函数也是可以的#因为mean是平均值函数返回的是单值,在transform的作用下就会广播成每组求平均值后返回

transform与agg的区别

  • transform的数据是填充到分组对象的每列上,agg只是生成了一个最终的聚合结果
df = pd.read_csv('C:\\Users\\Yuan\\Desktop\\pandas\\文件\\data\\learn_pandas.csv')
gb = df.groupby('Gender')[['Height','Weight']]

transform:

transform = gb.transform('mean')
        Height     Weight
0159.1969747.9185191173.6254972.7592592173.6254972.7592593159.1969747.9185194173.6254972.759259'''
    数据来源是['Height', 'Weight'],但是结果没有给出分组依据,而是把聚合结果直接填充到Gender对应的位置上(Female,Male对应的行填充了对应的值)
'''

agg:

agg = gb.agg('mean')
           Height     Weight
Gender                      
Female  159.1969747.918519
Male    173.6254972.759259'''
    直接返回分组结果,不会把值进行每行填充,所以它也不具备直接添加进源DataFrame的功能
'''

agg不具备直接添加进源表的功能,transform可以直接添加

组索引与过滤

​ groupby对象中定义了**

filter

函数进行组的筛选,传入的参数也是数据源**,参数中的函数只允许返回布尔值

参数:

'''
    DataFrameGroupBy.filter(func, dropna=True, *args, **kwargs)
    返回DataFrame的副本,不包括过滤的元素。如果组中的元素为False,则会过滤。 
    参数:
        func:函数,返回True/False
        dropna:丢弃为False的组。默认为True
    返回:DataFrame
'''
gb.filter(lambda x: x.shape[0]>100).head()

#####apply

 在设计上, apply 的自定义函数传入参数与

filter

完全一致只不过后者只允许返回布尔值

# 人体的BMI指标defBMI(x):
    Height = x['Height']/100
    Weight = x['Weight']
    BMI_value = Weight/Height**2return BMI_value.mean()

gb.apply(BMI)

apply函数根据返回值情况来输出不同的结果

  • 1:返回标量​ 得到结果的是 Series ,索引与 agg 的结果一致
gb = df.groupby(['Gender','Test_Number'])[['Height','Weight']]
gb.apply(lambda x:0)
Gender  Test_Number
Female  102030
Male    102030
dtype: int64
gb.apply(lambda x:[0,0])# 虽然是列表,但是作为返回值仍然看作标量
Gender  Test_Number
Female  1[0,0]2[0,0]3[0,0]
Male    1[0,0]2[0,0]3[0,0]
dtype:object
  • 返回Series​ 得到结果是 DataFrame ,行索引与标量情况一致,列索引为 Series 的索引
gb.apply(lambda x: pd.Series([0,0],index=['a','b']))
                    a    b
Gender    Test_Number        
Female            100200300
Male            100200300
  • 返回DataFrame​ 得到结果是 DataFrame ,行索引最内层在每个组原先 agg 的结果索引上,再加一层返回的 DataFrame 行索引,同时分组结果 DataFrame 的列索引和返回的 DataFrame 列索引一致
gb.apply(lambda x: pd.DataFrame(np.ones((2,2)),index =['a','b'],columns=pd.Index([('w','x'),('y','z')])))
                        w    y
                        x    z
Gender    Test_Number            
Female            1    a    1.01.0
                    b    1.01.02    a    1.01.0
                    b    1.01.03    a    1.01.0
                    b    1.01.0
Male            1    a    1.01.0
                    b    1.01.02    a    1.01.0
                    b    1.01.03    a    1.01.0
                    b    1.01.0

最后需要强调的是, apply 函数的灵活性是以牺牲一定性能为代价换得的,除非需要使用跨列处理的分组处理,否则应当使用其他专门设计的 groupby 对象方法,否则在性能上会存在较大的差距。同时,在使用聚合函数和变换函数时,也应当优先使用内置函数,它们经过了高度的性能优化,一般而言在速度上都会快于用自定义函数来实现。

变形

长宽表的变形

所有的变形都是Excel的数据透视表

概念:

​ 一个表把数据存入列中,他就是关于列的长表

​ 一个表把数据作为列名,列中的元素是与这个列相关的特征数值,他就是关于列名的宽表

a = pd.DataFrame({'Gender':['F','F','M','M'],'Height':[163,160,175,180]})#长表print(a)
pd.DataFrame({'Height: F':[163,160],'Height: M':[175,180]})#宽表
      Gender  Height
0      F     1631      F     1602      M     1753      M     180

    Height: F    Height: M
01631751160180

显然这两张表从信息上是完全等价的,它们包含相同的身高统计数值,只是这些数值的呈现方式不同,而其呈现方式主要又与性别一列选择的布局模式有关,即到底是以 long 的状态存储还是以 wide 的状态存储。因此, pandas 针对此类长宽表的变形操作设计了一些有关的变形函数。

变形函数

长表变宽表
  • **pivot**长表变宽表

参数:

'''
    DataFrame.pivot(index=None, columns=None, values=None)
    根据列值重塑数据(生成一个“透视”表)。 使用来自指定索引/列的唯一值来形成结果DataFrame的轴,此函数不支持数据聚合
    参数:
        index:str 或 object 或 list(str) 可选
            用作于新表的行索引。如果没有,则使用现有索引
        
        columns:str 或 object 或 list(str)
            用作于新表的列索引

        values:str 或 object 或 前面的列表 可选
            用作于新表的值 如果没有指定,将使用所有剩余的列,并且结果将具有分层索引的列

        return:返回重构的 DataFrame
'''

创建表便于学习

df = pd.DataFrame({'Class':[1,1,2,2],'Name':['San Zhang','San Zhang','Si Li','Si Li'],'Subject':['Chinese','Math','Chinese','Math'],'Grade':[80,75,90,85]})
df
    Class    Name    Subject    Grade
01    San Zhang    Chinese    8011    San Zhang    Math    7522    Si Li        Chinese    9032    Si Li        Math    85

变形最重要的三个要素:

变形后的行索引、需要转到列索引的列,以及这些列和行索引对应的数值

他们分别对应了

pivot

方法中

index,columns,values

参数

列索引

column

对应的列的 唯一值(unique)

行索引

index

对应的列的 唯一值(unique)

​ 而

values

对应了想要展示的数值列

df.pivot(index='Name', columns='Subject', values='Grade')
Subject        Chinese        Math
    Name        
San Zhang        8075
    Si Li        9085

由于pivot进行变形操作要满足唯一性要求,行列对应的值必须唯一,所以行列的组合必须是唯一的

df.loc[1,'Subject']='Chinese'#如果把列索引的Subject改成与值相同的Chinese就会报错
try:
    df.pivot(index='Name',columns='Subject',values='Grade')except Exception as e:
    Err_Msg = e

Err_Msg
ValueError('Index contains duplicate entries, cannot reshape')
pivot

相关的三个参数允许传入列表,这也意味着会返回多级索引

创建表便于学习

df = pd.DataFrame({'Class':[1,1,2,2,1,1,2,2],'Name':['San Zhang','San Zhang','Si Li','Si Li','San Zhang','San Zhang','Si Li','Si Li'],'Examination':['Mid','Final','Mid','Final','Mid','Final','Mid','Final'],'Subject':['Chinese','Chinese','Chinese','Chinese','Math','Math','Math','Math'],'Grade':[80,75,85,65,90,85,92,88],'rank':[10,15,21,15,20,7,6,2]})
df
    Class    Name    Examination    Subject    Grade    rank
01    San Zhang    Mid        Chinese        801011    San Zhang    Final    Chinese        751522    Si Li        Mid        Chinese        852132    Si Li        Final    Chinese        651541    San Zhang    Mid        Math        902051    San Zhang    Final    Math        85762    Si Li        Mid        Math        92672    Si Li        Final    Math        882

示例:

pivot_multi = df.pivot(index =['Class','Name'],
                        columns =['Subject','Examination'],
                        values =['Grade','rank'])'''
    这其实就是数据透视表,把行和列放进去,对应的就是值,但是必须是唯一值
'''
pivot_multi
                Grade                    rank
    Subject        Chinese        Math        Chinese        Math
    Examination    Mid    Final    Mid    Final    Mid    Final    Mid    Final
Class    Name1    San Zhang    8075908510152072    Si Li        85659288211562

​ 根据唯一性原则,新表的**行索引等价于对index中的多列使用

drop_duplicates

去重,而列索引长度为values中的元素乘以columns的唯一组合数量(**与index类型)

  • pivot_table不依赖唯一性条件的 长表变宽表​ pivot 的使用依赖于唯一性条件,那如果不满足唯一性条件,那么必须通过聚合操作使得相同行列组合对应的多个值变为一个值。

创建表方便学习

df = pd.DataFrame({'Name':['San Zhang','San Zhang','San Zhang','San Zhang','Si Li','Si Li','Si Li','Si Li'],'Subject':['Chinese','Chinese','Math','Math','Chinese','Chinese','Math','Math'],'Grade':[80,90,100,90,70,80,85,95]})
df
    Name        Subject    Grade
0    San Zhang    Chinese    801    San Zhang    Chinese    902    San Zhang    Math    1003    San Zhang    Math    904    Si Li        Chinese    705    Si Li        Chinese    806    Si Li        Math    857    Si Li        Math    95

参数:

'''
    DataFrame.pivot_table(values=None, index=None, columns=None, aggfunc='mean', fill_value=None, margins=False, dropna=True, margins_name='All', observed=False, sort=True)
    创建一个电子表格风格的数据透视表作为DataFrame,数据透视表中的层将存储在结果DataFrame的索引和列上的MultiIndex对象(分层索引)中
    参数:
        values:需要被聚合的列,可选
        
        index:column 或 Grouper 或 array 或 上个列表
            如果传入一个数组,它必须与数据的长度相同。 列表可以包含任何其他类型(
            列表除外)。 在透视表索引上进行分组的键。 如果传入一个数组,则以与列值
            相同的方式使用它

        columns:column 或 Grouper 或 array 或 上个列表
            如果传入一个数组,它必须与数据的长度相同。 列表可以包含任何其他类型(
            列表除外)。 在透视表列上进行分组的键。 如果传入一个数组,则以与列值
            相同的方式使用它

        aggfunc:function 或 list(functions) 或 dict 默认为 numpy.mean
            如果传递了函数列表,那么结果透视表将有层次结构列,它们的顶层是函数名(
            从函数对象本身推断出来)。如果传递了dict,键是column to aggregate,值
            是function或函数列表

        fill_value:标量 默认NULL
            用于替换缺失值的值(在结果数据透视表中,聚合后)

        margins:布尔值,默认为 False
            不要包括其条目全部为 NaN 的列。

        margins_name:str, 默认 ‘All’
            当边距为True时,包含总计的行/列的名称

        observed:布尔值, 默认 False
            这只适用于任何组别属于分类的情况。 
            如果为True:只显示分类组别的观察值。 
            如果为False:显示分类组别的所有值。  

        sortbool:布尔值, 默认 True
            指定结果是否应该排序
    
    return DataFrame
        一个Excel风格的数据透视表
'''

最常用的参数就是

aggfunc

指定聚合

df.pivot_table(index ='Name',
                columns ='Subject',
                values ='Grade',
                aggfunc ='mean')
Subject        Chinese    Math
Name        
San Zhang    8595
Si Li        7590

这里

aggfunc

传入的参数包含所有的聚合字符串,此外还可以传入以序列为输入 标量为输出的聚合函数来实现自定义操作

df.pivot_table(index ='Name',
                columns ='Subject',
                values ='Grade',
                aggfunc =lambda x:x.mean())
Subject        Chinese    Math
Name        
San Zhang    8595
Si Li        7590

pivot_table具有边际汇总的功能,可以通过设置

margins=True

来实现,其中边际聚合方式与 aggfunc 中给出的聚合方法一致

边际汇总就是把所有值算出来之后再进行给出聚合字符串再算一遍

df.pivot_table(index ='Name',
                columns ='Subject',
                values ='Grade',
                aggfunc='mean',
                margins=True)
Subject        Chinese    Math    All
Name            
San Zhang    8595.090.00
Si Li        7590.082.50
All            8092.586.25
宽表变长表
  • melt宽表转长表

创建表以便学习

df = pd.DataFrame({'Class':[1,2],'Name':['San Zhang','Si Li'],'Chinese':[80,90],'Math':[80,75]})
df
    Class    Name    Chinese    Math
01    San Zhang    808012    Si Li        9075

参数:

'''
    DataFrame.melt(id_vars=None, value_vars=None, var_name=None, value_name='value', col_level=None, ignore_index=True)
    将DataFrame从宽格式Unpivot到长格式,可以选择保留标识符集。  
    参数:
        id_vars:元组、列表或 ndarray,可选
            用作标识符变量的列。

        value_vars:元组、列表或 ndarray,可选
            要取消透视的列。如果未指定,则使用所有未设置为id_vars的列。

        var_name:标量
            用于“变量”列的名称。如果 None 它使用 frame.columns.name或“变量”。

        value_name:标量,默认“value”
            用于“value”列的名称。

        col_level: int 或 str,可选
            如果列是 MultiIndex,则使用此级别来融化。

        ignore_index:布尔值,默认为 True
            如果为 True,则忽略原始索引。
            如果为 False,则保留原始索引。
            索引标签将根据需要重复。

    Returns DataFrame
        没有透视DataFrame.
'''

示例:

df_melted = df.melt(id_vars =['Class','Name'],#需要保留不动的列
                    value_vars =['Chinese','Math'],#要动的列(把这个值翻转过来,从字段到数值)
                    var_name ='Subject',#反转字段后的列名(字段成为值之后需要给出新字段)
                    value_name ='Grade')#因为反转了字段,字段下面的值也有反转,所以这个参数是反转后值的字段#保留不动的列根据反转的字段来复制多少个
df_melted
    Class    Name    Subject    Grade
01    San Zhang    Chinese    8012    Si Li        Chinese    9021    San Zhang    Math    8032    Si Li        Math    75

​ **

melt

pivot

是一组互逆过程**,那么就一定可以通过pivot操作把

df_melted转回df的形式

df_unmelted = df_melted.pivot(index =['Class','Name'],
                                     columns='Subject',
                                     values='Grade')
df_unmelted # 下面需要恢复索引,并且重命名列索引名称
        Subject    Chinese    Math
Class    Name1    San Zhang    80802    Si Li        9075
df_unmelted = df_unmelted.reset_index().rename_axis(columns={'Subject':''})
df_unmelted.equals(df)#测试两个对象是否包含相同的元素
True

DataFrame.equals

'''
    DataFrame.equals(other)
        测试两个对象是否包含相同的元素
        此功能允许将两个 Series 或 DataFrame 相互比较,
        以查看它们是否具有相同的形状和元素。同一位置的 NaN 被认为是相等的。

        行/列索引不需要具有相同的类型,只要值被认为是相等的。对应的列必须具有相同的 dtype。
    
    参数
        other:Series 或者 DataFrame
            要与第一个进行比较的其他 Series 或 DataFrame。

    return 布尔
        如果两个对象中的所有元素都相同,则为 True,否则为 False。
'''
  • wide_to_long 宽表转长表创建表以便学习
df = pd.DataFrame({'Class':[1,2],'Name':['San Zhang','Si Li'],'Chinese_Mid':[80,75],'Math_Mid':[90,85],'Chinese_Final':[80,75],'Math_Final':[90,85]})
df
    Class    Name    Chinese_Mid    Math_Mid    Chinese_Final    Math_Final
01    San Zhang    8090809012    Si Li        75857585

参数:

'''
    pandas.wide_to_long(df, stubnames, i, j, sep='', suffix='\\d+')
    参数
        df:需要更改的DataFrame

        stubnames:需要拆分字段的前字段

        i:需要保留的字段

        j:需要拆分字段的后字段的列名

        sep:拆分的字段的拆分符号

        suffix:拆分符号后的正则匹配
        
'''

示例1:

pd.wide_to_long(df,
    stubnames=['Chinese','Math'],
    i =['Class','Name'],
    j='Examination',
    sep='_',
    suffix='.+')
                            Chinese    Math
Class    Name    Examination        
1    San Zhang    Mid                8090
                Final            80902    Si Li        Mid                7585
                Final            7585

示例2:

res = pivot_multi.copy()
res.columns = res.columns.map(lambda x:'_'.join(x))
res = res.reset_index()
res = pd.wide_to_long(res, stubnames=['Grade','rank'],
                        i =['Class','Name'],
                        j ='Subject_Examination',
                        sep ='_',
                        suffix ='.+')
res
                                        Grade    rank
Class    Name    Subject_Examination        
1    San Zhang        Chinese_Mid                8010
                    Chinese_Final            7515
                    Math_Mid                9020
                    Math_Final                8572    Si Li            Chinese_Mid                8521
                    Chinese_Final            6515
                    Math_Mid                926
                    Math_Final                882

str.join() 方法用于将序列中的元素以指定的字符连接生成一个新的字符串。

示例3:

res = res.reset_index()
res[['Subject','Examination']]= res['Subject_Examination'].str.split('_', expand=True)
res = res[['Class','Name','Examination','Subject','Grade','rank']].sort_values('Subject')

res = res.reset_index(drop=True)
res
    Class    Name    Examination    Subject    Grade    rank
01    San Zhang    Mid        Chinese    801011    San Zhang    Final    Chinese    751522    Si Li        Mid        Chinese    852132    Si Li        Final    Chinese    651541    San Zhang    Mid        Math    902051    San Zhang    Final    Math    85762    Si Li        Mid        Math    92672    Si Li        Final    Math    882

索引的变形

stack与unstack

  • stack

参数:

'''
    DataFrame.stack(level=- 1, dropna=True)
    将列中的规定层堆叠到索引。
    返回与当前 DataFrame 相比具有一个或多个新的最内层的多级索引的重构 DataFrame 或 Series。通过旋转当前数据框的列来创建新的最内层
        - 如果列有一个级别,则输出是一个系列;
        - 如果列有多个级别,则新的索引级别是从规定的级别获取的,
            并且输出是一个 DataFrame。
    参数
        level:int,str,list,默认 -1
            从列轴堆叠到索引轴的级别,定义为一个索引或标签,或者索引或标签的列表。

        dropna:布尔值,默认为 True
            是否删除结果帧/系列中缺少值的行。将列级别堆叠到索引轴上可以创建原始数据帧中缺少的索引和列值的组合。
    
    return:DataFrame or Series
'''
  • unstack

参数:

'''
    DataFrame.unstack(level=- 1, fill_value=None)
    枢轴(必须是分层的)索引标签的级别。
    返回具有新级别列标签的 DataFrame,其最内层由枢轴索引标签组成。
    参数
        level:int、str 或这些列表,默认 -1(最后一级)
            要解栈的索引级别,可以传递级别名称。

        fill_value:int、str 或 dict
            如果unstack产生缺失值,则将NaN 替换为该值。

    return:DataFrame or Series
'''

​ 之前提到了利用

swaplevel

reorder_levels

进行索引内部的层交换,

stack/unstack

就是行列索引交换,由于这种交换带来了DataFrame维度上的变化,因此属于变形操作

df = pd.DataFrame(np.ones((4,2)),
                index = pd.Index([('A','cat','big'),('A','dog','small'),('B','cat','big'),('B','dog','small')]),
                columns=['col_1','col_2'])#可能会产生缺失值
df
                    col_1    col_2
A    cat        big        1.01.0
    dog        small    1.01.0
B    cat        big        1.01.0
    dog        small    1.01.0

​ **

unstack

主要的参数是移动的层号默认转化最内层**,移动到列索引的最内层,同时支持同时转化多个层

df.unstack(2)#将最内层转化了,这里也可以写-1,他把第三个行索引转到列索引了
        col_1            col_2
        big        small    big        small
A    cat    1.0        NaN        1.0        NaN
    dog    NaN        1.0        NaN        1.0
B    cat    1.0        NaN        1.0        NaN
    dog    NaN        1.0        NaN        1.0
df.unstack([0,2])#把第0层和第2层转到列索引(由行索引起步)
    col_1                    col_2
    A            B            A            B
    big    small    big    small    big    small    big    small
cat    1.0    NaN        1.0    NaN        1.0    NaN        1.0    NaN
dog    NaN    1.0        NaN    1.0        NaN    1.0        NaN    1.0
  • 类似于pivot中的唯一性要求,在stack/unstack中必须保证被转为列索引的行索引层和被保留的行索引层构成的组合是唯一的,,破坏了唯一性,那么就会报错
my_index = df.index.to_list()
my_index[1]= my_index[0]
df.index = pd.Index(my_index)
df
                col_1    col_2
A    cat    big        1.01.0
        big        1.01.0
B    cat    big        1.01.0
    dog    small    1.01.0
try:
    df.unstack()except Exception as e:
    Err_Msg = e
Err_Msg
ValueError('Index contains duplicate entries, cannot reshape')
  • 与unstack相反,stack的作用就是把列索引的层压入行索引,其用法完全类似
df = pd.DataFrame(np.ones((4,2)),
                    index = pd.Index([('A','cat','big'),('A','dog','small'),('B','cat','big'),('B','dog','small')]),
                   columns=['index_1','index_2']).T
df
        A            B
        cat    dog        cat    dog
        big    small    big    small
index_1    1.01.01.01.0
index_2    1.01.01.01.0
df.stack()
                A        B
                cat    dog    cat    dog
index_1    big        1.0    NaN    1.0    NaN
        small    NaN    1.0    NaN    1.0
index_2    big        1.0    NaN    1.0    NaN
        small    NaN    1.0    NaN    1.0

unstack把行索引转到列索引 , stack把列索引转到行索引

聚合与变形的关系

​ 在上面介绍的所有函数中,除了带有聚合效果的 pivot_table 以外,所有的函数在变形前后并不会带来 values 个数的改变,只是这些值在呈现的形式上发生了变化

其他变形函数

读取表便于学习:

df = pd.read_csv('C:\\Users\\Yuan\\Desktop\\pandas\\文件\\data\\learn_pandas.csv')
df.head()
    School    Grade    Name    Gender    Height    Weight    Transfer    Test_Number    Test_Date    Time_Record
0    Shanghai Jiao Tong University    Freshman    Gaopeng Yang    Female    158.946.0    N    12019/10/50:04:341    Peking University    Freshman    Changqiang You    Male    166.570.0    N    12019/9/40:04:202    Shanghai Jiao Tong University    Senior    Mei Sun    Male    188.989.0    N    22019/9/120:05:223    Fudan University    Sophomore    Xiaojuan Sun    Female    NaN    41.0    N    22020/1/30:04:084    Fudan University    Sophomore    Gaojuan You    Male    174.074.0    N    22019/11/60:05:22
  • crosstab 交叉两个或多个序列成为新的表

参数:

'''
    pandas.crosstab(index, columns, values=None, rownames=None, colnames=None, aggfunc=None, margins=False, margins_name='All', dropna=True, normalize=False)
    计算两个(或更多)因子的简单交叉表。默认情况下,除非传递值数组和聚合函数,否则会计算因子的频率表。
    参数
        index:array-like, Series, or list of arrays/Series
            行中分组依据的值。

        column:array-like, Series, or list of arrays/Series
            列中分组依据的值。

        values:数组,可选
            根据因子聚合的值数组。需要指定aggfunc。

        rownames,默认无
            如果通过,则必须匹配通过的行数组数。

        colnames序列,默认无
            如果通过,则必须匹配通过的列数组的数量。

        aggfunc函数,可选
            如果指定,则还需要指定值。

        margins布尔值,默认为 False
            添加行/列边距(小计)。

        margins_name str,默认“全部”
            当边距为 True 时将包含总计的行/列的名称。

        dropna布尔值,默认为 True
            不要包括其条目全部为 NaN 的列。

        normalize bool, {'all', 'index', 'columns'} 或 {0,1},默认 False
            通过将所有值除以值的总和进行归一化。

            - 如果通过 'all' 或True,将对所有值进行标准化。
            - 如果通过“索引”将在每一行上标准化。
            - 如果通过“列”将在每一列上进行规范化。
            - 如果 margins 是True,也将规范化边距值。
'''

示例:

pd.crosstab(index = df.School, columns = df.Transfer)
Transfer                        N    Y
School        
Fudan University                381
Peking University                282
Shanghai Jiao Tong University    530
Tsinghua University                624

如果给出了

values

参数,就必须指定

aggfunc

聚合参数

pd.crosstab(index = df.School, columns = df.Transfer,
            values =[0]*df.shape[0], aggfunc ='count')#[0]*df.shape[0]只是把列表0乘以df.shape[0]就是第一维度,那这个表达式表示有第一维度的几个0
Transfer                        N        Y
School        
Fudan University                38.01.0
Peking University                28.02.0
Shanghai Jiao Tong University    53.0    NaN
Tsinghua University                62.04.0

可以使用

pivot_table

进行等价操作,由于这里统计的是组合的频数,所以

values

参数无论传入那一个列都不会影响最后的结果

df.pivot_table(index ='School',
                columns ='Transfer',
                values ='Name',
                aggfunc ='count')
Transfer                        N        Y
School        
Fudan University                38.01.0
Peking University                28.02.0
Shanghai Jiao Tong University    53.0    NaN
Tsinghua University                62.04.0
crosstab

的对应位置传入的是具体序列,而

pivot_table

传入的是被调用表的对应名字,若传入序列对应的值则会报错

  • explode展开表​ explode参数能够对某一列的元素进行纵向的展开,被展开的单元格必须存储为 **list, tuple, Series, np.ndarray**中的类型

创建表以便学习

df_ex = pd.DataFrame({'A':[[1,2],'my_str',{1,2},pd.Series([3,4])],'B':1})
df_ex
    A                        B
0[1,2]11    my_str                    12{1,2}130314 dtype: int64    1

示例1:

df_ex.explode('A')#以A列把所有的拆分
    A        B
0110211    my_str    1211221331341
  • get_dummies把类别特征转化为指示变量
#对年级一列转为指示变量,属于某一个年级的对应列标记为1,否则为0:
pd.get_dummies(df.Grade).head()
    Freshman    Junior    Senior    Sophomore
0100011000200103000140001

##连接

​ pandas的表连接与SQL的表连接相同,提供

how

参数来代表连接形式,分别为**

左连接left,右连接right,内连接inner,外连接outer

**

值连接

​ **

merge()

**

参数:

'''
    DataFrame.merge(right, how='inner', on=None, left_on=None, right_on=None, left_index=False, right_index=False, sort=False, suffixes=('_x', '_y'), copy=True, indicator=False, validate=None)
    
    将DataFrame或命名的 Series 对象与数据库样式的连接合并。
    命名的 Series 对象被视为具有单个命名列的 DataFrame。
    连接是在 列或索引 上完成的。如果在列上连接列,DataFrame 索引将被 '忽略' 。
    否则,如果加入索引上的索引或列上的索引,则索引将被传递。执行交叉合并时,不允许合并列规范。

    warning:
        如果两个键列都包含键为空值的行,则这些行将相互匹配。这与通常的 SQL 连接行为不同,并可能导致意外结果

    参数:
        right:DataFrame 或 普通的Series

        how:连接方式{‘left’, ‘right’, ‘outer’, ‘inner’, ‘cross’}, 默认 ‘inner’
            - left:仅使用左帧中的键,类似于 SQL 左外连接;保留密钥顺序。
            - right:仅使用右框架中的键,类似于 SQL 右外连接;保留密钥顺序。
            - 外部:使用来自两个帧的键并集,类似于 SQL 完全外部联接;按字典顺序对键进行排序。
            - 内部:使用来自两个帧的键的交集,类似于 SQL 内部连接;保留左键的顺序。
            - cross:从两个帧创建笛卡尔积,保留左键的顺序
        
        on:标签 或 list
            要连接的列或索引级别名称。 这些必须在两个 DataFrame 中都找到。 
            如果on为None并且没有在索引上合并,则默认为两个DataFrames中的列的交集。

        left_on:标签 或 列表 或 数组
            行列索引层级的名称连接到左DataFrame。 也可以是一个数
            组或数组的列表长度的左DataFrame。 这些数组被当作列来处理。

        right_on:标签 或 列表 或 数组
            行列索引层级的名称连接到右DataFrame。也可以是一个数
            组或数组列表的长度为正确的DataFrame。 这些数组被当作列来处理  

        left_index:布尔型 默认False
            使用来自左DataFrame的索引作为连接键。 如果它是一个MultiIndex,
            则其他DataFrame中的键的数量(索引或列的数量)必须与级别的数量匹配

        right_index:布尔型 默认False
            使用来自右DataFrame的索引作为连接键。 与left_index相同的注意事项

        sort:布尔型 默认False
            对结果DataFrame中的联接键按字典顺序排序。 如果为False,则连接键的顺序取决于连接类型(how关键字)

        suffixes:列表 默认为 (“_x”, “_y”)
            长度为2的序列,其中每个元素都是可选的字符串,指示要分别添加到左侧和右侧重叠列名的后缀。 
            传递None值而不是字符串来指示从左到右的列名应该保持原样,不带后缀。 至少有一个值不能为None

        copy:布尔型 默认为 True
            如果为False,尽可能避免复制

        indicator:布尔型 或 str 默认值为 False
            如果为True,则在输出DataFrame中添加一个名为“_merge”的列,该列包含关于每行源的信息。 
            通过提供一个字符串参数,可以给列一个不同的名称。 该列将有一个category类型的值为“left_only”,
            用于观察其合并键只出现在左DataFrame,“right_only”用于观察其合并键只出现在右DataFrame,
            如果观察的合并键在两个DataFrame中都发现,则为“both”。 

        validate: str 可选
            如果指定,则检查merge是否为指定类型。  
                - " one_to_one "或" 1:1 ":检查合并键在左右数据集中是否唯一。  
                - " one_to_many "或" 1:m ":检查合并键是否唯一的左数据集。  
                - " many_to_one "或" m:1 ":检查合并键在右数据集中是否唯一。  
                - “many_to_many”或“m:m”:允许,但不进行检查。

    return:DataFrame
        合并了两个对象的DataFrame
'''

示例:

df1 = pd.DataFrame({'Name':['San Zhang','Si Li'],'Age':[20,30]})
df2 = pd.DataFrame({'Name':['Si Li','Wu Wang'],'Gender':['F','M']})
df1.merge(df2,on='Name',how='left')#依照Name列做左连接
    Name        Age    Gender
0    San Zhang    20    NaN
1    Si Li        30    F

如果两个表中想要连接的列不具备相同的列名,可以通过

left_on

right_on
df1 = pd.DataFrame({'df1_name':['San Zhang','Si Li'],'Age':[20,30]})
df2 = pd.DataFrame({'df2_name':['Si Li','Wu Wang'],'Gender':['F','M']})
df1.merge(df2, 
            left_on='df1_name', 
            right_on='df2_name', 
            how='left')
    df1_name    Age    df2_name    Gender
0    San Zhang    20    NaN            NaN
1    Si Li        30    Si Li        F

出现重复列名可用

suffixes

参数指定

df1 = pd.DataFrame({'Name':['San Zhang'],'Grade':[70]})
df2 = pd.DataFrame({'Name':['San Zhang'],'Grade':[80]})
df1.merge(df2, 
            on='Name', 
            how='left', 
            suffixes=['_Chinese','_Math'])
    Name    Grade_Chinese    Grade_Math
0    San Zhang    7080

如果键不是唯一的,那么结果就会产生问题。举例中的行数很少,但如果实际数据中有几十万到上百万行的进行合并时,如果想要保证唯一性,除了用 duplicated 检查是否重复外, merge 中也提供了 validate 参数来检查连接的唯一性模式。这里共有三种模式,即一对一连接 1:1 ,一对多连接 1:m ,多对一连接 m:1 连接,第一个是指左右表的键都是唯一的,后面两个分别指左表键唯一和右表键唯一

索引连接

join()

示例:

df1 = pd.DataFrame({'Age':[20,30]},index=pd.Series(['San Zhang','Si Li'],name='Name'))
df2 = pd.DataFrame({'Gender':['F','M']},index=pd.Series(['Si Li','Wu Wang'],name='Name'))
df1.join(df2, how='left')
            Age        Gender
Name        
San Zhang    20        NaN
Si Li        30        F

方向连接

concat()

仍然关于索引连接,常用三个参数:

axis,join,keys

分别表示拼接方向,连接形式,以及在新表中指示来自于哪一张旧表的名字意,

join

keys

与之前提到的 join 函数和键的概念没有任何关系。

参数:

'''
    pandas.concat(objs, axis=0, join='outer', ignore_index=False, keys=None, levels=None, names=None, verify_integrity=False, sort=False, copy=True)
    沿特定轴连接pandas对象,并沿a其他轴使用可选的设置逻辑。
    还可以在连接轴上添加一层分层索引,如果标签在传递的轴号
    上相同(或重叠),这可能很有用

    参数
        objs:Series 或 DataFrame 对象的序列或映射
            如果传递了映射,则排序的键将用作键 参数,除非传递,在这
            种情况下将选择值(见下文)。任何 None 对象都将被静默删除
            ,除非它们都是 None 在这种情况下将引发 ValueError 。

        axis:{0/'index', 1/'columns'},默认 0
            要连接的轴。

        join:{'inner', 'outer'},默认 'outer'
            如何处理其他轴(或轴)上的索引。

        ignore_index:布尔值,默认为 False
            如果为 True,则不要使用连接轴上的索引值。结果轴将标记为 0,
             ..., n - 1。如果您要连接对象,而连接轴没有有意义的索引信
             息,这将非常有用。请注意,连接中仍然尊重其他轴上的索引值。

        key:序列,默认无
            如果通过了多个级别,则应包含元组。使用传递的键作为最外层构建层次索引。

        level:列表,默认无
            用于构造 MultiIndex 的特定级别(唯一值)。否则,它们将从密钥中推断出来。

        mane:列表,默认无
            生成的分层索引中的级别名称。

        verify_integrity:bool,默认为 False
            检查新的连接轴是否包含重复项。相对于实际的数据连接,这可能非常昂贵。

        sort:布尔值,默认为 False
            如果连接 为“外部”时未对齐,则对非连接轴进行排序。当已经保留了非串联轴的顺序时,这不起作用。join='inner'
            在 1.0.0 版更改:默认情况下更改为不排序。

        copy:bool,默认 True
            如果为 False,则不要不必要地复制数据。

    return object,objects
        当沿着索引 ( axisSeries =0) 连接时, Series返回 a。当objs包含至少
        一个 DataFrame时,DataFrame返回 a。当沿列连接时(axis=1),返回DataFramea 。
'''

默认状态下axis=0表示纵向连接两个表,常常用于多个样本的连接

默认状态下axis=1表示横向连接多个表,常用于多个字段或特征的拼接

df1 = pd.DataFrame({'Name':['San Zhang','Si Li'],'Age':[20,30]})
df2 = pd.DataFrame({'Name':['Wu Wang'],'Age':[40]})
pd.concat([df1, df2])
    Name        Age
0    San Zhang    201    Si Li        300    Wu Wang        40
df2 = pd.DataFrame({'Grade':[80,90]})
df3 = pd.DataFrame({'Gender':['M','F']})
pd.concat([df1, df2, df3],1)
    Name        Age        Grade    Gender
0    San Zhang    2080        M
1    Si Li        3090        F

默认状态下

join=outer

,表示保留所有列,并将不存在的值设置为缺失

df2 = pd.DataFrame({'Name':['Wu Wang'],'Gender':['M']})
pd.concat([df1, df2])
    Name        Age        Gender
0    San Zhang    20.0    NaN
1    Si Li        30.0    NaN
0    Wu Wang        NaN        M
df2 = pd.DataFrame({'Grade':[80,90]}, index=[1,2])
pd.concat([df1, df2],1)# 1 是axis
    Name        Age        Grade
0    San Zhang    20.0    NaN
1    Si Li        30.080.02    NaN            NaN        90.0
pd.concat([df1, df2], axis=1, join='inner')
    Name    Age    Grade
1    Si Li    3080

当确认要使用多表连接的方向合并时,尤其是横向的合并,可以先用reset_index方法恢复默认整数索引再进行合并,防止出现由索引的误对起和重复索引的笛卡尔积带来的错误结果

key参数是可以标记生成表的数据来自那些表

df1 = pd.DataFrame({'Name':['San Zhang','Si Li'],'Age':[20,21]})
df2 = pd.DataFrame({'Name':['Wu Wang'],'Age':[21]})
pd.concat([df1, df2], keys=['one','two'])#key是表明那些数据来自那些表
        Name        Age
one    0    San Zhang    201    Si Li        21
two    0    Wu Wang        21

序列与表的合并

​ 如果想把序列追加到表的行末或者列末,可以分别使用

append

assign

方法

  • append​ 如果原表是默认整数索引,那么可以使用ignore_index=True对新序列对应的索引自动标号,否则必须对Series指定name属性
s = pd.Series(['Wu Wang',21], index = df1.columns)
df1.append(s, ignore_index=True)
    Name        Age
0    San Zhang    201    Si Li        212    Wu Wang        21
  • assign​ 一般通过df['new_col']=...追加新列,缺点是会直接改动原表,所以assign返回的是一个临时副本
s = pd.Series([80,90])
df1.assign(Grade=s)#追加列
    Name        Age    Grade
0    San Zhang    20801    Si Li        2190
df1['Grade']= s
df1
    Name        Age    Grade
0    San Zhang    20801    Si Li        2190

类连接操作

比较

compare()

​ 它能够比较两个表或者序列的不同处并进行汇总展示

df1 = pd.DataFrame({'Name':['San Zhang','Si Li','Wu Wang'],'Age':[20,21,21],'Class':['one','two','three']})
df2 = pd.DataFrame({'Name':['San Zhang','Li Si','Wu Wang'],'Age':[20,21,21],'Class':['one','two','Three']})
df1.compare(df2)
    Name            Class
    self    other    self    other
1    Si Li    Li Si    NaN        NaN
2    NaN        NaN        three    Three

如果相同则会被填充为缺失值

nan

,其中

other

self

分别代指传入的参数表被调用的表自身

如果想要完整显示表中的所有元素的比较情况,可以设置

keep_shape=True
df1.compare(df2, keep_shape=True)
    Name            Age                Class
    self    other    self    other    self    other
0    NaN        NaN        NaN        NaN        NaN        NaN
1    Si Li    Li Si    NaN        NaN        NaN        NaN
2    NaN        NaN        NaN        NaN        three    Three

组合

combine

​ 能够让两张表按照一定规则进行组合,在进行规则比较的时候列索引会自动对其

defchoose_min(s1, s2):
    s2 = s2.reindex_like(s1)
    res = s1.where(s1<s2, s2)
    res = res.mask(s1.isna())# isna表示是否为缺失值,返回布尔序列return res

df1 = pd.DataFrame({'A':[1,2],'B':[3,4],'C':[5,6]})
df2 = pd.DataFrame({'B':[5,6],'C':[7,8],'D':[9,10]}, index=[1,2])
df1.combine(df2, choose_min)
    A    B    C    D
0    NaN    NaN    NaN    NaN
1    NaN    4.06.0    NaN
2    NaN    NaN    NaN    NaN

DataFrame.mask() 替换条件为 True 的值

overtwrite

参数为

False

可以保留被调用表中未出现在传入的参数表中的列,而不会设置为缺失值

df1.combine(df2, choose_min, overwrite=False)#A列是没有进行比较的
    A    B    C    D
01.0    NaN    NaN    NaN
12.04.06.0    NaN
2    NaN    NaN    NaN    NaN
combine_first

方法,在对两张表组合时,若第二张表中的值在第一张表中对应索引位置的值不是缺失状态,那么就使用第一张表的值填充

df1 = pd.DataFrame({'A':[1,2],'B':[3,np.nan]})
df2 = pd.DataFrame({'A':[5,6],'B':[7,8]}, index=[1,2])
df1.combine_first(df2)
    A    B
013.0127.0268.0

缺失值

###统计

  • isnaisnull​ 查看每个单元格是否缺失

读取表以便学习

df = pd.read_csv('C:\\Users\\Yuan\\Desktop\\pandas\\文件\\data\\learn_pandas.csv',
        usecols =['Grade','Name','Gender','Height','Weight','Transfer'])
df.isna().head()
    Grade    Name    Gender    Height    Weight    Transfer
0FalseFalseFalseFalseFalseFalse1FalseFalseFalseFalseFalseFalse2FalseFalseFalseFalseFalseFalse3FalseFalseFalseTrueFalseFalse4FalseFalseFalseFalseFalseFalse

如果想要查看某一列缺失或者非缺失的行,可以利用 Series 上的

isna

或者

notna

进行布尔索引

df[df.Height.isna()].head()
    Grade        Name            Gender    Height    Weight    Transfer
3    Sophomore    Xiaojuan Sun    Female    NaN        41.0    N
12    Senior        Peng You        Female    NaN        48.0    NaN
26    Junior        Yanli You        Female    NaN        48.0    N
36    Freshman    Xiaojuan Qin    Male    NaN        79.0    Y
60    Freshman    Yanpeng Lv        Male    NaN        65.0    N

同时对几个列检查缺失情况可以用

isna,notna

any,all

的组合

'''
    any()一个序列中满足一个True,则返回True;
    all()一个序列中所有值为True时,返回True,否则为False
'''

参数:

'''
    DataFrame.any(self, axis=0, bool_only=None, skipna=True, level=None, **kwargs)
        DataFrame.all(self, axis=0, bool_only=None, skipna=True, level=None, **kwargs)
        参数
            参数
            axis:{0 或 'index',1 或 'columns',无},默认 0
                指示应减少哪个轴或多个轴。
                    0 / 'index' : 减少索引,返回一个以原始列标签为索引的系列。
                    1 / 'columns' :减少列,返回一个索引为原始索引的系列。
                    None:减少所有轴,返回一个标量。
            bool_only:布尔值,默认None
                仅包括布尔列。如果没有,将尝试使用所有内容,然后仅使用布尔数据。未针对系列实施。

            skipna:布尔值,默认为 True
                排除 NA/空值。如果整个行/列为 NA 且 skipna 为 True,则结果将为 False,与空行/列一样。
                如果 skipna 为 False,则 NA 被视为 True,因为它们不等于零。

            level: int 或 层级名称,默认无
                如果轴是 MultiIndex(分层),则沿特定级别计数,折叠成一个系列。

        Returns:Series or DataFrame
            如果指定了level,则返回DataFrame;否则,返回Series
'''

示例1:

sub_set = df[['Height','Weight','Transfer']]
df[sub_set.isna().all(1)]# 全部缺失
    Grade    Name            Gender    Height    Weight    Transfer
102    Junior    Chengli Zhao    Male    NaN        NaN        NaN

示例2:

df[sub_set.isna().any(1)].head()# 至少有一个缺失
    Grade        Name            Gender    Height    Weight    Transfer
3    Sophomore    Xiaojuan Sun    Female    NaN        41.0    N
9    Junior        Juan Xu            Female    164.8    NaN        N
12    Senior        Peng You        Female    NaN        48.0    NaN
21    Senior        Xiaopeng Shen    Male    166.062.0    NaN
26    Junior        Yanli You        Female    NaN        48.0    N

示例3:

df[sub_set.notna().all(1)].head()# 没有缺失
    Grade        Name            Gender    Height    Weight    Transfer
0    Freshman    Gaopeng Yang    Female    158.946.0    N
1    Freshman    Changqiang You    Male    166.570.0    N
2    Senior        Mei Sun            Male    188.989.0    N
4    Sophomore    Gaojuan You        Male    174.074.0    N
5    Freshman    Xiaoli Qian        Female    158.051.0    N

删除

  • dropna​ 主要参数为方向**axis(默认为0,即删除行),删除方式how,删除的非缺失值个数阈值thresh(非缺失值 没有达到这个数量的相应维度会被删除),备选的删除子集subset,其中how**主要有anyall两种参数可以选择

参数:

'''
    DataFrame.dropna(axis=0, how='any', thresh=None, subset=None, inplace=False)
    删除缺失值。
    参数
        axis:{0 或 'index',1 或 'columns'},默认 0
            确定是否删除了包含缺失值的行或列。
                0 或 'index' :删除包含缺失值的行。
                1 或 'columns' :删除包含缺失值的列。
                (在 1.0.0 版更改:将元组或列表传递到多个轴上。只允许使用单个轴。)

        how:{'any', 'all'}, 默认 'any'
        当我们至少有一个 NA 或全部 NA 时,确定是否从 DataFrame 中删除行或列。
            'any' :如果存在任何 NA 值,则删除该行或列。
            'all' :如果所有值都是 NA,则删除该行或列。

        thresh: int,可选
            删除的非缺失值个数阈值,非缺失值 没有达到这个数量的相应维度会被删除
            其实就是删除条件

        subset:列标签或标签序列,可选
            要考虑的沿其他轴的标签,例如,如果您要删除行,这些将是要包含的列列表。

        inplace:bool,默认 False
            如果为 True,则在原地执行操作并返回 None。
'''

示例1:

res = df.dropna(how ='any', subset =['Height','Weight'])
res.shape
(174,6)

示例2:

res = df.dropna(1, thresh=df.shape[0]-15)# 身高被删除
res.head()#没有达到thresh的条件
    Grade        Name            Gender    Weight    Transfer
0    Freshman    Gaopeng Yang    Female    46.0    N
1    Freshman    Changqiang You    Male    70.0    N
2    Senior        Mei Sun            Male    89.0    N
3    Sophomore    Xiaojuan Sun    Female    41.0    N
4    Sophomore    Gaojuan You        Male    74.0    N

不用

dropna

也可以用布尔索引完成

res = df.loc[df[['Height','Weight']].notna().all(1)]
res.shape
(174,6)
res = df.loc[:,~(df.isna().sum()>15)]
res.head()
    Grade        Name            Gender    Weight    Transfer
0    Freshman    Gaopeng Yang    Female    46.0    N
1    Freshman    Changqiang You    Male    70.0    N
2    Senior        Mei Sun            Male    89.0    N
3    Sophomore    Xiaojuan Sun    Female    41.0    N
4    Sophomore    Gaojuan You        Male    74.0    N

填充

  • fillna​ 最常用三个参数:value,method,limit​ 其中value为填充值,可以是标量,也可以是索引到元素的字典映射method为填充给方法,有用前面的元素填充fill后面的元素填充bfill两种类型​ limit 参数表示连续缺失值的最大填充次数

参数:

'''
    DataFrame.fillna(value=None, method=None, axis=None, inplace=False, limit=None, downcast=None)
    使用指定的方法填充 NA/NaN 值
    参数
        value:标量、dict、Series 或 DataFrame
            用于填充孔的值(例如 0),或者是值的 dict/Series/DataFrame,指定每个索引(对于 Series)或列(对于 DataFrame)使用哪个值。
            不在 dict/Series/DataFrame 中的值将不会被填充。'此值不能是列表'。

        method:{'backfill', 'bfill', 'pad', 'ffill', None},默认None
            用于填充重新索引系列垫/填充中的孔的方法:
                将最后一个有效观察向前传播到下一个有效回填/bfill:使用下一个有效观察来填充间隙。

        axis:{0 或“索引”、1 或“列”}
            沿其填充缺失值的轴。

        inplace:bool,默认 False
            如果为真,则就地填写。
                注意:这将修改此对象上的任何其他视图(例如,DataFrame 中列的无复制切片)。

        limit: int 默认None
            如果指定了方法,则这是向前/向后填充的连续 NaN 值的最大数量。
            换句话说,如果有超过这个数量的连续 NaN 的间隙,它只会被部分填充。
            如果未指定方法,则这是沿整个轴将填充 NaN 的最大条目数。如果不是无,则必须大于 0。

        downcast:dict,默认为 None
            一个 item->dtype 的字典,如果可能的话,或者字符串 'infer',
            它将尝试向下转换为适当的相等类型(例如,如果可能,float64 到 int64)
'''

创建表以便学习

s = pd.Series([np.nan,1, np.nan, np.nan,2, np.nan],list('aaabcd'))
s

示例1:

s.fillna(method='ffill')# 用前面的值向后填充
a    NaN
a    1.0
a    1.0
b    1.0
c    2.0
d    2.0
dtype: float64

示例2:

s.fillna(method='ffill', limit=1)# 连续出现的缺失,最多填充一次
a    NaN
a    1.0
a    1.0
b    NaN
c    2.0
d    2.0
dtype: float64

示例3:

s.fillna(s.mean())# value为标量
a    1.5
a    1.0
a    1.5
b    1.5
c    2.0
d    1.5
dtype: float64

示例4:

s.fillna({'a':100,'d':200})# 通过索引映射填充的值
a    100.0
a      1.0
a    100.0
b      NaN
c      2.0
d    200.0
dtype: float64

有时为了更加合理地填充,需要先进行分组后再操作

df.groupby('Grade')['Height'].transform(lambda x: x.fillna(x.mean())).head()
0158.9000001166.5000002188.9000003163.0758624174.000000
Name: Height, dtype: float64

插值

​ 对于

interpolate

而言,除了插值方法(默认为 linear 线性插值)之外,有与 fillna 类似的两个常用参数,一个是控制方向的 limit_direction ,另一个是控制最大连续缺失值插值个数的 limit 。其中,限制插值的方向默认为 forward ,这与 fillna 的 method 中的 ffill 是类似的,若想要后向限制插值或者双向限制插值可以指定为 backward 或 both 。

Nullable类型

####基本概念

​ 在 python 中的缺失值用 None 表示,该元素除了等于自己本身之外,与其他任何元素不相等

print(None==None)None==False
TrueFalse

​ 在 numpy 中利用 np.nan 来表示缺失值,该元素除了不和其他任何元素相等之外,和自身的比较结果也返回 False

np.nan == np.nan
False

注意:虽然在对缺失序列或表格的元素进行比较操作的时候

np.nan

的对应位置会返回**

False

,但是在使用

equals

函数进行两张表或两个序列的相同性检验时,会自动跳过两侧表都是缺失值的位置,直接返回

True

**

'''
    DataFrame.equals(other)
    测试两个对象是否包含相同的元素。
    此功能允许将两个 Series 或 DataFrame 相互比较,以查看它们是否具
    有相同的形状和元素。同一位置的 NaN 被认为是相等的。
    行/列索引不需要具有相同的类型,只要值被认为是相等的。对应的列必须
    参数
        other:Series或DataFrame
            要与第一个进行比较的其他 Series 或 DataFrame。具有相同的 dtype。

    return:bool
        如果两个对象中的所有元素都相同,则为 True,否则为 False
'''

示例1:

s1 = pd.Series([1, np.nan])
s2 = pd.Series([1,2])
s3 = pd.Series([1, np.nan])
s1 ==1
0True1False
dtype:bool

示例2:

s1.equals(s2)
False

示例3:

s1.equals(s3)
True

​ 在时间序列的对象中, pandas 利用

pd.NaT

来指代缺失值,它的作用和 **

np.nan

是一致的**

pd.to_timedelta(['30s', np.nan])# Timedelta中的NaT
TimedeltaIndex(['0 days 00:00:30', NaT], dtype='timedelta64[ns]', freq=None)
pd.to_datetime(['20200101', np.nan])# Datetime中的NaT
DatetimeIndex(['2020-01-01','NaT'], dtype='datetime64[ns]', freq=None)

​ 在 pandas 中可以看到 object 类型的对象,而 object 是一种混杂对象类型,如果出现了多个类型的元素同时存储在 Series 中,它的类型就会变成 object

​ NaT的问题根源在于np.nan本身是一种浮点型,如果浮点型和时间类型混合存储,就会成为object

​ 因此,pandas尝试设计了一种新的缺失类型pd.NA以及三种Nullable序列类型来应对,它们分别是

Int,boolean和strin

性质

​ Nullable性质就是序列类型不受缺失值影响的类型

​ 在**

Int,boolean和strin

中存储缺失值**,pandas都会转为内置的

pd.NA

示例1:

pd.Series([np.nan,1], dtype ='Int64')# "i"是大写的
0<NA>11
dtype: Int64

示例2:

pd.Series([np.nan,True], dtype ='boolean')
0<NA>1True
dtype: boolean

示例3:

pd.Series([np.nan,'my_str'], dtype ='string')
0<NA>1    my_str
dtype: string

如果在Int类型序列乘以小数,只会是浮点型

  • pandas的boolean类型 与 python的bool类型的区别

1 . 带有缺失值的布尔列表无法进行索引器选择,,而**

boolean

**会把缺失值看作

False
s = pd.Series(['a','b'])
s_bool = pd.Series([True, np.nan])#不会把np.nan看成False+
s_boolean = pd.Series([True, np.nan]).astype('boolean')# s[s_bool] # 报错
s[s_boolean]
0    a
dtype:object

2 . 在逻辑运算的时候**bool类型在缺失处返回的永远是

False

**,而

boolean

会根据逻辑运算是否能确定唯一结果来返回相应的值

s_boolean &True
0True1<NA>
dtype: boolean
s_boolean |True
0True1True
dtype: boolean
~s_boolean # 取反操作同样是无法唯一地判断缺失结果
0False1<NA>
dtype: boolean
  • 一般在实际数据处理时,可以在数据集读入后,先通过convert_dtypes转为Nullable类型
df = pd.read_csv('C:\\Users\\Yuan\\Desktop\\pandas\\文件\\data\\learn_pandas.csv')
df = df.convert_dtypes()
df.dtypes
School          string
Grade           string
Name            string
Gender          string
Height         Float64
Weight           Int64
Transfer        string
Test_Number      Int64
Test_Date       string
Time_Record     string
dtype:object

计算和分组

​ 当调用函数sum,prod使用加法和乘法的时候,缺失数据等价于被分别视作0和1,即不改变原来的计算

s = pd.Series([2,3,np.nan,4,5])
s.sum()
14.0
s.prod()
120.0

​ 当使用累计函数时,会自动跳过缺失值所处的位置

s.cumsum()
02.015.02     NaN
39.0414.0
dtype: float64

​ 除了

np.nan**0

np.nan**1

这两种情况为确定值之外(结果为

1.0

),所有运算返回结果全为缺失(pd.NA的行为与此一致),并且

np.nan

在**比较操作时一定返回

False

,而

pd.NA

返回

pd.NA

**

diff与pct_change

​ 前者凡是缺失计算都设置为缺失值,后者**缺失位置会被设置为

0%

的变化率**

  • diff
s.diff()
0    NaN
11.02    NaN
3    NaN
41.0
dtype: float64
  • pct_change()
s.pct_change()
0         NaN
10.50000020.00000030.33333340.250000
dtype: float64

缺失值分组

​ 缺失值可以作为一个类别来处理,在分组(

groupby

)里面的**

get_dummies

函数来增加缺失类别**

创建表便于学习

df_nan = pd.DataFrame({'category':['a','a','b',np.nan,np.nan],'value':[1,3,5,7,9]})
df_nan
    category    value
0        a        11        a        32        b        53        NaN        74        NaN        9

示例:

#先分组
df_nan.groupby('category',dropna=False)['value'].mean()# pandas版本大于1.1.0
category
a      2.0
b      5.0
NaN    8.0
Name: value, dtype: float64
pd.get_dummies(df_nan.category, dummy_na=True)
    a    b    NaN
01001100201030014001

文本数据

str对象

str 对象是定义在 Index 或 Series 上的属性,与python中的str模块类似

var ='abcd'str.upper(var)# Python内置str模块
'ABCD'
s = pd.Series(['abcd','efg','hi'])
s.str.upper()# pandas中str对象上的upper方法
0    ABCD
1     EFG
2      HI
dtype:object

string类型

文本处理操作

拆分

str.split()

​ 第一个参数为**

正则表达式

,第二个参数为从左到右最大拆分**字数

n

,是否展开为多个列

expand
s = pd.Series(['上海市黄浦区方浜中路249号','上海市宝山区密山路5号'])
s.str.split('[市区路]')#正则表达式
0[上海, 黄浦, 方浜中,249号]1[上海, 宝山, 密山,5号]
dtype:object
s.str.split('[市区路]', n=2, expand=True)#n最大拆分次数,expend是否展开多个列
0120    上海    黄浦    方浜中路249号
1    上海    宝山    密山路5号

合并

str.join()

​ 用某个链接把

Series

中的字符串列表连起来,列表中出现了非字符串元素则返回缺失值

s = pd.Series([['a','b'],[1,'a'],[['a','b'],'c']])
s.str.join('-')#因为出现非字符串元素,所以返回了缺失值
0    a-b
1    NaN
2    NaN
dtype:object

str.cat()

​ 用于合并两个序列,主要参数为**

连接符sep,连接形式join,缺失值代替符号na_rep

,其中连接形式默认为以索引为键的左连接**

s1 = pd.Series(['a','b'])
s2 = pd.Series(['cat','dog'])
s1.str.cat(s2,sep='-')
0    a-cat
1    b-dog
dtype:object
s2.index =[1,2]
s1.str.cat(s2, sep='-', na_rep='?', join='outer')#na_rep缺失值代替符号
0      a-?
1    b-cat
2    ?-dog
dtype:object

匹配

str.contains()

​ 返回每个字符串是否符合正则表达式的布尔索引

s = pd.Series(['my cat','he is fat','railway station'])
s.str.contains('\s\wat')#给出正则模式,查找包含了这个正则的字符串元素,如果找得到就返回True
0True1True2False
dtype:bool

str.startswith()

返回以给定模式开始布尔序列

str.endwith()

返回以给定模式结束布尔序列

他们都不支持正则表达式

s.str.startswith('my')#指定开始字符
0True1False2False
dtype:bool
s.str.endswith('t')#指定结束字符
0True1True2False
dtype:bool

str.match()

返回每组字符串是否符合正则表达式布尔序列

s.str.match('m|h')
0True1True2False
dtype:bool
s.str[::-1].str.match('ta[f|g]|n')# 反转后匹配
0False1True2True
dtype:bool

当然,这些也能通过在 str.contains 的正则中使用 ^ 和

$

来实现

s.str.contains('^[m|h]')
0True1True2False
dtype:bool

返回索引的匹配函数

​ **

str.find()

** 返回从左到右第一次匹配的位置索引,未找到则返回

-1

​ **

str.rfind()

** 返回从右到左第一次匹配的位置索引,未找到则返回

-1
s = pd.Series(['This is an apple. That is not an apple.'])
s.str.find('apple')
011
dtype: int64
s.str.rfind('apple')
033
dtype: int64

替换

str.replace()

str.replace

replace

并不是一个函数,在使用字符串替换时应当使用前者

参数:

'''
    Series.str.replace(pat, repl, n=- 1, case=None, flags=0, regex=None)
    替换系列/索引中每次出现的模式/正则表达式
    参数
        pat:str或编译的正则表达式
            字符串可以是字符序列或正则表达式。

        repl:str或可调用
            替换ment字符串或可调用对象。可调用对象传递正则表达式匹配对象,
            并且必须返回要使用的替换字符串。见re.sub()。

        n:int,默认 -1(全部)
            从一开始就进行的更换次数。

        case:布尔值,默认无
            确定替换是否区分大小写:
                如果为 True,则区分大小写(如果pat是字符串,则为默认值)
                设置为 False 不区分大小写
                如果pat是已编译的正则表达式,则无法设置。

        flags:int,默认 0(无标志)
            正则表达式模块标志,例如 re.IGNORECASE。如果pat是已编译的正则表达式,则无法设置。

        regex:bool,默认 True
            确定传入的模式是否是正则表达式:
                如果为 True,则假定传入的模式是正则表达式。
                如果为False ,则将模式视为文字字符串
                如果pat是已编译的正则表达式或repl是可调用的,则不能设置为 False 。
'''
s = pd.Series(['a_1_b','c_?'])
s.str.replace('\d|\?','new', regex=True)#regex是否使用正则表达式
0    a_new_b
1      c_new
dtype:object
  • 当需要对不同部分进行有差别的替换时,用子组的方法可以通过传入自定义的替换函数来分别处理字符串

注意:group(k)代表匹配到第k个子组

创建表便于学习

s = pd.Series(['上海市黄浦区方浜中路249号','上海市宝山区密山路5号','北京市昌平区北农路2号'])

pat ='(\w+市)(\w+区)(\w+路)(\d+号)'

city ={'上海市':'Shanghai','北京市':'Beijing'}

district ={'昌平区':'CP District','黄浦区':'HP District','宝山区':'BS District'}

road ={'方浜中路':'Mid Fangbin Road','密山路':'Mishan Road','北农路':'Beinong Road'}

创建字符串替换函数:

#创建字符替换函数defmy_func(m):
    str_city = city[m.group(1)]
    str_district = district[m.group(2)]
    str_road = road[m.group(3)]
    str_no ='No. '+ m.group(4)[:-1]return' '.join([str_city,
                    str_district,
                    str_road,
                    str_no])
s.str.replace(pat, my_func, regex=True)
0    Shanghai HP District Mid Fangbin Road No.2491           Shanghai BS District Mishan Road No.52           Beijing CP District Beinong Road No.2
dtype:object
  • 可以使用 命名子组 更加清晰地写出子组代表的含义
#创建正则表达式并给每个组命名
pat ='(?P<市名>\w+市)(?P<区名>\w+区)(?P<路名>\w+路)(?P<编号>\d+号)'#<>中间的就是组的名字defmy_func(m):
    str_city = city[m.group('市名')]
    str_district = district[m.group('区名')]
    str_road = road[m.group('路名')]
    str_no ='No. '+ m.group('编号')[:-1]return' '.join([str_city,
                    str_district,
                    str_road,
                    str_no])

s.str.replace(pat, my_func, regex=True)
0    Shanghai HP District Mid Fangbin Road No.2491           Shanghai BS District Mishan Road No.52           Beijing CP District Beinong Road No.2
dtype:object

提取

str.extract(regex)

​ 用正则表达式提取字符串(只匹配一个)

pat ='(\w+市)(\w+区)(\w+路)(\d+号)'
s.str.extract(pat)
01230    上海市    黄浦区    方浜中路    249号
1    上海市    宝山区    密山路        5号
2    北京市    昌平区    北农路        2号
  • 通过子组的命名,可以直接对新生成 DataFrame 的列命名
pat ='(?P<市名>\w+市)(?P<区名>\w+区)(?P<路名>\w+路)(?P<编号>\d+号)'
s.str.extract(pat)
    市名    区名        路名        编号
0    上海市    黄浦区    方浜中路    249号
1    上海市    宝山区    密山路        5号
2    北京市    昌平区    北农路        2号

str.extractall()

​ 它会把所有符合条件的模式全部匹配出来,如果存在多个结果,则以多级索引的方式存储

s = pd.Series(['A135T15,A26S5','B674S2,B25T6'], index =['my_A','my_B'])
pat ='[A|B](\d+)[T|S](\d+)'
s.str.extractall(pat)
01
    match        
my_A    0135151265
my_B    067421256
pat_with_name ='[A|B](?P<name1>\d+)[T|S](?P<name2>\d+)'
s.str.extractall(pat_with_name)
01
    match        
my_A    0135151265
my_B    067421256

str.findall()

​ 也是把所有符合条件的模式全部匹配出来,但是它把结果存入列表

s.str.findall(pat)
my_A    [(135,15),(26,5)]
my_B     [(674,2),(25,6)]
dtype:object

常用字符串函数

字符串函数

  • str.upper(小写变大写)
  • str.lower(大写变小写)
  • str.swapcase(小写变大写,大写变小写)
  • str.capitalize(句首大写,其余都小写)
  • str.title(单词首字母大写,其余都小写)

数值型函数

pd.to_numeric

对字符格式的数值进行快速转换和筛选,其主要参数包括

errors

downcast

分别代表了非数的处理模式转换类型。其中,对于不能转换为数值的有三种

errors

选项,

raise

,

coerce

,

ignore

分别表示直接报错设为缺失以及保持原来的字符串

s = pd.Series(['1','2.2','2e','??','-2.1','0'])
pd.to_numeric(s, errors='ignore')
0112.222e3      ??
4-2.150
dtype:object
pd.to_numeric(s, errors='coerce')
01.012.22    NaN
3    NaN
4-2.150.0
dtype: float64
  • 数据清洗的时候,可以利用**coerce快速查看非数值型的行**
s[pd.to_numeric(s, errors='coerce').isna()]
22e3    ??
dtype:object

统计型函数

count

len

的作用分别是返回出现正则表达式匹配的次数字符串的长度

s = pd.Series(['cat rat fat at','get feed sheet heat'])
s.str.count('[r|f]at|ee')
0212
dtype: int64
s.str.len()
014119
dtype: int64

格式型函数

  • 除空型strip() 去除两侧空格​ rstrip() 去除右侧空格​ lstrip() 去除左侧空格
  • 填充型pad()​ 可以选定字符串长度填充的方向填充内容
s = pd.Series(['a','b','c'])
s.str.pad(5,'left','*')
0****a
1****b
2****c
dtype:object
left,right,both

both

是两边一起填充

  • 填充型的pad()可以用rjust,ljust,center来等效完成

**

ljust

右填充

rjust

左填充**

  • 在读取 excel 文件时,经常会出现数字前补0的需求除了可以使用上面的左侧填充函数进行操作之外,还可用 zfill 来实现

例如证券代码读入的时候会把”000007”作为数值7来处理

s = pd.Series([7,155,303000]).astype('string')
s.str.zfill(6)
000000710001552303000
dtype: string

分类数据

cat对象

分类类型

category

​ 可以用

astype()

方法直接转为

category

类型

读取表格便于学习

df = pd.read_csv('C:\\Users\\Yuan\\Desktop\\pandas\\文件\\data\\learn_pandas.csv',
    usecols =['Grade','Name','Gender','Height','Weight'])
s = df.Grade.astype('category')
s.head()
0     Freshman
1     Freshman
2       Senior
3    Sophomore
4    Sophomore
Name: Grade, dtype: category
Categories (4,object):['Freshman','Junior','Senior','Sophomore']

分类类型中定义了cat对象,与str类似,可以使用属性和方法

s.cat 
<pandas.core.arrays.categorical.CategoricalAccessor object at 0x000001C2A8498970>

​ 分类类型具有两个部分

​ 1 .

categories

类别本身(以Index类型存储)

​ 2 .

ordered

是否有序

s.cat.categories#类别本身
Index(['Freshman','Junior','Senior','Sophomore'], dtype='object')
s.cat.ordered#是否有序
False

codes

用来访问类别被赋予的唯一整数编号

s.cat.codes.head()
0010223343
dtype: int8

####增,删,改

注意:

Index

类型是无法用

index_obj[0] = item

来修改的

  • add_categories 类别的增加
s = s.cat.add_categories('Graduate')# 增加一个毕业生类别
s.cat.categories
Index(['Freshman','Junior','Senior','Sophomore','Graduate'], dtype='object')
  • remove_categories删除类别​ 原来的序列中该类会被设置为缺失
s = s.cat.remove_categories('Freshman')
s.cat.categories
Index(['Junior', 'Senior', 'Sophomore', 'Graduate'], dtype='object')
s.head()
0          NaN
1          NaN
2       Senior
3    Sophomore
4    Sophomore
Name: Grade, dtype: category
Categories (4,object):['Junior','Senior','Sophomore','Graduate']
  • set_categories设置序列的类别​ 原先的类别会被覆盖,不满足就会设置为缺失
s = s.cat.set_categories(['Sophomore','PhD'])# 新类别为大二学生和博士
s.cat.categories
Index(['Sophomore','PhD'], dtype='object')
s.head()
0          NaN
1          NaN
2          NaN
3    Sophomore
4    Sophomore
Name: Grade, dtype: category
Categories (2,object):['Sophomore','PhD']
  • remove_unused_categories删除未出现在序列中的类别
s = s.cat.remove_unused_categories()# 移除了未出现的博士生类别
s.cat.categories#序列中只有Sophomore
Index(['Sophomore'], dtype='object')
  • rename_categories更改类别​ 以字典的方式更改类别​ 这个方法会对原序列的对应值也进行相应修改
s = s.cat.rename_categories({'Sophomore':'本科二年级学生'})
s.head()
0        NaN
1        NaN
2        NaN
3    本科二年级学生
4    本科二年级学生
Name: Grade, dtype: category
Categories (1,object):['本科二年级学生']

###有序分类

as_unordered

有序类别

reorder_categories

无序类别

无序类别:

​ 传入的参数必须是由当前序列的无序类别构成的列表,不能够增加新的类别,也不能缺少原来的类别,并且**必须指定参数

ordered=True

**,否则方法无效

s = df.Grade.astype('category')
s = s.cat.reorder_categories(['Freshman','Sophomore','Junior','Senior'],ordered=True)#无序
s.head()
0     Freshman
1     Freshman
2       Senior
3    Sophomore
4    Sophomore
Name: Grade, dtype: category
Categories (4,object):['Freshman'<'Sophomore'<'Junior'<'Senior']
s.cat.as_unordered().head()
0     Freshman
1     Freshman
2       Senior
3    Sophomore
4    Sophomore
Name: Grade, dtype: category
Categories (4,object):['Freshman','Sophomore','Junior','Senior']

如果不想指定

ordered=True

参数,那么可以先用

s.cat.as_ordered()

转化为有序类别,再利用

reorder_categories

进行具体的相对大小调整。

排序和比较

​ 只需把列的类型修改为

category

后,再赋予相应的大小关系,就能正常地使用 **

sort_index

** 和 **

sort_values

** 进行排序

==

,

!=

,

>,>=,<,<=

都能进行比较,返回布尔型

区间类别

cut/qcut

cut

参数:

'''
    pandas.cut(x, bins, right=True, labels=None, retbins=False, precision=3, include_lowest=False, duplicates='raise', ordered=True)
    将值分箱到离散区间中
    参数
        x:array-like
            要装箱的输入数组。必须是一维的。

        bins:int、sequence of scalars(标量序列) 或 IntervalIndex
        要装箱依据的条件。
            int :定义 x 范围内等宽条柱的数量。x 的范围在每侧扩展 0.1%,以包括 x 的最小值和最大值。
            sequence of scalars(标量序列) :定义允许非均匀宽度的条柱边。不扩展 x 的范围。
            IntervalIndex(间隔索引) :定义要使用的确切条柱。请注意,条柱的间隔索引必须是非重叠的。

        right:布尔型 默认为 True
            指示条柱是否包含最右边。如果(默认值),则条柱指示 (1,2]、(2,3]、(3,4)。当条柱是
            间隔索引时,将忽略此参数。right == True[1, 2, 3, 4]

        labels:array 或 False,默认值"None"
            指定返回的条柱的标签。长度必须与生成的条柱相同。如果为 False,则仅返回条柱的整数指示符。
            这会影响输出容器的类型(见下文)。当条柱是间隔索引时,将忽略此参数。如果为 True,则引发错误。当排序=False时,必须提供标签。

        retbins:bool 默认 False
            是否退回垃圾箱。当箱作为标量提供时很有用。

        precision:int 默认值 3
            存储和显示库标签的精度。

        include_lowest:布尔型,默认为 False
            第一个间隔是否应为左包含区间。

        duplicates:{默认 ‘raise’, ‘drop’},可选
            如果条柱边不唯一,请提高 ValueError 或删除非唯一边。

        ordered:布尔,默认为 True
            标签是否订购。适用于返回的类型"分类"和"系列"(使用分类 dtype)。如果为 True,则将对生成的
            分类进行排序。如果为 False,则生成的分类将是无序的(必须提供标签)。

    返回
        out:Categoryial, Series, or ndarray
            一个类似数组的对象,表示 x 的每个值的相应 bin。类型取决于标签的值。
            None(默认值):为系列 x 返回一个系列,为所有其他输入返回一个分类。其中存储的值为间隔 dtype。
            标量序列 :返回序列 x 的序列或所有其他输入的类别。其中存储的值是序列中的任何类型。
            False :返回整数的 ndarray。

        bins:numpy.ndarray 或 IntervalIndex.
            计算的或指定的条柱。仅当 retbins=True 时才返回。对于标量或序列条柱,这是一个包含计算箱的 ndarray。
            如果设置重复项 = 丢弃,则条柱将丢弃非唯一条柱。对于间隔索引条柱,这等于条柱。
'''

​ 最重要的参数是

bins

,传入整数

n

代表把整个传入数组的按照最大和最小值等间距地分为

n

区间默认是左开右闭,需要在调整时把最小值包含进去

​ pandas中的解决方案是在值最小的区间左端点减去**

0.001*(max-min)

**

​ 指定左闭右开时,需要把

right

参数设置为

False

,相应的区间调整方法是在值最大的区间右端点加上 **

0.001*(max-min)

**

示例1:

s = pd.Series([1,2])
pd.cut(s, bins=2)'''
    因为要包含最小值1,所以pandas做了 1-0.001*(2-1) 这个运算(1是左端点)
'''
0(0.999,1.5]1(1.5,2.0]
dtype: category
Categories (2, interval[float64]):[(0.999,1.5]<(1.5,2.0]]

示例2:

pd.cut(s, bins=2, right=False)#right左闭右开'''
    因为要包含最大值2,所以pandas做了 2+0.001*(2-1) 这个运算(2是右端点)
'''
0[1.0,1.5)1[1.5,2.001)
dtype: category
Categories (2, interval[float64]):[[1.0,1.5)<[1.5,2.001)]
  • 指定区间分割点​ 给bins一个列表np.infty表示无穷大
pd.cut(s, bins=[-np.infty,1.2,1.8,2.2, np.infty])
0(-inf,1.2]1(1.8,2.2]
dtype: category
Categories (4, interval[float64]):[(-inf,1.2]<(1.2,1.8]<(1.8,2.2]<(2.2, inf]]
  • 分割点常用参数labels:指定区间名字​ retbins:是否返回分割点(默认False)​ 指定True之后会返回两个对象,第一个是区间分区,第二个是分割点数组,可以用索引访问
s = pd.Series([1,2])
res = pd.cut(s, bins=2, labels=['small','big'], retbins=True)
res[0]
0    small
1      big
dtype: category
Categories (2,object):['small'<'big']
res[1]# 该元素为返回的分割点
array([0.999,1.5,2.])

qcut

参数:

'''
    pandas.qcut(x, q, labels=None, retbins=False, precision=3, duplicates='raise')
    基于分位数的离散化函数。
    根据排名或基于样本分位数将变量离散化为大小相等的桶
    
    参数:
         x:array-like
            要装箱的输入数组。必须是一维的。
            
         q:int 或 list(float)
            分位数。10 用于十分位数,4 用于四分位数等。交替排列的分位数,例如 [0, .25, .5, .75, 1.] 用于四分位数。
            
         labels:array或False,默认None
            用作结果箱的标签。必须与生成的 bin 长度相同。如果为 False,则仅返回 bin 的整数指示符。如果为 True,则引发错误。
            
         retbins:bool 默认 False
            是否退回垃圾箱。当箱作为标量提供时很有用。
            
         precision:int 默认 3
            存储和显示库标签的精度。
            
         duplicates:{默认 ‘raise’, ‘drop’},可选
            如果条柱边不唯一,请提高 ValueError 或删除非唯一边
            
     return:
         out:如果标签为 False,则输出分类或系列或整数数组返回类型(分类或系列)取决于输入:如果输入是系列,则为类别类型系列,否则为分类。当返回分类数据时,bin 表示为类别。

        bins:浮点数的ndarray
            仅当retbins为 True 时才返回
'''

qcut

只是把

bins

参数改成

q

q

参数是指

quantile

,这里的

q

整数

n

时,指按照

n

等分位数把数据分箱,还可以传入浮点列表指代相应的分位数分割点

s = df.Weight
pd.qcut(s, q=[0,0.2,0.8,1]).head()
0(44.0,69.4]1(69.4,89.0]2(69.4,89.0]3(33.999,44.0]4(69.4,89.0]
Name: Weight, dtype: category
Categories (3, interval[float64]):[(33.999,44.0]<(44.0,69.4]<(69.4,89.0]]

####区间构造

​ 三要素:左端点,右端点,开闭状态

开闭状态可以指定

right, left, both, neither

中的一类

my_interval = pd.Interval(0,1,'right')
my_interval
Interval(0,1, closed='right')

函数:

pd.Interval()

​ 此函数创建的对象属性:

​ 属性包含了

mid, length, right, left, closed

,分别表示中点、长度、右端点、左端点和开闭状态

​ 使用

in

可以判断元素是否属于区间

​ 使用

overlaps

可以判断两个区间是否有交集

  • pd.IntervalIndex对象**from_breaks**传入列表,每个元素依次为左右端点
pd.IntervalIndex.from_breaks([1,3,6,10], closed='both')
IntervalIndex([[1,3],[3,6],[6,10]],
              closed='both',
              dtype='interval[int64]')

​ **

from_arrays

传入两个列表,两个列表的元素为对应形式**成立区间

pd.IntervalIndex.from_arrays(left =[1,3,6,10],
                             right =[5,4,9,11],
                             closed ='neither')
IntervalIndex([(1,5),(3,4),(6,9),(10,11)],
              closed='neither',
              dtype='interval[int64]')

​ **

from_tuples

**传入元组的列表,每个元组为一个区间

pd.IntervalIndex.from_tuples([(1,5),(3,4),(6,9),(10,11)],
                             closed='neither')
IntervalIndex([(1,5),(3,4),(6,9),(10,11)],
              closed='neither',
              dtype='interval[int64]')

​ **

interval_range

生成等差**区间

​ 参数:

start, end, periods, freq

起点、终点、区间个数和区间长度

pd.interval_range(start=1,end=5,periods=8)
IntervalIndex([(1.0,1.5],(1.5,2.0],(2.0,2.5],(2.5,3.0],(3.0,3.5],(3.5,4.0],(4.0,4.5],(4.5,5.0]],
              closed='right',
              dtype='interval[float64]')
pd.interval_range(end=5,periods=8,freq=0.5)
IntervalIndex([(1.0,1.5],(1.5,2.0],(2.0,2.5],(2.5,3.0],(3.0,3.5],(3.5,4.0],(4.0,4.5],(4.5,5.0]],
              closed='right',
              dtype='interval[float64]')
  • Interval 类型的列表组成传入其中转为区间索引,那么所有的区间会被强制转为指定的 closed 类型,因为 pd.IntervalIndex只允许存放同一种开闭区间的Interval 对象
my_interval
Interval(0,1, closed='right')
my_interval_2
Interval(0.5,1.5, closed='left')
pd.IntervalIndex([my_interval, my_interval_2], closed='left')
IntervalIndex([[0.0,1.0),[0.5,1.5)],
              closed='left',
              dtype='interval[float64]')

区间的属性与方法

​ 如果想要具体利用

cut

或者

qcut

的结果进行分析,那么需要先将其转为该种索引类型

id_interval = pd.IntervalIndex(pd.cut(s,3))

IntervalIndex

的常用属性:

left, right, mid, length

,分别表示左右端点、两端点均值和区间长度

id_demo = id_interval[:5]# 选出前5个展示
id_demo
IntervalIndex([(33.945,52.333],(52.333,70.667],(70.667,89.0],(33.945,52.333],(70.667,89.0]],
              closed='right',
              name='Weight',
              dtype='interval[float64]')

示例:

id_demo.left
Float64Index([33.945,52.333,70.667,33.945,70.667], dtype='float64')

contains

overlaps

,分别指逐个判断每个区间是否包含某元素,以及是否和一个

pd.Interval

对象有交集

id_demo.contains(4)
array([False,False,False,False,False])
id_demo.overlaps(pd.Interval(40,60))
array([True,True,False,True,False])

时序数据

时间戳

Timestamp

​ 将日期格式转换成Timestamp类型:**

pd.Timestamp()

**

ts = pd.Timestamp('2020/1/1')
ts
Timestamp('2020-01-01 00:00:00')

​ Timestamp类型的属性:

year, month, day, hour, min, second

​ Timestamp类型表示的时间范围最大是:

585

pd.Timestamp.max

pd.Timestamp.min

可以获取时间戳表示的范围

Datetime序列

  • **to_datetime**​ 能够把时间戳格式转化为datetime64[ns]类型的时间序列
pd.to_datetime(['2020-1-1','2020-1-3','2020-1-6'])
DatetimeIndex(['2020-01-01', '2020-01-03', '2020-01-06'], dtype='datetime64[ns]', freq=None)

读取表便于学习

df = pd.read_csv('C:\\Users\\Yuan\\Desktop\\pandas\\文件\\data\\learn_pandas.csv')
s = pd.to_datetime(df.Test_Date)
s.head()
02019-10-0512019-09-0422019-09-1232020-01-0342019-11-06
Name: Test_Date, dtype: datetime64[ns]

​ 时间戳格式如果不满足转换,可以使用**

format

**强制转换进行匹配

temp = pd.to_datetime(['2020\\1\\1','2020\\1\\3'],format='%Y\\%m\\%d')
temp
DatetimeIndex(['2020-01-01','2020-01-03'], dtype='datetime64[ns]', freq=None)

列表传入返回

DatetimeIndex

对象

Series传入返回**

datetime64[ns]

**类型

​ 把表的多列时间属性拼接转为时间序列,但是列名必须与给定的属性关键词相同

df_date_cols = pd.DataFrame({'year':[2020,2020],'month':[1,1],'day':[1,2],'hour':[10,20],'minute':[30,50],'second':[20,40]})
pd.to_datetime(df_date_cols)
02020-01-0110:30:2012020-01-0220:50:40
dtype: datetime64[ns]
  • date_range​ 生成连续间隔时间的一种方法​ 参数:``start, end, freq, periods`分别表示开始时间,结束时间,时间间隔,时间戳个数> 注意:开始或结束日期如果作为端点,如果计算到端点则它会被包含
pd.date_range('2020-1-1','2020-1-21', freq='10D')# 包含
DatetimeIndex(['2020-01-01','2020-01-11','2020-01-21'], dtype='datetime64[ns]', freq='10D')
pd.date_range('2020-1-1','2020-2-28', freq='10D')
DatetimeIndex(['2020-01-01','2020-01-11','2020-01-21','2020-01-31','2020-02-10','2020-02-20'],
dtype='datetime64[ns]', freq='10D')
pd.date_range('2020-1-1','2020-2-28', periods=6)# 由于结束日期无法取到,freq不为10天
DatetimeIndex(['2020-01-01 00:00:00','2020-01-12 14:24:00','2020-01-24 04:48:00','2020-02-04 19:12:00','2020-02-16 09:36:00','2020-02-28 00:00:00'],
              dtype='datetime64[ns]', freq=None)

这里的

freq

参数与

DateOffset

对象紧密相关

  • **asfreq**方法​ 改变序列采样频率
datetime64[ns]

本质上可以理解为一个大整数,对于一个该类型的序列,可以使用

max, min, mean

,来取得最大时间戳、最小时间戳和“平均”时间戳

dt对象

  • datetime64[ns].dt

datetime64[ns]

上的属性

​ 大致分为三类操作:取出时间相关的属性、判断时间戳是否满足条件、取整操作

取出时间相关的属性:``date, time, year, month, day, hour,minute, second, microsecond, nanosecond, dayofweek, dayofyear, weekofyear, daysinmonth, quarter

,**其中

daysinmonth, quarter` 分别表示该月一共有几天和季度。**

s = pd.Series(pd.date_range('2020-1-1','2020-1-3', freq='D'))
s.dt.daysinmonth
  • dayofweek

​ 返回周中的星期情况(周一为0、周二为1)

s.dt.dayofweek
021324
dtype: int64

month_name, day_name

返回英文的月名和星期名,注意它们是方法而不是属性

s.dt.month_name()
0    January
1    January
2    January
dtype:object

判断时间戳是否满足条件

​ 测试是否为月/季/年的第一天或者最后一天

s.dt.is_year_start # 还可选 is_quarter/month_start
0True1False2False
dtype:bool
s.dt.is_year_end # 还可选 is_quarter/month_end
0False1False2False
dtype:bool

取整操作

round, ceil, floor

四舍五入,进入,舍去

​ 公共参数为

freq

,常用的包括

H, min, S

(小时、分钟、秒),所有可选的

freq
s = pd.Series(pd.date_range('2020-1-1 20:35:00','2020-1-1 22:35:00',
                            freq='45min'))

####切片与索引

​ 索引都是以布尔索引为开始

​ 切片都是用**索引器

[]

**

  • 每月的第一天或者最后一天
s[(idx.is_month_start|idx.is_month_end).values].head()
2020-01-0112020-01-3102020-02-0112020-02-2912020-03-010
dtype: int32
  • 双休日
s[idx.dayofweek.isin([5,6]).values].head()
2020-01-0412020-01-0502020-01-1102020-01-1212020-01-181
dtype: int32
  • 取出单日值
s['2020-07'].head()
2020-07-0102020-07-0212020-07-0302020-07-0402020-07-050
Freq: D, dtype: int32
  • 取出5月初至7月15日
s['2020-05':'2020-7-15'].head()
2020-05-0102020-05-0212020-05-0302020-05-0412020-05-051
Freq: D, dtype: int32
s['2020-05':'2020-7-15'].tail()
2020-07-1102020-07-1202020-07-1312020-07-1402020-07-151
Freq: D, dtype: int32

时间差

Timedelta

pd.Timedelta

是两个时间戳的

pd.Timedelta(days=1, minutes=25)# 需要注意加s
Timedelta('1 days 00:25:00')
pd.Timedelta('1 days 25 minutes')# 字符串生成
Timedelta('1 days 00:25:00')
  • **pd.to_timedelta**​ 生成时间差序列,类型为 timedelta64[ns]
s = pd.to_timedelta(df.Time_Record)
s.head()
00 days 00:04:3410 days 00:04:2020 days 00:05:2230 days 00:04:0840 days 00:05:22
Name: Time_Record, dtype: timedelta64[ns]
  • **pd.timedelta_range**​ 时间差序列,与``date_range`具有一致的参数
pd.timedelta_range('0s','1000s', freq='6min')
TimedeltaIndex(['0 days 00:00:00','0 days 00:06:00','0 days 00:12:00'], dtype='timedelta64[ns]', freq='6T')
pd.timedelta_range('0s','1000s', periods=3)
TimedeltaIndex(['0 days 00:00:00','0 days 00:08:20','0 days 00:16:40'], dtype='timedelta64[ns]', freq=None)

dt对象

Timedelta

序列也定义了dt对象

​ 属性:

days, seconds, mircroseconds, nanoseconds

这里的

seconds

不是指单纯的秒,而是对天数取余后剩余的秒数

s.dt.seconds.head()
02741260232232484322
Name: Time_Record, dtype: int64

​ 直接对应秒数:

total_seconds
s.dt.total_seconds().head()
0274.01260.02322.03248.04322.0
Name: Time_Record, dtype: float64

取整函数也是可以在

dt

对象上使用

pd.to_timedelta(df.Time_Record).dt.round('min').head()
00 days 00:05:0010 days 00:04:0020 days 00:05:0030 days 00:04:0040 days 00:05:00
Name: Time_Record, dtype: timedelta64[ns]

####Timedelta的运算

​ 三类:与标量的乘法运算、与时间戳的加减法运算、与时间差的加减法与除法运算

预设:

td1 = pd.Timedelta(days=1)
td2 = pd.Timedelta(days=3)
ts = pd.Timestamp('20200101')
ts - td1
Timestamp('2019-12-31 00:00:00')
td1 *2
Timedelta('2 days 00:00:00')

时间差序列的运算

td1 = pd.timedelta_range(start='1 days', periods=5)
td2 = pd.timedelta_range(start='12 hours',freq='2H',periods=5)
ts = pd.date_range('20200101','20200105')

示例1:

td1 *5
TimedeltaIndex(['5 days','10 days','15 days','20 days','25 days'], dtype='timedelta64[ns]', freq='5D')

示例2:

td1 * pd.Series(list(range(5)))# 逐个相乘
00 days
12 days
26 days
312 days
420 days
dtype: timedelta64[ns]

示例3:

td1 + ts # 逐个相加
DatetimeIndex(['2020-01-02','2020-01-04','2020-01-06','2020-01-08','2020-01-10'],
              dtype='datetime64[ns]', freq=None)

日期偏置

Offset对象

​ **

pd.offsets

**定义offset对象

​ 日期偏置是一种和日历相关的特殊时间差

示例:

pd.Timestamp('20200831')+ pd.offsets.WeekOfMonth(week=0,weekday=0)
Timestamp('2020-09-07 00:00:00')

+

获取最近的一个日期

-

获取最近的一个日期

pd.Timestamp('20200907')- pd.offsets.BDay(30)
Timestamp('2020-07-27 00:00:00')
pd.Timestamp('20200907')+ pd.offsets.MonthEnd()
Timestamp('2020-09-30 00:00:00')
  • CDay​ 特殊的offset对象​ 参数:​ holidays传入了需要过滤的日期列表weekmask 传入的是三个字母的星期缩写构成的星期字符串,其作用是只保留字符串中出现的星期
my_filter = pd.offsets.CDay(n=1,weekmask='Wed Fri',holidays=['20200109'])
dr = pd.date_range('20200108','20200111')
dr.to_series().dt.dayofweek
2020-01-0822020-01-0932020-01-1042020-01-115
Freq: D, dtype: int64
[i + my_filter for i in dr]
[Timestamp('2020-01-10 00:00:00'),
 Timestamp('2020-01-10 00:00:00'),
 Timestamp('2020-01-15 00:00:00'),
 Timestamp('2020-01-15 00:00:00')]

不要使用部分

Offset

:

​ 在当前版本下由于一些

bug

不要使用

Day

级别以下的

Offset

对象,比如

Hour, Second

等,请使用对应的

Timedelta

对象来代替

偏置字符串

​ 偏执字符串就是Offset的缩写,作为类型一并给freq参数使用

示例:

pd.date_range('20200101','20200331', freq='MS')# 月初
DatetimeIndex(['2020-01-01','2020-02-01','2020-03-01'], dtype='datetime64[ns]', freq='MS')
pd.date_range('20200101','20200201',freq='WOM-1MON')# 每月第一个周一
DatetimeIndex(['2020-01-06'], dtype='datetime64[ns]', freq='WOM-1MON')

上面的这些字符串,等价于使用的

Offset

对象

时序中的滑窗与分组

滑动窗口

​ 时序的滑窗函数,即把滑动窗口用

freq

关键词代替

​ **

shift

**函数可以指定freq单位进行滑动(

datetime64

为索引的序列)

s.shift(freq='50D').head()
2020-02-20-12020-02-21-22020-02-22-12020-02-25-12020-02-26-2
dtype: int32

​ **

diff

**

datetime64[ns]

的序列进行

diff

后就能够得到

timedelta64[ns]

的序列

my_series = pd.Series(s.index)
my_series.head()
02020-01-0112020-01-0222020-01-0332020-01-0642020-01-07
dtype: datetime64[ns]
 my_series.diff(1).head()
0      NaT
11 days
21 days
33 days
41 days
dtype: timedelta64[ns]

重采样

​ **

pd.resample

**

​ 与groupby用法类似,是对时间序列分组计算的分组对象

s.resample('10D').mean().head()
2020-01-01-2.0000002020-01-11-3.1666672020-01-21-3.6250002020-01-31-4.0000002020-02-10-0.375000
Freq:10D, dtype: float64

​ 重采样也可以使用**

apply

**

s.resample('10D').apply(lambda x:x.max()-x.min()).head()# 极差
2020-01-0132020-01-1142020-01-2142020-01-3122020-02-104
Freq:10D, dtype: int32

resample边界处理

​ 起始值的计算方法:从给定的最小时间戳的午夜0点开始,一直增加

freq

加到不超过这个时间戳,就被设置为起始值

​ 每次累加的freq参数作为分割节点进行分组,区间为左闭右开

idx = pd.date_range('20200101 8:26:35','20200101 9:31:58', freq='77s')
data = np.random.randint(-1,2,len(idx)).cumsum()
s = pd.Series(data,index=idx)
s.head()
2020-01-0108:26:35-12020-01-0108:27:52-12020-01-0108:29:09-22020-01-0108:30:26-32020-01-0108:31:43-4
Freq: 77S, dtype: int32

下面对应的第一个组起始值为

08:24:00

,其是从当天0点增加72个

freq=7 min

得到的,如果再增加一个

freq

则超出了序列的最小时间戳

08:26:35
s.resample('7min').mean().head()
2020-01-0108:24:00-1.7500002020-01-0108:31:00-2.6000002020-01-0108:38:00-2.1666672020-01-0108:45:000.2000002020-01-0108:52:002.833333
Freq: 7T, dtype: float64

​ 指定

origin

start

:最小时间戳开始依次增加

freq

进行分组

s.resample('7min', origin='start').mean().head()
2020-01-0108:26:35-2.3333332020-01-0108:33:35-2.4000002020-01-0108:40:35-1.3333332020-01-0108:47:351.2000002020-01-0108:54:353.166667
Freq: 7T, dtype: float64
  • 返回值一般是组的第一个时间戳,但 M, A, Q, BM, BA, BQ, W 这七个是取对应区间的最后一个时间戳
s = pd.Series(np.random.randint(2,size=366),index=pd.date_range('2020-01-01','2020-12-31'))
s.resample('M').mean().head()
2020-01-310.4516132020-02-290.4482762020-03-310.5161292020-04-300.5666672020-05-310.451613
Freq: M, dtype: float64
s.resample('MS').mean().head()# 结果一样,但索引不同
2020-01-010.4516132020-02-010.4482762020-03-010.5161292020-04-010.5666672020-05-010.451613
Freq: MS, dtype: float64

归属人:我怕是有点打脑壳
严禁转载


本文转载自: https://blog.csdn.net/qq_57268469/article/details/124139509
版权归原作者 我怕是有点打脑壳 所有, 如有侵权,请联系我们删除。

“pandas”的评论:

还没有评论