微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

【DW组队学习—Pandas】02.pandas基础

import numpy as np
import pandas as pd

在开始学习前,请保证 pandas 的版本号不低于如下所示的版本,否则请务必升级!请确认已经安装了 xlrd, xlwt, openpyxl 这三个包,其中xlrd版本不得高于 2.0.0 。

pd.__version__
'1.1.5'
pip install -U pandas==1.1.5 # 版本不够时更新,重启kernel生效

一、文件的读取和写入

1.文件读取

pandas 可以读取的文件格式有很多,这里主要介绍读取 csv, excel, txt 文件

df_csv = pd.read_csv('data/my_csv.csv')
df_csv
col1col2col3col4col5
02a1.4apple2020/1/1
13b3.4banana2020/1/2
26c2.5orange2020/1/5
35d3.2lemon2020/1/7
df_txt = pd.read_table('data/my_table.txt')
df_txt
col1col2col3col4
02a1.4apple 2020/1/1
13b3.4banana 2020/1/2
26c2.5orange 2020/1/5
35d3.2lemon 2020/1/7
df_excel = pd.read_excel('data/my_excel.xlsx')
df_excel
col1col2col3col4col5
02a1.4apple2020/1/1
13b3.4banana2020/1/2
26c2.5orange2020/1/5
35d3.2lemon2020/1/7

这里有一些常用的公共参数:

  • header=None 表示第一行不作为列名
  • index_col 表示把某一列或几列作为索引,索引的内容将会在第三章进行详述
  • usecols 表示读取列的集合,认读取所有的列
  • parse_dates 表示需要转化为时间的列,关于时间序列的有关内容将在第十章讲解
  • nrows 表示读取的数据行数。

上面这些参数在上述的三个函数里都可以使用。

pd.read_table('data/my_table.txt', header = None) #第一行不作为列名
0123
0col1col2col3col4
12a1.4apple 2020/1/1
23b3.4banana 2020/1/2
36c2.5orange 2020/1/5
45d3.2lemon 2020/1/7
pd.read_csv('data/my_csv.csv', index_col = ['col1', 'col2']) #第一、二列作为索引
col3col4col5
col1col2
2a1.4apple2020/1/1
3b3.4banana2020/1/2
6c2.5orange2020/1/5
5d3.2lemon2020/1/7
pd.read_table('data/my_table.txt', usecols = ['col1', 'col2']) #只读取第一、二列
col1col2
02a
13b
26c
35d
pd.read_csv('data/my_csv.csv', parse_dates = ['col5']) # 第五列转化为时间
col1col2col3col4col5
02a1.4apple2020-01-01
13b3.4banana2020-01-02
26c2.5orange2020-01-05
35d3.2lemon2020-01-07
pd.read_excel('data/my_excel.xlsx', nrows = 2) #读取两行数据
col1col2col3col4col5
02a1.4apple2020/1/1
13b3.4banana2020/1/2

在读取 txt 文件时,经常遇到分隔符非空格的情况, read_table 有一个分割参数sep,它使得用户可以自定义分割符号,进行 txt 数据的读取。例如,下面的读取的表以 |||| 为分割:
【VC小注】即sep指定分割标志

pd.read_table('data/my_table_special_sep.txt')
col1 |||| col2
0TS |||| This is an apple.
1GQ |||| My name is Bob.
2WT |||| Well done!
3PT |||| May I help you?

上面的结果显然不是理想的,这时可以使用 sep ,同时需要指定引擎为 python :

pd.read_table('data/my_table_special_sep.txt', sep = '\|\|\|\|', engine = 'python')
col1col2
0TSThis is an apple.
1GQMy name is Bob.
2WTWell done!
3PTMay I help you?

【注】sep 是正则参数,需要进行转义
在使用read_table 的时候需要注意,参数 sep 中使用的是正则表达式,因此需要对 | 进行转义变成 | ,否则无法读取到正确的结果。有关正则表达式的基本内容可以参考第八章或者其他相关资料。

2.数据写入

一般在数据写入中,最常用的操作是把 index 设置为 False ,特别当索引没有特殊意义的时候,这样的行为能把索引在保存的时候去除

df_csv.to_csv('data/my_csv_saved.csv', index = False)
#出现XLRD相关报错的,可以尝试安装xlrd、xlwt、tabulate三个扩展库,
pip install xlrd xlwt tabulate
Requirement already satisfied: xlrd in c:\programdata\anaconda3\envs\py37\lib\site-packages (1.2.0)
Collecting xlwt
  Downloading xlwt-1.3.0-py2.py3-none-any.whl (99 kB)
Collecting tabulate
  Downloading tabulate-0.8.7-py3-none-any.whl (24 kB)
Installing collected packages: xlwt, tabulate
Successfully installed tabulate-0.8.7 xlwt-1.3.0
Note: you may need to restart the kernel to use updated packages.
pip install openpyxl
Collecting openpyxl
  Downloading openpyxl-3.0.5-py2.py3-none-any.whl (242 kB)
Collecting et-xmlfile
  Downloading et_xmlfile-1.0.1.tar.gz (8.4 kB)
Collecting jdcal
  Downloading jdcal-1.4.1-py2.py3-none-any.whl (9.5 kB)
Building wheels for collected packages: et-xmlfile
  Building wheel for et-xmlfile (setup.py): started
  Building wheel for et-xmlfile (setup.py): finished with status 'done'
  Created wheel for et-xmlfile: filename=et_xmlfile-1.0.1-py3-none-any.whl size=8919 sha256=cdc60ba1dee65fbab03e098bc4d92e1221d06fd80800a626fba7fa5fe4429865
  Stored in directory: c:\users\viochan\appdata\local\pip\cache\wheels\e2\bd\55\048b4fd505716c4c298f42ee02dffd9496bb6d212b266c7f31
Successfully built et-xmlfile
Installing collected packages: et-xmlfile, jdcal, openpyxl
Successfully installed et-xmlfile-1.0.1 jdcal-1.4.1 openpyxl-3.0.5
Note: you may need to restart the kernel to use updated packages.

【VC小注】出现ModuleNotFoundError错误时,可根据提示安装相关库

df_excel.to_excel('data/my_excel_saved.xlsx', index = False)

pandas 中没有定义 to_table 函数,但是to_csv 可以保存为 txt 文件,并且允许自定义分隔符,常用制表符 \t 分割:

df_txt.to_csv('data/my_txt_saved.txt', sep = "\t", index = False)

如果想要把表格快速转换为 markdown 和 latex 语言,可以使用 to_markdownto_latex 函数,此处需要安装 tabulate 包。

**Series/DataFrame.to_markdown(buf=None, mode=None, index=True, kwargs)
以Markdown形式打印
参数

  • buf:str,可选,认为None,指定要写入的缓冲区,输出以字符串形式返回
  • mode:str,可选,打开文件的模式
  • index:bool,可选,认为True,添加索引(行)标签

