importnumpyasnpimportpandasaspd
在开始学习前,请保证pandas的版本号不低于1.1.4,否则请务必升级!
一、文件的读取和写入1.文件读取pandas可以读取的文件格式有很多,这里主要介绍读取csv,excel,txt文件。
df_csv=pd.read_csv(../data/my_csv.csv)df_csvcol1col2col3col4cola1.4apple/1/b3.4banana/1/c2.5orange/1/d3.2lemon/1/7
df_txt=pd.read_table(../data/my_table.txt)df_txtcol1col2col3cola1.4apple/1/b3.4banana/1/c2.5orange/1/d3.2lemon/1/7
df_excel=pd.read_excel(../data/my_excel.xlsx)df_excelcol1col2col3col4cola1.4apple/1/b3.4banana/1/c2.5orange/1/d3.2lemon/1/7
这里有一些常用的公共参数,header=None表示第一行不作为列名,index_col表示把某一列或几列作为索引,索引的内容将会在第三章进行详述,usecols表示读取列的集合,默认读取所有的列,parse_dates表示需要转化为时间的列,关于时间序列的有关内容将在第十章讲解,nrows表示读取的数据行数。上面这些参数在上述的三个函数里都可以使用。
pd.read_table(../data/my_table.txt,header=None)col1col2col3cola1.4apple/1/b3.4banana/1/c2.5orange/1/d3.2lemon/1/7
pd.read_csv(../data/my_csv.csv,index_col=[col1,col2])col3col4col5col1col22a1.4apple/1/13b3.4banana/1/26c2.5orange/1/55d3.2lemon/1/7
pd.read_table(../data/my_table.txt,usecols=[col1,col2])col1cola13b26c35d
pd.read_csv(../data/my_csv.csv,parse_dates=[col5])col1col2col3col4cola1.4apple-01-0b3.4banana-01-0c2.5orange-01-0d3.2lemon-01-07
pd.read_excel(../data/my_excel.xlsx,nrows=2)col1col2col3col4cola1.4apple/1/b3.4banana/1/2
在读取txt文件时,经常遇到分隔符非空格的情况,read_table有一个分割参数sep,它使得用户可以自定义分割符号,进行txt数据的读取。例如,下面的读取的表以
为分割:
pd.read_table(../data/my_table_special_sep.txt)col1
col20TS
Thisisanapple.1GQ
MynameisBob.2WT
Welldone!3PT
MayIhelpyou?
上面的结果显然不是理想的,这时可以使用sep,同时需要指定引擎为python:
pd.read_table(../data/my_table_special_sep.txt,sep=\
\
\
\
,engine=python)col1col20TSThisisanapple.1GQMynameisBob.2WTWelldone!3PTMayIhelpyou?sep是正则参数
在使用read_table的时候需要注意,参数sep中使用的是正则表达式,因此需要对
进行转义变成\
,否则无法读取到正确的结果。有关正则表达式的基本内容可以参考第八章或者其他相关资料。
2.数据写入一般在数据写入中,最常用的操作是把index设置为False,特别当索引没有特殊意义的时候,这样的行为能把索引在保存的时候去除。
df_csv.to_csv(../data/my_csv_saved.csv,index=False)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_markdown和to_latex函数,此处需要安装tabulate包。
print(df_csv.to_markdown())
col1
col2
col3
col4
col5
---:
-------:
:-------
-------:
:-------
:---------
0
2
a
1.4
apple
/1/1
1
3
b
3.4
banana
/1/2
2
6
c
2.5
orange
/1/5
3
5
d
3.2
lemon
/1/7
print(df_csv.to_latex())
\begin{tabular}{lrlrll}\toprule{}col1col2col3col4col5\\\midrule02a1.4apple/1/1\\13b3.4banana/1/2\\26c2.5orange/1/5\\35d3.2lemon/1/7\\\bottomrule\end{tabular}二、基本数据结构
pandas中具有两种基本的数据存储结构,存储一维values的Series和存储二维values的DataFrame,在这两种结构上定义了很多的属性和方法。
1.SeriesSeries一般由四个部分组成,分别是序列的值data、索引index、存储类型dtype、序列的名字name。其中,索引也可以指定它的名字,默认为空。
s=pd.Series(data=[,a,{dic1:5}],index=pd.Index([id1,20,third],name=my_idx),dtype=object,name=my_name)s
my_idxidathird{dic1:5}Name:my_name,dtype:objectobject类型
object代表了一种混合类型,正如上面的例子中存储了整数、字符串以及Python的字典数据结构。此外,目前pandas把纯字符串序列也默认认为是一种object类型的序列,但它也可以用string类型存储,文本序列的内容会在第八章中讨论。
对于这些属性,可以通过.的方式来获取:
s.values
array([,a,{dic1:5}],dtype=object)
s.index
Index([id1,20,third],dtype=object,name=my_idx)
s.dtype
dtype(O)
s.name
my_name
利用.shape可以获取序列的长度:
s.shape
(3,)
索引是pandas中最重要的概念之一,它将在第三章中被详细地讨论。如果想要取出单个索引对应的值,可以通过[index_item]可以取出。
2.DataFrameDataFrame在Series的基础上增加了列索引,一个数据框可以由二维的data与行列索引来构造:
data=[[1,a,1.2],[2,b,2.2],[3,c,3.2]]df=pd.DataFrame(data=data,index=[row_%d%iforiinrange(3)],columns=[col_0,col_1,col_2])dfcol_0col_1col_2row_01a1.2row_12b2.2row_23c3.2
但一般而言,更多的时候会采用从列索引名到数据的映射来构造数据框,同时再加上行索引:
df=pd.DataFrame(data={col_0:[1,2,3],col_1:list(abc),col_2:[1.2,2.2,3.2]},index=[row_%d%iforiinrange(3)])dfcol_0col_1col_2row_01a1.2row_12b2.2row_23c3.2
由于这种映射关系,在DataFrame中可以用[col_name]与[col_list]来取出相应的列与由多个列组成的表,结果分别为Series和DataFrame:
df[col_0]
row_01row_12row_23Name:col_0,dtype:int64
df[[col_0,col_1]]col_0col_1row_01arow_12brow_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#返回的是值为相应列数据类型的Series
col_0int64col_1objectcol_2float64dtype:object
df.shape
(3,3)
通过.T可以把DataFrame进行转置:
df.Trow_0row_1row_2col_0col_1abccol_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)
上述列名依次代表学校、年级、姓名、性别、身高、体重、是否为转系生、体测场次、测试时间、0米成绩,本章只需使用其中的前七列。
df=df[df.columns[:7]]1.汇总函数
head,tail函数分别表示返回表或者序列的前n行和后n行,其中n默认为5:
df.head(2)SchoolGradeNameGenderHeightWeightTransfer0ShanghaiJiaoTongUniversityFreshmanGaopengYangFemale..0N1PekingUniversityFreshmanChangqiangYouMale..0N
df.tail(3)SchoolGradeNameGenderHeightWeightTransferShanghaiJiaoTongUniversitySeniorChengqiangChuFemale..0NShanghaiJiaoTongUniversitySeniorChengmeiShenMale..0NTsinghuaUniversitySophomoreChunpengLvMale..0N
info,describe分别返回表的信息概况和表中数值列对应的主要统计量:
df.info()
classpandas.core.frame.DataFrameRangeIndex:entries,0toDatacolumns(total7columns):#ColumnNon-NullCountDtype----------------------------0Schoolnon-nullobject1Gradenon-nullobject2Namenon-nullobject3Gendernon-nullobject4Heightnon-nullfloatWeightnon-nullfloatTransfernon-nullobjectdtypes:float64(2),object(5)memoryusage:11.1+KB
df.describe()HeightWeightcount..mean..073std8..min..25%..50%..75%..max..更全面的数据汇总
info,describe只能实现较少信息的展示,如果想要对一份数据集进行全面且有效的观察,特别是在列较多的情况下,推荐使用pandas-profiling包,它将在第十一章被再次提到。
2.特征统计函数在Series和DataFrame上定义了许多统计函数,最常见的是sum,mean,median,var,std,max,min。例如,选出身高和体重列进行演示:
df_demo=df[[Height,Weight]]df_demo.mean()
Height.Weight55.073dtype:float64
df_demo.max()
Height.9Weight89.0dtype:float64
此外,需要介绍的是quantile,count,idxmax这三个函数,它们分别返回的是分位数、非缺失值个数、最大值对应的索引:
df_demo.quantile(0.75)
Height.5Weight65.0Name:0.75,dtype:float64
df_demo.count()
HeightWeightdtype:int64
df_demo.idxmax()#idxmin是对应的函数
HeightWeight2dtype:int64
上面这些所有的函数,由于操作后返回的是标量,所以又称为聚合函数,它们有一个公共参数axis,默认为0代表逐列聚合,如果设置为1则表示逐行聚合:
df_demo.mean(axis=1).head()#在这个数据集上体重和身高的均值并没有意义
....004.00dtype:float.唯一值函数
对序列使用unique和nunique可以分别得到其唯一值组成的列表和唯一值的个数:
df[School].unique()
array([ShanghaiJiaoTongUniversity,PekingUniversity,FudanUniversity,TsinghuaUniversity],dtype=object)
df[School].nunique()
4
value_counts可以得到唯一值和其对应出现的频数:
df[School].value_counts()
TsinghuaUniversity69ShanghaiJiaoTongUniversity57FudanUniversity40PekingUniversity34Name:School,dtype:int64
如果想要观察多个列组合的唯一值,可以使用drop_duplicates。其中的关键参数是keep,默认值first表示每个组合保留第一次出现的所在行,last表示保留最后一次出现的所在行,False表示把所有重复组合所在的行剔除。
df_demo=df[[Gender,Transfer,Name]]df_demo.drop_duplicates([Gender,Transfer])GenderTransferName0FemaleNGaopengYang1MaleNChangqiangYou12FemaleNaNPengYou21MaleNaNXiaopengShen36MaleYXiaojuanQin43FemaleYGaoliFeng
df_demo.drop_duplicates([Gender,Transfer],keep=last)GenderTransferNameMaleNaNJuanYouMaleYChengpengYouFemaleYChengquanQinFemaleNaNYanmeiQianFemaleNChengqiangChuMaleNChunpengLv
df_demo.drop_duplicates([Name,Gender],keep=False).head()#保留只出现过一次的性别和姓名组合GenderTransferName0FemaleNGaopengYang1MaleNChangqiangYou2MaleNMeiSun4MaleNGaojuanYou5FemaleNXiaoliQian
df[School].drop_duplicates()#在Series上也可以使用
0ShanghaiJiaoTongUniversity1PekingUniversity3FudanUniversity5TsinghuaUniversityName:School,dtype:object
此外,duplicated和drop_duplicates的功能类似,但前者返回了是否为唯一值的布尔列表,其keep参数与后者一致。其返回的序列,把重复元素设为True,否则为False。drop_duplicates等价于把duplicated为True的对应行剔除。
df_demo.duplicated([Gender,Transfer]).head()
0False1False2True3True4Truedtype:bool
df[School].duplicated().head()#在Series上也可以使用
0False1False2True3False4TrueName:School,dtype:bool4.替换函数
一般而言,替换操作是针对某一个列进行的,因此下面的例子都以Series举例。pandas中的替换函数可以归纳为三类:映射替换、逻辑替换、数值替换。其中映射替换包含replace方法、第八章中的str.replace方法以及第九章中的cat.codes方法,此处介绍replace的用法。
在replace中,可以通过字典构造,或者传入两个列表来进行替换:
df[Gender].replace({Female:0,Male:1}).head()
Name:Gender,dtype:int64
df[Gender].replace([Female,Male],[0,1]).head()
Name:Gender,dtype:int64
另外,replace还有一种特殊的方向替换,指定method参数为ffill则为用前面一个最近的未被替换的值进行替换,bfill则使用后面最近的未被替换的值进行替换。从下面的例子可以看到,它们的结果是不同的:
s=pd.Series([a,1,b,2,1,1,a])s.replace([1,2],method=ffill)
0a1a2b3b4b5b6adtype:object
s.replace([1,2],method=bfill)
0a1b2b3a4a5a6adtype:object正则替换请使用str.replace
虽然对于replace而言可以使用正则替换,但是当前版本下对于string类型的正则替换还存在bug,因此如有此需求,请选择str.replace进行替换操作,具体的方式将在第八章中讲解。
逻辑替换包括了where和mask,这两个函数是完全对称的:where函数在传入条件为False的对应行进行替换,而mask在传入条件为True的对应行进行替换,当不指定替换值时,替换为缺失值。
s=pd.Series([-1,1.,,-50])s.where(s0)
0-1.01NaN2NaN3-50.0dtype:float64
s.where(s0,)
0-1.01.02.03-50.0dtype:float64
s.mask(s0)
0NaN11.2.NaNdtype:float64
s.mask(s0,-50)
0-50..2.-50.dtype:float64
需要注意的是,传入的条件只需是与被调用的Series索引一致的布尔序列即可:
s_condition=pd.Series([True,False,False,True],index=s.index)s.mask(s_condition,-50)
0-50..2.-50.dtype:float64
数值替换包含了round,abs,clip方法,它们分别表示取整、取绝对值和截断:
s=pd.Series([-1,1.,,-50])s.round(2)
0-1..232.-50.00dtype:float64
s.abs()
01..2.50.dtype:float64
s.clip(0,2)#前两个数分别表示上下截断边界
00..22.0.dtype:float64
在clip中,超过边界的只能截断为边界值,如果要把超出边界的替换为自定义的值,应当如何做?
data=s.clip(0,2)data.where(data0,-50)0-50..22.-50.dtype:float.排序函数排序共有两种方式,其一为值排序,其二为索引排序,对应的函数是sort_values和sort_index。
为了演示排序函数,下面先利用set_index方法把年级和姓名两列作为索引,多级索引的内容和索引设置的方法将在第三章进行详细讲解。
df_demo=df[[Grade,Name,Height,Weight]].set_index([Grade,Name])df_demo.head(3)HeightWeightGradeNameFreshmanGaopengYang..0ChangqiangYou..0SeniorMeiSun..0
对身高进行排序,默认参数ascending=True为升序:
df_demo.sort_values(Height).head()HeightWeightGradeNameJuniorXiaoliChu..0SeniorGaomeiLv..0SophomorePengHan..0SeniorChangliLv..0SophomoreChangjuanYou..0
df_demo.sort_values(Height,ascending=False).head()HeightWeightGradeNameSeniorXiaoqiangQin..0MeiSun..0GaoliZhao..0FreshmanQiangHan..0SeniorQiangZheng..0
在排序中,进场遇到多列排序的问题,比如在体重相同的情况下,对身高进行排序,并且保持身高降序排列,体重升序排列:
df_demo.sort_values([Weight,Height],ascending=[True,False]).head()HeightWeightGradeNameSophomorePengHan..0SeniorGaomeiLv..0JuniorXiaoliChu..0SophomoreQiangZhou..0FreshmanYanqiangXu..0
索引排序的用法和值排序完全一致,只不过元素的值在索引中,此时需要指定索引层的名字或者层号,用参数level表示。另外,需要注意的是字符串的排列顺序由字母顺序决定。
df_demo.sort_index(level=[Grade,Name],ascending=[True,False]).head()HeightWeightGradeNameFreshmanYanquanWang..0YanqiangXu..0YanqiangFeng..0YanpengLvNaN65.0YanliZhang..06.apply方法
apply方法常用于DataFrame的行迭代或者列迭代,它的axis含义与第2小节中的统计聚合函数一致,apply的参数往往是一个以序列为输入的函数。例如对于.mean(),使用apply可以如下地写出:
df_demo=df[[Height,Weight]]defmy_mean(x):res=x.mean()returnresdf_demo.apply(my_mean)
Height.Weight55.073dtype:float64
同样的,可以利用lambda表达式使得书写简洁,这里的x就指代被调用的df_demo表中逐个输入的序列:
df_demo.apply(lambdax:x.mean())
Height.Weight55.073dtype:float64
若指定axis=1,那么每次传入函数的就是行元素组成的Series,其结果与之前的逐行均值结果一致。
df_demo.apply(lambdax:x.mean(),axis=1).head()
....004.00dtype:float64
这里再举一个例子:mad函数返回的是一个序列中偏离该序列均值的绝对值大小的均值,例如序列1,3,7,10中,均值为5.25,每一个元素偏离的绝对值为4.25,2.25,1.75,4.75,这个偏离序列的均值为3.25。现在利用apply计算升高和体重的mad指标:
df_demo.apply(lambdax:(x-x.mean()).abs().mean())
Height6.Weight10.dtype:float64
这与使用内置的mad函数计算结果一致:
df_demo.mad()
Height6.Weight10.dtype:float64谨慎使用apply
得益于传入自定义函数的处理,apply的自由度很高,但这是以性能为代价的。一般而言,使用pandas的内置函数处理和apply来处理同一个任务,其速度会相差较多,因此只有在确实存在自定义需求的情境下才考虑使用apply。
四、窗口对象pandas中有3类窗口,分别是滑动窗口rolling、扩张窗口expanding以及指数加权窗口ewm。需要说明的是,以日期偏置为窗口大小的滑动窗口将在第十章讨论,指数加权窗口见本章练习。
1.滑窗对象要使用滑窗函数,就必须先要对一个序列使用.rolling得到滑窗对象,其最重要的参数为窗口大小window。
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()
0NaN1NaN22...0dtype:float64
roller.sum()
0NaN1NaN26..0.0dtype:float64
对于滑动相关系数或滑动协方差的计算,可以如下写出:
s2=pd.Series([1,2,6,16,30])roller.cov(s2)
0NaN1NaN22..0.0dtype:float64
roller.corr(s2)
0NaN1NaN20.94490.97072.995dtype:float64
此外,还支持使用apply传入自定义函数,其传入值是对应窗口的Series,例如上述的均值函数可以等效表示:
roller.apply(lambdax:x.mean())
0NaN1NaN22...0dtype:float64
shift,diff,pct_change是一组类滑窗函数,它们的公共参数为periods=n,默认为1,分别表示取向前第n个元素的值、与向前第n个元素做差(与Numpy中不同,后者表示n阶差分)、与向前第n个元素相比计算增长率。这里的n可以为负,表示反方向的类似操作。
s=pd.Series([1,3,6,10,15])s.shift(2)
0NaN1NaN21...0dtype:float64
s.diff(3)
0NaN1NaN2NaN39.0.0dtype:float64
s.pct_change()
0NaN12.21.30..50dtype:float64
s.shift(-1)
03....04NaNdtype:float64
s.diff(-2)
0-5.01-7.02-9.03NaN4NaNdtype:float64
将其视作类滑窗函数的原因是,它们的功能可以用窗口大小为n+1的rolling方法等价代替:
s.rolling(3).apply(lambdax:list(x)[0])#s.shift(2)
0NaN1NaN21...0dtype:float64
s.rolling(4).apply(lambdax:list(x)[-1]-list(x)[0])#s.diff(3)
0NaN1NaN2NaN39.0.0dtype:float64
defmy_pct(x):L=list(x)returnL[-1]/L[0]-1s.rolling(2).apply(my_pct)#s.pct_change()
0NaN12.21.30..50dtype:float64
rolling对象的默认窗口方向都是向前的,某些情况下用户需要向后的窗口,例如对1,2,3设定向后窗口为2的sum操作,结果为3,5,NaN,此时应该如何实现向后的滑窗操作?(提示:使用shift)
data=pd.Series([1,2,3])roller=data.rolling(window=2)roller.sum().shift(-1)03..02NaNdtype:float.扩张窗口扩张窗口又称累计窗口,可以理解为一个动态长度的窗口,其窗口的大小就是从序列开始处到具体操作的对应位置,其使用的聚合函数会作用于这些逐步扩张的窗口上。具体地说,设序列为a1,a2,a3,a4,则其每个位置对应的窗口即[a1]、[a1,a2]、[a1,a2,a3]、[a1,a2,a3,a4]。
s=pd.Series([1,3,6,10])s.expanding().mean()
01.12.23..dtype:float64
cummax,cumsum,cumprod函数是典型的类扩张窗口函数,请使用expanding对象依次实现它们。
data=pd.Series([1,3,6,10])#cummaxdata.expanding().max()01....0dtype:float64#cumsumdata.expanding().sum()01....0dtype:float64#cumproddefmultiplyList(myList):#将列表元素一一相乘product=1forxinmyList:product=product*xreturnproductdata.expanding().apply(lambdax:multiplyList(x),raw=False)01....0dtype:float64五、练习Ex1:口袋妖怪数据集现有一份口袋妖怪的数据集,下面进行一些背景说明:
#代表全国图鉴编号,不同行存在相同数字则表示为该妖怪的不同状态
妖怪具有单属性和双属性两种,对于单属性的妖怪,Type2为缺失值
Total,HP,Attack,Defense,Sp.Atk,Sp.Def,Speed分别代表种族值、体力、物攻、防御、特攻、特防、速度,其中种族值为后6项之和
df=pd.read_csv(../data/pokemon.csv)df.head(3)#NameType1Type2TotalHPAttackDefenseSp.AtkSp.DefSpeed01BulbasaurGrassPoison12IvysaurGrassPoisonVenusaurGrassPoison52580828380
对HP,Attack,Defense,Sp.Atk,Sp.Def,Speed进行加总,验证是否为Total值。
解答:
importpandasaspdimportnumpyasnpdf=pd.read_csv(D:\python与kaggle\数据分析学习笔记\参考答案\pokemon.csv)(df[[HP,Attack,Defense,Sp.Atk,Sp.Def,Speed]].sum(1)!=df[Total]).mean()0.0
对于#重复的妖怪只保留第一条记录,解决以下问题:
求第一属性的种类数量和前三多数量对应的种类dp_dup=df.drop_duplicates(#,keep=first)dp_dup[Type1].nunique()dp_dup[Type1].value_counts().index[:3]求第一属性和第二属性的组合种类attr_dup=dp_dup.drop_duplicates([Type1,Type2])attr_dup.shape[0]求尚未出现过的属性组合L_full=[.join([i,j])ifi!=jelseiforjindp_dup[Type1].unique()foriindp_dup[Type1].unique()]L_part=[.join([i,j])iftype(j)!=floatelseifori,jinzip(attr_dup[Type1],attr_dup[Type2])]res=set(L_full).difference(set(L_part))len(res)#打印数量按照下述要求,构造Series:取出物攻,超过的替换为high,不足50的替换为low,否则设为middf[Attack].mask(df[Attack],high).mask(df[Attack]50,low).mask((50=df[Attack])(df[Attack]=),mid).head()取出第一属性,分别用replace和apply替换所有字母为大写df[Type1].replace({i:str.upper(i)foriindf[Type1].unique()})df[Type1].apply(lambdax:str.upper(x)).head()求每个妖怪六项能力的离差,即所有能力中偏离中位数最大的值,添加到df并从大到小排序df[Deviation]=df[[HP,Attack,Defense,Sp.Atk,Sp.Def,Speed]].apply(lambdax:np.max((x-x.median()).abs()),1)df.sort_values(Deviation,ascending=False).head()Ex2:指数加权窗口作为扩张窗口的ewm窗口在扩张窗口中,用户可以使用各类函数进行历史的累计指标统计,但这些内置的统计函数往往把窗口中的所有元素赋予了同样的权重。事实上,可以给出不同的权重来赋给窗口中的元素,指数加权窗口就是这样一种特殊的扩张窗口。
其中,最重要的参数是alpha,它决定了默认情况下的窗口权重为
,其中
表示当前元素,
表示序列的第一个元素。
从权重公式可以看出,离开当前值越远则权重越小,若记原序列为
,更新后的当前元素为
,此时通过加权公式归一化后可知:
对于Series而言,可以用ewm对象如下计算指数平滑后的序列:
np.random.seed(0)s=pd.Series(np.random.randint(-1,2,30).cumsum())s.head()
0-11-12-23-24-2dtype:int32
s.ewm(alpha=0.2).mean().head()
0-1.1-1.2-1.-1.-1.dtype:float64
请用expanding窗口实现。
解答
np.random.seed(0)s=pd.Series(np.random.randint(-1,2,30).cumsum())defewm_func(x,alpha=0.2):win=(1-alpha)**np.arange(x.shape[0])[::1]#wi与xt-i序号相反res=(win*x).sum()/win.sum()returnress.expanding().apply(ewm_func).head()0-1.1-1.2-1.-1.-1.441dtype:float64作为滑动窗口的ewm窗口
从第1问中可以看到,ewm作为一种扩张窗口的特例,只能从序列的第一个元素开始加权。现在希望给定一个限制窗口n,只对包含自身最近的n个窗口进行滑动加权平滑。请根据滑窗函数,给出新的wi与yt的更新公式,并通过rolling窗口实现这一功能。
s.rolling(window=4).apply(ewm_func).head()#无需对原函数改动0NaN1NaN2NaN3-1.-1.dtype:float64预览时标签不可点收录于话题#个上一篇下一篇