DataFrame.to_latex(buf=None, columns=None, col_space=None, header=True, index=True, na_rep=‘NaN’, formatters=None, float_format=None, sparsify=None, index_names=True, bold_rows=False, column_format=None, longtable=None, escape=None, encoding=None, decimal=’.’, multicolumn=None, multicolumn_format=None, multirow=None, caption=None, label=None)
将对象渲染为LaTeX表格,长表或嵌套表/表格(LtTeX语言)

print(df_csv.to_markdown())
|    |   col1 | col2   |   col3 | col4   | col5     |
|---:|-------:|:-------|-------:|:-------|:---------|
|  0 |      2 | a      |    1.4 | apple  | 2020/1/1 |
|  1 |      3 | b      |    3.4 | banana | 2020/1/2 |
|  2 |      6 | c      |    2.5 | orange | 2020/1/5 |
|  3 |      5 | d      |    3.2 | lemon  | 2020/1/7 |
print(df_csv.to_latex())
\begin{tabular}{lrlrll}
\toprule
{} &  col1 & col2 &  col3 &    col4 &      col5 \\
\midrule
0 &     2 &    a &   1.4 &   apple &  2020/1/1 \\
1 &     3 &    b &   3.4 &  banana &  2020/1/2 \\
2 &     6 &    c &   2.5 &  orange &  2020/1/5 \\
3 &     5 &    d &   3.2 &   lemon &  2020/1/7 \\
\bottomrule
\end{tabular}

二、基本数据结构

pandas 中具有两种基本的数据存储结构,存储一维 values 的 Series存储二维 values 的 DataFrame在这两种结构上定义了很多的属性方法

1. Series

Series 一般由四个部分组成,分别是序列的**值 data 、索引 index 、存储类型 dtype 、序列的名字 name** 。其中,索引也可以指定它的名字,认为空

s = pd.Series(data = [100, 'a', {'dic1': 5}],
              index = pd.Index(['id1', 20, 'third'], name = 'my_idx'),
              dtype = 'object',
              name = 'my_name'
             )
s
my_idx
id1              100
20                 a
third    {'dic1': 5}
Name: my_name, dtype: object

pandas.Series(data=None, index=None, dtype=None, name=None, copy=False, fastpath=False)
生成具有轴标签包括时间序列)的一维ndarray对象
参数

  • data:数组,可迭代,字典或标量值,包含存储在Series中的数据
  • index:数组或索引
  • ①值必须是可散列的,并且长度与data相同;
  • ②允许使用非唯一索引值,如果未提供,则认为RangeIndex(0,1,2,…,n);
  • ③如果同时使用字典和索引序列,则索引将覆盖在字典中找到的键。
  • dtype:可选,指定输出的数据类型,如果未指定,则将从data推断出来。
  • name:str,可选,指定series的名称
  • copy:bool,认为False,复制输入数据

【VC小注】这是一个函数生成一个具体的对象,该对象有预定的属性方法

【注】object 类型
object 代表了一种混合类型,正如上面的例子中存储了整数、字符串以及 Python 的字典数据结构。此外,目前 pandas 把纯字符串序列也认认为是一种 object 类型的序列,但它也可以用 string 类型存储,文本序列的内容会在第八章中讨论。
对于这些属性,可以通过 . 的方式获取

s.values #查看series的值
array([100, 'a', {'dic1': 5}], dtype=object)
s.index #查看series的索引
Index(['id1', 20, 'third'], dtype='object', name='my_idx')
s.dtype #查看series的类型
dtype('O')
s.name #查看series的名称
'my_name'

利用 .shape 可以获取序列的长度:

s.shape
(3,)

索引是 pandas 中最重要的概念之一,它将在第三章中被详细地讨论。如果想要取出单个索引对应的值,可以通过**[index_item]**可以取出。

s['third']
{'dic1': 5}

2. DataFrame

DataFrame 在 Series 的基础上增加了列索引,一个数据框可以由二维的 data 与行列索引来构造:

data = [[1, 'a', 1.2], [2, 'b', 2.2], [3, 'c', 3.2]]

df = pd.DataFrame(data = data,
                  index = ['row%d' % i for i in range(3)],
                  columns = ['col_0', 'col_1','col_2']
                 )

df
col_0col_1col_2
row01a1.2
row12b2.2
row23c3.2

pandas.DataFrame(data=None, index=None, columns=None, dtype=None, *copy=False)
返回二维,大小可变,潜在异构的表格数据
参数

  • data:数组、可迭代的、字典或者DataFrame,dict可以包含Series,数组,常量或类似列表的对象。
  • index:(行)索引或者数组。如果没有输入数据的索引信息部分并且没有提供索引,则认为RangeIndex。
  • columns:用于结果框架的列标签。如果未提供列标签,则认为RangeIndex(0,1,2,…,n)。
  • dtype:强制的数据类型。仅允许单个dtype。如果没有,则推断。
  • copy:从输入中复制数据,仅影响输入

【VC小注】这是一个函数生成一个具体的对象,该对象有预定的属性方法

但一般而言,更多的时候会采用从列索引名到数据的映射来构造数据框,同时再加上行索引:

df = pd.DataFrame(data = {'col_0': [1, 2, 3], 'col_1': list('abc'), 'col_2': [1.2, 2.2, 3.2]},
                  index = ['row_%d' % i for i in range(3)]
                 )
df
col_0col_1col_2
row_01a1.2
row_12b2.2
row_23c3.2

【VC小注】即创建DF类型数据有两种方式:一种是data参数中按行给数据,用columns参数给定列名;另一种是在data参数中按列写明{列名:值序列},不再需要columns参数

由于这种映射关系,在 DataFrame 中可以用 [col_name] 与 [col_list] 来取出相应的列与由多个列组成的表,结果分别为 Series 和 DataFrame :

df['col_0']
row_0    1
row_1    2
row_2    3
Name: col_0, dtype: int64
df[['col_0', 'col_1']]
col_0col_1
row_01a
row_12b
row_23c

与 Series 类似,在数据框中同样可以取出相应的属性

df.values
array([[1, 'a', 1.2],
       [2, 'b', 2.2],
       [3, 'c', 3.2]], dtype=object)
df.index
Index(['row_0', 'row_1', 'row_2'], dtype='object')
df.columns
Index(['col_0', 'col_1', 'col_2'], dtype='object')
df.dtypes
col_0      int64
col_1     object
col_2    float64
dtype: object
df.shape
(3, 3)

通过 .T 可以把 DataFrame 进行转置

df.T
row_0row_1row_2
col_0123
col_1abc
col_21.22.23.2

三、常用基本函数

为了进行举例说明,在接下来的部分和其余章节都将会使用一份 learn_pandas.csv 的虚拟数据集,它记录了四所学校学生的体测个人信息。

df = pd.read_csv('data/learn_pandas.csv')
df.columns
Index(['School', 'Grade', 'Name', 'Gender', 'Height', 'Weight', 'Transfer',
       'Test_Number', 'Test_Date', 'Time_Record'],
      dtype='object')

上述列名依次代表学校、年级、姓名、性别、身高、体重、是否为转系生、体测场次、测试时间、1000米成绩,本章只需使用其中的前七列。

df = df[df.columns[ : 7]] #只取前7列
df
SchoolGradeNameGenderHeightWeightTransfer
0Shanghai Jiao Tong UniversityFreshmanGaopeng YangFemale158.946.0N
1Peking UniversityFreshmanChangqiang YouMale166.570.0N
2Shanghai Jiao Tong UniversitySeniorMei SunMale188.989.0N
3Fudan UniversitySophomoreXiaojuan SunFemaleNaN41.0N
4Fudan UniversitySophomoreGaojuan YouMale174.074.0N
........................
195Fudan UniversityJuniorXiaojuan SunFemale153.946.0N
196Tsinghua UniversitySeniorLi ZhaoFemale160.950.0N
197Shanghai Jiao Tong UniversitySeniorChengqiang ChuFemale153.945.0N
198Shanghai Jiao Tong UniversitySeniorChengmei ShenMale175.371.0N
199Tsinghua UniversitySophomoreChunpeng LvMale155.751.0N

200 rows × 7 columns

1.汇总函数

head, tail 函数分别表示返回表或者序列的前 n 行和后 n 行,其中 n 认为5:

Series/DataFrame.head(n = 5)
返回前n行
参数

  • n:int,认为5,要选择的行数

对于n的负值,此函数返回除最后n行之外的所有行,等效于df[:-n]

Series/DataFrame.tail(n = 5)
返回最后n行
参数

  • n:int,认为5,要选择的行数

对于n的负值,此函数返回除前n行之外的所有行,等效于df[n:]

df.head(2)
SchoolGradeNameGenderHeightWeightTransfer
0Shanghai Jiao Tong UniversityFreshmanGaopeng YangFemale158.946.0N
1Peking UniversityFreshmanChangqiang YouMale166.570.0N
df.tail(3)
SchoolGradeNameGenderHeightWeightTransfer
197Shanghai Jiao Tong UniversitySeniorChengqiang ChuFemale153.945.0N
198Shanghai Jiao Tong UniversitySeniorChengmei ShenMale175.371.0N
199Tsinghua UniversitySophomoreChunpeng LvMale155.751.0N

info, describe 分别返回表的 信息概况 和表中 数值列对应的主要统计

DataFrame.info(verbose=None, buf=None, max_cols=None, memory_usage=None, null_counts=None)
返回DataFrame的简要摘要
参数

  • verbose:bool,可选,是否打印完整的摘要
  • buf:可写缓冲区,认情况下,输出被打印到sys.stdout;如果需要进一步处理输出,请传递可写缓冲区
  • max_cols:int,可选,何时从详细输出切换到截断输出。如果DataFrame的列数超过max_cols列,则使用截断的输出
  • memory_usage:bool,str,可选,指定是否应显示DataFrame元素(包括索引)的总内存使用情况。
  • True:始终显示内存使用情况
  • False:永远不会显示内存使用情况
  • ‘deep’:显示内存使用真实值
  • null_counts:bool,可选,是否显示非空计数。认情况下,仅在DataFrame小于和时显示。值为True始终显示计数,而值为False则不显示计数。

DataFrame.describe(percentiles=None, include=None, exclude=None, datetime_is_numeric=False)
生成描述性统计信息,包括总结数据集分布的集中趋势,离散度和形状**(不包括NaN值)**的统计量。
参数

  • percentiles:数字列表,可选,表示要包含在输出中的百分比,全部应介于0和1之间
  • include:“all”/类似dtype的列表/None,可选,要包括在结果中的数据类型的白名单
  • ‘all’:输入的所有列将包含在输出
  • 类似于dtypes的列表:将结果限制为提供的数据类型
  • None(认):结果将包括所有数字列
  • exclude:类似dtype的列表或None(认),可选,要从结果中忽略的数据类型黑名单
  • 类似于dtypes的列表:从结果中排除提供的数据类型
  • None(认):结果将不排除任何内容
  • datetime_is_numeric:bool,认为False,是否将datetime dtypes视为数字。这会影响为该列计算的统计信息。
df.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 200 entries, 0 to 199
Data columns (total 7 columns):
 #   Column    Non-Null Count  Dtype  
---  ------    --------------  -----  
 0   School    200 non-null    object 
 1   Grade     200 non-null    object 
 2   Name      200 non-null    object 
 3   Gender    200 non-null    object 
 4   Height    183 non-null    float64
 5   Weight    189 non-null    float64
 6   Transfer  188 non-null    object 
dtypes: float64(2), object(5)
memory usage: 11.1+ KB
df.describe()
HeightWeight
count183.000000189.000000
mean163.21803355.015873
std8.60887912.824294
min145.40000034.000000
25%157.15000046.000000
50%161.90000051.000000
75%167.50000065.000000
max193.90000089.000000

【注】更全面的数据汇总
info, describe 只能实现较少信息的展示,如果想要对一份数据集进行全面且有效的观察,特别是在列较多的情况下,推荐使用 pandas-profiling 包,它将在第十一章被再次提到

2.特征统计函数

在 Series 和 DataFrame 上定义了许多统计函数,最常见的是 sum, mean, median, var, std, max, min 。例如,选出身高和体重列进行演示:

**Series/DataFrame.sum(axis=None, skipna=None, level=None, numeric_only=None, min_count=0, kwargs)
返回所请求轴的值之和
参数

  • axis:{index(0)}/{index (0), columns (1)},所选的轴
  • skipna:bool,认为True,计算结果时排除NA/null值
  • level:int/level名称认为None,如果轴是MultiIndex(分层),则沿特定级别计数,并折叠成标量(Series数据)/Series(DataFrame数据)
  • numeric_only:bool,认值None,仅包括float,int,boolean列。如果为None,将尝试使用所有内容,然后仅使用数字数据
  • min_count:int,认为0,执行操作所需的有效值数量。如果非NA值数量少于min_count,则结果将为NA

**Series/DataFrame.mean/median/max/min(axis=None, skipna=None, level=None, numeric_only=None, kwargs)
返回所请求轴的值的平均值/中位数/最大值/最小值

  • 参数含义同前

**Series/DataFrame.var/std(axis=None, skipna=None, level=None, ddof=1, numeric_only=None, kwargs)
返回所请求轴的值的方差/标准差
参数

  • ddof:int,认值1,δ自由度。计算中使用的除数为N-ddof,其中N表示元素数
  • 其他参数同前
df_demo = df[['Height', 'Weight']]

df_demo.mean()
Height    163.218033
Weight     55.015873
dtype: float64
df_demo.max()
Height    193.9
Weight     89.0
dtype: float64

此外,需要介绍的是quantile,count,idxmax 这三个函数,它们分别返回的是分位数、非缺失值个数、最大值对应的索引

Series.quantile(q=0.5, interpolation=‘linear’)
返回给定分位数所对应的值/数组
参数

  • q:浮点数或者数组,认0.5(50%分位数),要计算的分位数可以在范围内:0 <= q <= 1
  • interpolation:{‘linear’, ‘lower’, ‘higher’, ‘midpoint’, ‘nearest’}
    • linear:i +(j-i)*分数,其中分数是被i和j包围的索引的分数部分
    • lower:i
    • higher:j
    • midpoint:(i+j)/2
    • nearest:i和j中里的最近的那个

DataFrame.quantile(q=0.5, axis=0, numeric_only=True, interpolation=‘linear’)
返回给定分位数所对应的数组/表格
参数

  • axis:{0, 1, ‘index’, ‘columns’},认为0。对于行,等于0或“index”;对于列,等于1或“columns”
  • numeric_only:bool,认为True。如果为False,则还将计算日期时间和时间增量数据的分位数。
  • 其他参数同前

Series.count(level=None)
返回系列中非NA/null观测值的数量
参数

  • level:int/level名称认为None,如果轴是MultiIndex(分层),则沿特定级别计数,折叠成较小的Series

DataFrame.count(axis=0, level=None, numeric_only=False)
为每一列或每一行计算非NA单元。值None,NaN,NaT和可选的numpy.inf(取决于pandas.options.mode.use_inf_as_na)被视为NA。
参数

  • axis:{0, 1, ‘index’, ‘columns’},认为0。如果为0或“index”,则为每列生成计数。如果为1或“columns”,则为每一行生成计数。
  • numeric_only:bool,认为False,仅包含float,int或boolean数据。
  • 其他参数同前

Series.idxmax(axis=0, skipna=True, *args, **kwargs)
返回最大值的行标签。如果多个值等于最大值,则返回具有该值的第一行标签
参数

  • axis:int,认为0
  • skipna:bool,认为True,排除NA /null值。如果整个系列为NA,则结果为NA

DataFrame.idxmax(axis=0, skipna=True)
返回在请求轴上第一次出现最大值的索引。包括NA /空值。
参数

  • axis:axis:{0, 1, ‘index’, ‘columns’},认为0。如果为0或“index”,则为每列生成计数。如果为1或“columns”,则为每一行生成计数。
  • 其他参数同前
df_demo.quantile(0.75)
Height    167.5
Weight     65.0
Name: 0.75, dtype: float64
df_demo.count()
Height    183
Weight    189
dtype: int64
df_demo.idxmax() # idxmin是对应的函数
Height    193
Weight      2
dtype: int64

上面这些所有的函数,由于操作后返回的是标量,所以又称为聚合函数,它们有一个公共参数 axis ,认为0代表逐列聚合,如果设置为1则表示逐行聚合
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kjbVP26g-1608607207100)(attachment:image.png)]

df_demo.mean(axis=1).head() # 在这个数据集上体重和身高的均值并没有意义
0    102.45
1    118.25
2    138.95
3     41.00
4    124.00
dtype: float64

3.唯一值函数

对序列使用 unique 和 nunique 可以分别得到其唯一值组成的列表唯一值的个数

Series.unique()
返回Series对象的唯一值。
按出现顺序返回唯一的。基于哈希表的唯一,因此不排序。

Series.nunique(dropna=True)
返回对象中唯一元素的数量
参数

  • dropna:bool,认为True,表示计数中不包括NaN

DataFrame.nunique(axis=0, dropna=True)
计算请求轴上的不同观察值,返回具有不同观察值的序列。
参数

  • axis:要使用的轴。0或’index’代表行,1或’columns’代表行。
  • dropna:bool,认为True,表示不要将NaN包括在内。
df['School'].unique()
array(['Shanghai Jiao Tong University', 'Peking University',
       'Fudan University', 'Tsinghua University'], dtype=object)
df['School'].nunique()
4

value_counts 可以得到唯一值和其对应出现的频数:

Series.value_counts(normalize=False, sort=True, ascending=False, bins=None, dropna=True)
返回一个包含唯一值计数的系列。生成的对象将按降序排列,以便第一个元素是最频繁出现的元素。认情况下不包括NA值。
参数

  • normalize:bool,认为False。如果为True,则返回的对象将包含唯一值的相对频率
  • sort:bool,认为True,按频率排序
  • ascending:bool,认为False,升序排列
  • bins:int,可选,不是对值进行计数,而是将它们分组到半开箱中
  • dropna:bool,认为True,表示不计入NaN

DataFrame.value_counts(subset=None, normalize=False, sort=True, ascending=False)
返回一个包含DataFrame中唯一行数的Series
参数

  • subset:list,可选,计算唯一组合时要使用的列
  • normalize:bool,认为False,返回比例而不是频率
  • 其他参数同前
df['School'].value_counts()
Tsinghua University              69
Shanghai Jiao Tong University    57
Fudan University                 40
Peking University                34
Name: School, dtype: int64

如果想要观察多个列组合的唯一值,可以使用 drop_duplicates 。其中的关键参数是 keep ,认值 first 表示每个组合保留第一次出现的所在行, last 表示保留最后一次出现的所在行, False 表示把所有重复组合所在的行剔除。

Series.drop_duplicates(keep=‘first’, inplace=False)
返回具有重复值的Series
参数

  • keep:{‘first’,‘last’,False},认为’first’,表示处理删除重复项的方法
    • ‘first’:保留第一次出现的所在行
    • ‘last’:保留最后一次出现的所在行
    • False:把所有重复组合所在的行剔除
  • inplace:bool,认False,如果为True,则执行操作并返回None。

DataFrame.drop_duplicates(subset=None, keep=‘first’, inplace=False, ignore_index=False)
返回删除了重复行的DataFrame。考虑某些列是可选的。包括时间索引在内的索引将被忽略
参数

  • subset:列标签或者标签序列,可选,仅考虑某些列来标识重复项,认情况下使用所有列
  • ignore_index:bool,认为False,如果为True,则结果轴将标记为0、1,…,n-1
  • 其他参数同前
df_demo = df[['Gender', 'Transfer', 'Name']]
df_demo.drop_duplicates(['Gender', 'Transfer'])
GenderTransferName
0FemaleNGaopeng Yang
1MaleNChangqiang You
12FemaleNaNPeng You
21MaleNaNXiaopeng Shen
36MaleYXiaojuan Qin
43FemaleYGaoli Feng
df_demo.drop_duplicates(['Gender', 'Transfer'], keep = 'last')
GenderTransferName
147MaleNaNJuan You
150MaleYChengpeng You
169FemaleYChengquan Qin
194FemaleNaNYanmei Qian
197FemaleNChengqiang Chu
199MaleNChunpeng Lv
df_demo.drop_duplicates(['Gender', 'Name'], keep = False).head() # 保留只出现过一次的性别和姓名组合
GenderTransferName
0FemaleNGaopeng Yang
1MaleNChangqiang You
2MaleNMei Sun
4MaleNGaojuan You
5FemaleNXiaoli Qian
df['School'].drop_duplicates()
0    Shanghai Jiao Tong University
1                Peking University
3                 Fudan University
5              Tsinghua University
Name: School, dtype: object

此外, duplicated 和 drop_duplicates 的功能类似,但前者返回了是否为唯一值的布尔列表,其 keep 参数与后者一致。其返回的序列,把重复元素设为 True ,否则为 False 。 drop_duplicates 等价于把 duplicated 为 True 的对应行剔除。

Series.duplicated(keep=‘first’)
返回表示重复行的布尔序列
参数

  • keep:{‘first’,‘last’,False},认为’first’,表示标记重复项的方法
    • ‘first’:重复项第一次出现行表示为True
    • ‘last’:重复项最后一次出现行表示为True
    • False:所有重复项标记为True

DataFrame.duplicated(subset=None, keep=‘first’)
返回表示重复行的布尔序列
参数

  • subset:列标签标签序列,可选,仅考虑某些列来标识重复项,认情况下使用所有列
  • 其他参数同前
df_demo.duplicated(['Gender', 'Transfer']).head()
0      False
1      False
2       True
3       True
4       True
       ...  
195     True
196     True
197     True
198     True
199     True
Length: 200, dtype: bool
df['School'].duplicated()# 在Series上也可以使用
0      False
1      False
2       True
3      False
4       True
       ...  
195     True
196     True
197     True
198     True
199     True
Name: School, Length: 200, dtype: bool
df.duplicated(['School'])
0      False
1      False
2       True
3      False
4       True
       ...  
195     True
196     True
197     True
198     True
199     True
Length: 200, dtype: bool

【VC小注】对于DF数据,df[列名].方法只保留列名所对应的一列或者几列信息,相当于先把指定列的数据提取出来在进行操作;**df.方法([列名])**会保留所有列信息

4.替换函数

一般而言,替换操作是针对一个进行的,因此下面的例子都以 Series 举例。 pandas 中的替换函数可以归纳为三类:映射替换逻辑替换数值替换。其中映射替换包含 replace 方法、第八章中的 str.replace 方法以及第九章中的 cat.codes 方法,此处介绍 replace 的用法

Series/DataFrame.replace(to_replace=None, value=None, inplace=False, limit=None, regex=False, method=‘pad’)
将to_replace中给出的值替换为value
参数

  • to_replace:str、regex、list、dict、Series、int、float或None
  • value:scalar、dict、list、str、regex,认为None,用于替换与to_replace匹配的任何值的值
  • inplace:bool,认为False
  • limit:int,认None,向前或向后填充的最大尺寸间隙
  • regex:bool或与to_ replace相同的类型,认为False,否将to_ replace和/或value解释为正则表达式,如果是True,则to_ replace 必须为字符串。
  • method:{‘pad’,‘ffill’,‘bfill’,None},表示替换方向
    • ffill:使用前面一个最近的未被替换的值进行替换
    • bfill:使用后面最近的未被替换的值进行替换

在 replace 中,可以通过字典构造,或者传入两个列表来进行替换:

df['Gender'].replace({'Female': 0, 'Male': 1}) #构造字典进行替换
0      0
1      1
2      1
3      0
4      1
      ..
195    0
196    0
197    0
198    1
199    1
Name: Gender, Length: 200, dtype: int64
df['Gender'].replace(['Female','Male'], [0, 1]) #传入两个列表进行替换
0      0
1      1
2      1
3      0
4      1
      ..
195    0
196    0
197    0
198    1
199    1
Name: Gender, Length: 200, dtype: int64

另外, replace 还有一种特殊的方向替换,指定 method 参数为 ffill 则为用前面一个最近的未被替换的值进行替换, bfill 则使用后面最近的未被替换的值进行替换。从下面的例子可以看到,它们的结果是不同的:

s = pd.Series(['a', 1 ,'b', 2, 1, 1, 'a'])
s.replace([1, 2], method = 'ffill')
0    a
1    a
2    b
3    b
4    b
5    b
6    a
dtype: object
s.replace([1, 2], method = 'bfill')
0    a
1    b
2    b
3    a
4    a
5    a
6    a
dtype: object

【注】正则替换请使用 str.replace
虽然对于 replace 而言可以使用正则替换,但是当前版本下对于 string 类型的正则替换还存在 bug ,因此如有此需求,请选择 str.replace 进行替换操作,具体的方式将在第八章中讲解。

【VC小注】什么是正则表达式?
正则表达式(regular expression)描述了一种字符串匹配的模式(pattern),可以用来检查一个串是否含有某种子串、将匹配的子串替换或者从某个串中取出符合某个条件的子串等。
例如:

  • runoo+b,可以匹配 runoob、runooob、runoooooob 等,+ 号代表前面的字符必须至少出现一次(1次或多次)。
  • runoo*b,可以匹配 runob、runoob、runoooooob 等,* 号代表前面的字符可以不出现,也可以出现一次或者多次(0次、或1次、或多次)。
  • colou?r 可以匹配 color 或者 colour,? 问号代表前面的字符最多只可以出现一次(0次、或1次)。

正则表达式是由普通字符(例如字符 a 到 z)以及特殊字符(称为"元字符")组成文字模式。模式描述在搜索文本时要匹配的一个或多个字符串。正则表达式作为一个模板,将某个字符模式与所搜索的字符串进行匹配。

逻辑替换包括wheremask ,这两个函数是完全对称的: where 函数在传入条件为 False 的对应行进行替换,而 mask 在传入条件为 True 的对应行进行替换,当不指定替换值时,替换为缺失值。

Series/DataFrame.where(cond, other=nan, inplace=False, axis=None, level=None, errors=‘raise’, try_cast=False)
替换条件结果为False的地方
参数

  • cond:bool Series/DataFrame,array-like,或可调用。如果cond为True,则保留原始值。如果为 False,则用other中的相应值替换。如果cond是可调用的,则它是在Series/DataFrame上计算的,并且应返回布尔Series/DataFrame或数组。可调用对象不得更改输入Series/DataFrame。
  • other:scalar,Series/DataFrame,或可调用认为空值,替换值。如果other是可调用的,则在Series/DataFrame上对其进行计算,并应返回标量或Series/DataFrame。可调用对象不得更改输入Series/DataFrame
  • inplace:bool,认False,是否对数据执行适当的操作
  • axis:int,认None,对齐轴
  • level:int,认None,对齐级别
  • errors:str,{‘raise’,‘ignore’},认为‘raise’,此参数不会影响结果,并且始终会强制转换为合适的dtype。
    • ‘raise’:允许引发异常。
    • ‘ignore’:抑制异常。错误时返回原始对象。
  • try_cast:bool,认为False,尝试将结果转换回输入类型

Series/DataFrame.mask(cond, other=nan, inplace=False, axis=None, level=None, errors=‘raise’, try_cast=False)
替换条件结果为Ture的地方
参数同where

s = pd.Series([-1, 1.2345, 100, -50])
s.where(s < 0)
0    -1.0
1     NaN
2     NaN
3   -50.0
dtype: float64
s.where(s < 0, 100)
0     -1.0
1    100.0
2    100.0
3    -50.0
dtype: float64
s.mask(s < 0)
0         NaN
1      1.2345
2    100.0000
3         NaN
dtype: float64
s.mask(s < 0, -50)
0    -50.0000
1      1.2345
2    100.0000
3    -50.0000
dtype: float64

需要注意的是,传入的条件只需是与被调用的 Series 索引一致的布尔序列即可:

s_condition = pd.Series([True, False, False, True], index = s.index)
s.mask(s_condition, -50)
0    -50.0000
1      1.2345
2    100.0000
3    -50.0000
dtype: float64

数值替换包含了 round, abs, clip 方法,它们分别表示按照给定精度四舍五入取绝对值截断

Series/DataFrame.round(decimals=0, *args, **kwargs)
将序列中的每个值四舍五入到给定的小数位数
参数

  • decimals:int,认为0,要舍入的小数位数。如果小数为负数,则指定小数点左边的位数。

Series/DataFrame.abs()
返回具有每个元素的绝对数字值的Series/DataFrame,仅适用于全数字元素

Series/DataFrame.clip(lower=None, upper=None, axis=None, inplace=False, *args, **kwargs)
修剪输入阈值处的值,将边界外的值分配给边界值
参数

  • lower:float或array_like,认为None,最小阈值。低于此阈值的所有值都将被设置为该值。
  • upper:float或array_like,认为None,最大阈值。所有高于此阈值的值都将被设置为该值。
  • axis:int或str轴名称,可选,沿给定轴上下对齐对象。
  • inplace:bool,认为False,是否对数据执行适当的操作。
s = pd.Series([-1, 1.2345, 100, -50])
s.round(2)
0     -1.00
1      1.23
2    100.00
3    -50.00
dtype: float64
s.abs()
0      1.0000
1      1.2345
2    100.0000
3     50.0000
dtype: float64
s.clip(0,2) # 前两个数分别表示上下截断边界
0    0.0000
1    1.2345
2    2.0000
3    0.0000
dtype: float64

【练一练】
在 clip 中,超过边界的只能截断为边界值,如果要把超出边界的替换为自定义的值,应当如何做?
答:可以用条件赋值,如下:

ss = pd.Series([i if i < 2 else 3 for i in s])
ss = pd.Series([i if i > 0 else -2 for i in ss])
ss
0   -2.0000
1    1.2345
2    3.0000
3   -2.0000
dtype: float64

5. 排序函数

排序共有两种方式,其一为值排序,其二为索引排序,对应的函数sort_valuessort_index

Series.sort_values(axis=0, ascending=True, inplace=False, kind=‘quicksort’, na_position=‘last’, ignore_index=False, key=None)
按值排序
参数

  • axis:{0或’index’},认0,按轴直接排序
  • ascending:bool,认为True,如果为True,则按升序对值排序,否则按降序排序
  • inplace:bool,认为False,如果为True,则就地执行操作,即产生新Series,否则更新原始Series
  • kind:{‘quicksort’,‘mergesort’或’heapsort’},认为’quicksort’,选择排序算法
  • na_position:{‘first’或’last’},认为’last’,参数“ first”将NaN放在开头,“ last”将NaN放在结尾
  • ignore_index:bool,认为False,如果为True,则结果轴将标记为0、1,…,n-1
  • key:可调用,可选,如果不是“None”,则在排序之前将键函数应用于序列值

DataFrame.sort_values(by, axis=0, ascending=True, inplace=False, kind=‘quicksort’, na_position=‘last’, ignore_index=False, key=None)
沿任一轴的值排序
参数

  • by:str或str列表,名称或要排序的名称列表,需要对多个列同时排序时使用列表
    • 如果axis为0或’index’,则by可能包含索引级别和/或列标签
    • 如果axis为1或“ columns”,则by可能包含列级别和/或索引标签
  • 其他参数同前

Series/DataFrame.sort_index(axis=0, level=None, ascending=True, inplace=False, kind=‘quicksort’, na_position=‘last’, sort_remaining=True, ignore_index=False, key=None)
按索引标签对系列进行排序
参数

  • level:int或级别名称或级别列表或级别名称列表,如果不是None,则对指定索引级别中的值进行排序
  • 其他参数同前

为了演示排序函数,下面先利用 set_index 方法把年级和姓名两列作为索引,多级索引的内容和索引设置的方法将在第三章进行详细讲解。

DataFrame.set_index(keys, drop=True, append=False, inplace=False, verify_integrity=False)
使用现有一个或多个列设置DataFrame索引,索引可以替换现有索引或在其上扩展
参数

  • keys:标签或类似数组或标签/数组列表,此参数可以是单个列键,长度与调用DataFrame相同的单个数组,也可以是包含列键和数组的任意组合的列表
  • drop:bool,认为True,删除要用作新索引的列
  • append:bool,认为False,是否将列追加到现有索引
  • inplace:bool,认为False,是否将修改后的作为新表创建
  • verify_integrity:bool,认为False,检查新索引是否重复
df_demo = df[['Grade', 'Name','Height', 'Weight']].set_index(['Grade','Name'])
df_demo
HeightWeight
GradeName
FreshmanGaopeng Yang158.946.0
Changqiang You166.570.0
SeniorMei Sun188.989.0
SophomoreXiaojuan SunNaN41.0
Gaojuan You174.074.0
............
JuniorXiaojuan Sun153.946.0
SeniorLi Zhao160.950.0
Chengqiang Chu153.945.0
Chengmei Shen175.371.0
SophomoreChunpeng Lv155.751.0

200 rows × 2 columns

对身高进行排序,认参数 ascending=True 为升序:

df_demo.sort_values('Height').head()
HeightWeight
GradeName
JuniorXiaoli Chu145.434.0
SeniorGaomei Lv147.334.0
SophomorePeng Han147.834.0
SeniorChangli Lv148.741.0
SophomoreChangjuan You150.540.0
df_demo.sort_values('Height', ascending = False).head()
HeightWeight
GradeName
SeniorXiaoqiang Qin193.979.0
Mei Sun188.989.0
Gaoli Zhao186.583.0
FreshmanQiang Han185.387.0
SeniorQiang Zheng183.987.0

在排序中,经常遇到多列排序的问题,比如在体重相同的情况下,对身高进行排序,并且保持身高降序排列,体重升序排列:

df_demo.sort_values(by = ['Weight', 'Height'], ascending = [True, False]).head()
HeightWeight
GradeName
SophomorePeng Han147.834.0
SeniorGaomei Lv147.334.0
JuniorXiaoli Chu145.434.0
SophomoreQiang Zhou150.536.0
FreshmanYanqiang Xu152.438.0

索引排序的用法和值排序完全一致,只不过元素的值在索引中,此时需要指定索引层的名字或者层号,用参数 level 表示。另外,需要注意的是字符串的排列顺序由字母顺序决定

df_demo.sort_index(level = ['Grade', 'Name'], ascending = [True, False]).head()
HeightWeight
GradeName
FreshmanYanquan Wang163.555.0
Yanqiang Xu152.438.0
Yanqiang Feng162.351.0
Yanpeng LvNaN65.0
Yanli Zhang165.152.0

6.apply方法

apply 方法常用于 DataFrame 的行迭代或者列迭代

**Series.apply(func, convert_dtype=True, args=(), kwds)
在Series值上调用函数
参数

  • func:函数,python函数或者numpy的ufunc
  • convert_dtype:bool,认为True,尝试找到更好的dtype以获得逐元素函数结果。如果为False,则保留为dtype = object
  • args:元组,在序列值之后将位置参数传递给func

**DataFrame.apply(func, axis=0, raw=False, result_type=None, args=(), kwds)
沿DataFrame的轴调用函数
参数

  • axis:{0或’index’,1或’columns’},认0,指定函数是按列(0或’index’)应用还是按行(1或’columns’)应用
  • raw:bool,认为False,确定是否将行或列作为Series或ndarray对象传递:
    • False :将每个行或列作为系列传递给函数
    • True:传递的函数将改为接收ndarray对象
  • result_type:{‘expand’,‘reduce’,‘broadcast’,None},认为None,这些仅在axis=1(columns)时起作用
    • ‘expand’:类似列表的结果将变成列
    • ‘reduce’:如果可能,返回一个Series,而不是扩展类似列表的结果
    • broadcast’:结果将广播到DataFrame的原始形状,原始索引和列将保留
    • None:取决于所应用函数的返回值
  • 其他参数同前

它的 axis 含义与第2小节中的统计聚合函数一致, apply 的参数往往是一个以序列为输入的函数。例如对于 .mean() ,使用 apply 可以如下地写出:

df_demo = df[['Height', 'Weight']]
def my_mean(x):
    res = x.mean()
    return res

df_demo.apply(my_mean)
Height    163.218033
Weight     55.015873
dtype: float64

同样的,可以利用 lambda 表达式使得书写简洁,这里的 x 就指代被调用的 df_demo 表中逐个输入的序列:

df_demo.apply(lambda x: x.mean())
Height    163.218033
Weight     55.015873
dtype: float64

若指定 axis=1 ,那么每次传入函数的就是行元素组成的 Series ,其结果与之前的逐行均值结果一致。

df_demo.apply(lambda x: x.mean(), axis = 1).head()
0    102.45
1    118.25
2    138.95
3     41.00
4    124.00
dtype: float64

这里再举一个例子: mad 函数返回的是一个序列中偏离该序列均值的绝对值大小的均值,例如序列1,3,7,10中,均值为5.25,每一个元素偏离的绝对值为4.25,2.25,1.75,4.75,这个偏离序列的均值为3.25。现在利用 apply 计算升高和体重的 mad 指标:

df_demo.apply(lambda x: (x - x.mean()).abs().mean())
Height     6.707229
Weight    10.391870
dtype: float64

这与使用内置的 mad 函数计算结果一致:

df_demo.mad()
Height     6.707229
Weight    10.391870
dtype: float64

【注】谨慎使用 apply
得益于传入自定义函数的处理, apply 的自由度很高,但这是以性能为代价的。一般而言,使用 pandas 的内置函数处理和 apply 来处理同一个任务,其速度会相差较多,因此只有在确实存在自定义需求的情境下才考虑使用 apply 。

四、窗口对象

pandas 中有3类窗口,分别是滑动窗口 rolling扩张窗口 expanding 以及指数加权窗口 ewm 。需要说明的是,以日期偏置为窗口大小的滑动窗口将在第十章讨论,指数加权窗口见本章练习。

1.滑窗对象

要使用滑窗函数,就必须先要对一个序列使用 .rolling 得到滑窗对象,其最重要的参数为窗口大小 window 。

Series/DataFrame.rolling(window, min_periods=None, center=False, win_type=None, on=None, axis=0, closed=None)
生成滑窗工具
参数

  • window:int,offset或BaseIndexer子类,表示移动窗口的大小,这是用于计算统计量的观察值的数量,每个窗口将是固定大小。如果偏移,则这将是每个窗口的时间段。每个窗口的大小将根据时间段内的观察结果而变化
  • min_periods:int,认值None,窗口中具有值的最小观察数(否则结果为NA)。对于由偏移量指定的窗口,min_periods将认为1。否则,min_periods将认为窗口的大小
  • center:bool,认为False,将当前位置设置在窗口的中央
  • win_type:str,认值None,提供一个窗口类型。如果为None,则所有点均加权
  • on:str,可选,对于DataFrame,是类似于日期时间的列或MultiIndex级别,在其上计算滚动窗口,而不是DataFrame的索引。由于不使用整数索引来计算滚动窗口,因此忽略提供的整数列并将其从结果中排除
  • axis:int或str,认为0
  • closed:str,认为None,使间隔在“right”,“left”,“both”或“neither”端点上关闭。对于基于偏移的窗口,认为“ right”。对于固定窗口,认为“both”

【VC小注】窗口中若有一个元素为None,则无法计算结果

s = pd.Series([1, 2, 3, 4, 5])
roller = s.rolling(window = 3)
roller
Rolling [window=3,center=False,axis=0]

在得到了滑窗对象后,能够使用相应的聚合函数进行计算,需要注意的是窗口包含当前行所在的元素,例如在第四个位置进行均值运算时,应当计算(2+3+4)/3,而不是(1+2+3)/3:

roller.mean()
0    NaN
1    NaN
2    2.0
3    3.0
4    4.0
dtype: float64
roller.sum()
0     NaN
1     NaN
2     6.0
3     9.0
4    12.0
dtype: float64

对于滑动相关系数或滑动协方差的计算,可以如下写出:

s2 = pd.Series([1, 2, 6, 16, 30])
roller.cov(s2)
0     NaN
1     NaN
2     2.5
3     7.0
4    12.0
dtype: float64
roller.corr(s2)
0         NaN
1         NaN
2    0.944911
3    0.970725
4    0.995402
dtype: float64

此外,还支持使用 apply 传入自定义函数,其传入值是对应窗口的 Series ,例如上述的均值函数可以等效表示:

roller.apply(lambda x: x.mean())
0    NaN
1    NaN
2    2.0
3    3.0
4    4.0
dtype: float64

shift,diff,pct_change是一组类滑窗函数,它们的公共参数为periods=n,认为1,分别表示取向前第n个元素的值与向前第n个元素做差(与Numpy中不同,后者表示n阶差分)、与向前第n个元素相比计算增长率。这里的n可以为负,表示反方向的类似操作。

Series/DataFrame.shift(periods=1, freq=None, axis=0, fill_value=None)
按期望的周期数移动索引,并带有可选的时间频率
参数

  • periods:int,要转移的时期数。可以是正数或负数
  • freq:DateOffset,tseries.offsets,timedelta或str(可选),从tseries模块或时间规则使用的偏移量
  • axis:{0或’index’,1或’columns’,None},认为None,偏移方向
  • fill_value:object,可选,用于新引入的缺失值的标量值

Series.diff(periods=1)
计算Series元素与Series中另一个元素相比的差值(认值为上一行中的元素)
参数

  • periods:nt,认为1,周期来计算移位的差值,接受负值

DataFrame.diff(periods=1, axis=0)
计算DataFrame元素与DataFrame中另一个元素相比的差值(认值为上一行中的元素)
参数

  • axis:{0 or‘index’,1 or‘columns’},default 0,跨行(0)或跨列(1)计算差值
  • 其他参数同前

**Series/DataFrame.pct_change(periods=1, fill_method=‘pad’, limit=None, freq=None, kwargs)
当前元素与先前元素之间的百分比变化。认情况下,计算与前一行的百分比变化
参数

  • periods:int,认为1,形成百分比变化的周期
  • fill_method:str,认为‘pad’,在计算百分比变化之前如何处理资产净值
  • limit:int,认None,停止之前要填充的连续NA数
  • freq:DateOffset,timedelta或str(可选),从时间序列API开始使用的增量
s = pd.Series([1, 3, 6, 10, 15])
s.shift(2)
0    NaN
1    NaN
2    1.0
3    3.0
4    6.0
dtype: float64
s.diff(3)
0     NaN
1     NaN
2     NaN
3     9.0
4    12.0
dtype: float64
s.pct_change()
0         NaN
1    2.000000
2    1.000000
3    0.666667
4    0.500000
dtype: float64
s.shift(-1)
0     3.0
1     6.0
2    10.0
3    15.0
4     NaN
dtype: float64
s.diff(-2)
0   -5.0
1   -7.0
2   -9.0
3    NaN
4    NaN
dtype: float64

将其视作类滑窗函数的原因是,它们的功能可以用窗口大小为 n+1 的 rolling 方法等价代替

s.rolling(3).apply(lambda x: list(x)[0])# s.shift(2)
0    NaN
1    NaN
2    1.0
3    3.0
4    6.0
dtype: float64
s.rolling(4).apply(lambda x: list(x)[-1] - list(x)[0]) # s.diff(3)
0     NaN
1     NaN
2     NaN
3     9.0
4    12.0
dtype: float64
def my_pct(x):
    L = list(x)
    return (L[-1]-L[0])/L[0]

s.rolling(2).apply(my_pct)# s.pct_change()
0         NaN
1    2.000000
2    1.000000
3    0.666667
4    0.500000
dtype: float64

【练一练】
rolling 对象的认窗口方向都是向前的,某些情况下用户需要向后的窗口,例如对1,2,3设定向后窗口为2的 sum 操作,结果为3,5,NaN,此时应该如何实现向后的滑窗操作?

#暂时没想出来

2.扩张窗口

扩张窗口又称累计窗口,可以理解为一个动态长度的窗口,其窗口的大小就是从序列开始处到具体操作的对应位置,其使用的聚合函数会作用于这些逐步扩张的窗口上。具体地说,设序列为a1, a2, a3, a4,则其每个位置对应的窗口即[a1]、[a1, a2]、[a1, a2, a3]、[a1, a2, a3, a4]。

Series/DataFrame.expanding(min_periods=1, center=None, axis=0)
提供扩展的转换
参数

  • min_periods:int,认为1,窗口中具有值的最小观察数
  • center:bool,认为False,将标签设置在窗口的中央
  • axis:int或str,认为0
s = pd.Series([1, 3, 6, 10])
s.expanding().mean()
0    1.000000
1    2.000000
2    3.333333
3    5.000000
dtype: float64

【练一练】
cummax, cumsum, cumprod 函数是典型的类扩张窗口函数,请使用 expanding 对象依次实现它们。

Series/DataFrame.cummax(axis=None, skipna=True, *args, **kwargs)
返回DataFrame或Series轴上的累积最大值
参数

  • axis:{0或’index’,1或’columns’},认0,轴的索引或名称。0等于None或“index”
  • skipna:bool,认为True,排除NA /空值。如果整个行/列均为NA,则结果为NA

Series/DataFrame.cumsum(axis=None, skipna=True, *args, **kwargs)
返回DataFrame或Series轴上的累积总和
参数

  • axis:{0或’index’,1或’columns’},认0,轴的索引或名称。0等于None或“index”
  • skipna:bool,认为True,排除NA /空值。如果整个行/列均为NA,则结果为NA

Series/DataFrame.cumprod(axis=None, skipna=True, *args, **kwargs)
返回DataFrame或Series轴上的累积乘积
参数

  • axis:{0或’index’,1或’columns’},认0,轴的索引或名称。0等于None或“index”
  • skipna:bool,认为True,排除NA /空值。如果整个行/列均为NA,则结果为NA
s = pd.Series([1, 3, 6, 10])
s.expanding().max()
0     1.0
1     3.0
2     6.0
3    10.0
dtype: float64
s.cummax()
0     1
1     3
2     6
3    10
dtype: int64
s.expanding().sum()
0     1.0
1     4.0
2    10.0
3    20.0
dtype: float64
s.cumsum()
0     1
1     4
2    10
3    20
dtype: int64
def my_multi(x):
    result = 1
    L = list(x)
    for i in L:
        result = result * i
    return  result

s.expanding().apply(my_multi)
0      1.0
1      3.0
2     18.0
3    180.0
dtype: float64
s.cumprod()
0      1
1      3
2     18
3    180
dtype: int64

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