import numpy as np
import pandas as pd
之前的版本号是1.0.5
使用pip install --upgrade pandas
更新即可
一、文件的读取和写入
1. 文件读取
pandas
可以读取的文件格式有很多,这里主要介绍读取csv, excel, txt
文件。
即pd.read_csv
pd.read_table
pd.read_excel
1.1pd.read_csv
pandas.read_csv(filepath_or_buffer, sep=', ', delimiter=None, header='infer', names=None, index_col=None, usecols=None, squeeze=False, prefix=None, mangle_dupe_cols=True, dtype=None, engine=None, converters=None, true_values=None, false_values=None, skipinitialspace=False, skiprows=None, nrows=None, na_values=None, keep_default_na=True, na_filter=True, verbose=False, skip_blank_lines=True, parse_dates=False, infer_datetime_format=False, keep_date_col=False, date_parser=None, dayfirst=False, iterator=False, chunksize=None, compression='infer', thousands=None, decimal=b'.', lineterminator=None, quotechar='"', quoting=0, escapechar=None, comment=None, encoding=None, dialect=None, tupleize_cols=None, error_bad_lines=True, warn_bad_lines=True, skipfooter=0, doublequote=True, delim_whitespace=False, low_memory=True, memory_map=False, float_precision=None)
具体参数详解参考:pandas参数详解
1.2pd.read_table
pandas.read_table(filepath_or_buffer,sep='\t',delimiter=None,header='infer',names=None,
index_col=None,usecols=None,squeeze=False,prefix=None,mangle_dupe_cols=True,dtype=None,
engine=None,converters=None,true_values=None,false_values=None,skipinitialspace=False,
skiprows=None,nrows=None,na_values=None,keep_default_na=True,na_filter=True,
verbose=False,skip_blank_lines=True,parse_dates=False,infer_datetime_format=False,
keep_date_col=False,date_parser=None,dayfirst=False,iterator=False,chunksize=None,
compression='infer',thousands=None,decimal=b'.',lineterminator=None,quotechar='"',
quoting=0,escapechar=None,comment=None,encoding=None,dialect=None,tupleize_cols=None,
error_bad_lines=True,warn_bad_lines=True,skipfooter=0,doublequote=True,
delim_whitespace=False,low_memory=True,memory_map=False,float_precision=None)
和pandas.read_csv
参数类似,可以看到前者sep=‘,’
后者sep='\t'
1.3pd.read_excel
pd.read_excel(io, sheet_name=0, header=0, names=None, index_col=None, usecols=None, squeeze=False, dtype=None, engine=None, converters=None, true_values=None, false_values=None, skiprows=None, nrows=None, na_values=None, keep_default_na=True, na_filter=True, verbose=False, parse_dates=False, date_parser=None, thousands=None, comment=None, skipfooter=0, convert_float=True, mangle_dupe_cols=True)
参数详解:
1.io参数
io参数可以接受的有:str,Excel文件,xlrd.Book,路径对象或类似文件的对象,其中最常用的是str,一般是文件路径+文件名,需要注意的是文件名字不要漏掉后缀,即文件扩展名,表明文件类型的那个!有时候需要对路径中的”\”进行转义,io参数没有默认值,必须传入。
2.sheet_name参数
sheet_name参数可以接收的有:str,int,list或None,默认0
其中,字符串用于工作表名称。 整数用于零索引工作表位置。 字符串/整数列表用于请求多个工作表。设置None获取所有工作表。
有时候一个excel工作簿中包含有很多个sheet工作表,如果不指定默认为0,数据读入的时候默认读入的是第一个位置的sheet。0就是排在第一个位置的sheet,1是排在第二位置的sheet,依次类推。
也可以传入列表[0,1],输出的结果是Dict,里面存入两个sheet的内容。
df_excel1=pd.read_excel('../data/my_excel.xlsx', sheet_name=[0,1])
type(df_excel1) #Dict
3.header参数
这个参数是用来指定哪一行作为列名的,默认是第0行,接收的参数可以是整数(指定第几行作为列名),可以是有整数组成的列表(指定哪几行作为列名,是的,列名可以有多行,是不是有点突破认知?),也可以是None(没有列名)。
4.names参数
官方文档说这个参数接收 array-like, 默认 None,表示要使用的列名列表,如果不需要列名,请设置header = None,如果header 和names参数都设置的话,依然会显示names指定的列名。
5.usecols参数
该参数接收字符或者类似列表的序列,默认值是None,返回的是列的子集,直白点解释就是在读入表格的时候不是所有的列都会被读入,可以通过usecols参数来设置要把哪些列读取进来。
如果是None,表示所有的列都会被读取。
如果是列表,表示选取指定的列读取,比如像要只读入第n列,这样就可以usecols=[n],如果是多列,就把多个整数放入一个列表中传递给参数。需要留心的是,列表中不止可以传入整数,也可以是字段名组成的列表。
如果是str,则可以用A表示第一列,依次类推。例如‘A,B’或者‘A,B,E:F’
注意:如果设置了names参数,注意设置的列名个数要和读取的列数一致
这里有一些常用的公共参数,header=None
表示第一行不作为列名,index_col
表示把某一列或几列作为索引,索引的内容将会在第三章进行详述,usecols
表示读取列的集合,默认读取所有的列,parse_dates
表示需要转化为时间的列,关于时间序列的有关内容将在第十章讲解,nrows
表示读取的数据行数。上面这些参数在上述的三个函数里都可以使用。
pd.read_csv('../data/my_csv.csv', index_col=['col1', 'col2'])
pd.read_csv('../data/my_csv.csv', index_col=[0,1])
pd.read_excel('../data/my_excel.xlsx', index_col=[0,1])
区别:pd.read_excel中index_col中只能传入元素是整数的列表
这里用的都是相对路径引用。
在读取 txt
文件时,经常遇到分隔符非空格的情况, read_table
有一个分割参数 sep
,它使得用户可以自定义分割符号,进行 txt
数据的读取。例如,下面的读取的表以 ||||
为分割:
上面的结果显然不是理想的,这时可以使用sep
,同时需要指定引擎为python
:
engine有两个参数:c和python。c只能处理sep为一个字符或\s+。故这里要指定引擎为python
注意: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)
与上面pd.read_csv()与pd.read_table()的区别对应,sep不一样。
如果想要把表格快速转换为markdown
和latex
语言,可以使用to_markdown
和to_latex
函数,此处需要安装tabulate
包。
二、基本数据结构
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'), #指定index的名字
dtype = 'object', #指定存储类型
name = 'my_name') #序列的名字
s
'''my_idx
id1 100
20 a
third {'dic1': 5}
Name: my_name, dtype: object'''
【NOTE】object
类型
object
代表了一种混合类型,正如上面的例子中存储了整数、字符串以及Python
的字典数据结构。此外,目前pandas
把纯字符串序列也默认认为是一种object
类型的序列,但它也可以用string
类型存储。
pd.Series()可以用字典结构为参数。
s=pd.Series({'a':1,'b':2,'c':3,'f':4,'e':5})
pd.Series的这些属性可以通过.的方式来获取:
还有pd.Series.is_monotonic
返回一个布尔值(若值是单调递增的则返回True)
pd.Series.is_monotonic_decreasing
是单调递减返回True
pd.Series.is_monotonic_increasing
与第一个一样
索引是pandas
中最重要的概念之一,它将在第三章中被详细地讨论。如果想要取出单个索引对应的值,可以通过[index_item]
可以取出。
2. DataFrame
DataFrame
在Series
的基础上增加了列索引columns
,一个数据框可以由二维的data
与行列索引来构造:
但一般而言,更多的时候会采用从列索引名到数据的映射来构造数据框,同时再加上行索引:
这里的data还可以传入ndarray等
由于这种映射关系,在DataFrame
中可以用[col_name]
与[col_list]
来取出相应的列与由多个列组成的表,结果分别为Series
和DataFrame
:
注意:DataFrame在取相应的列时,当传入的是[col_name_1,col_name_2](一个list)时,返回的是DataFrame,而只是传入一个col_name,则返回的是Series
与Series
类似,在数据框中同样可以取出相应的属性:
通过.T可以把DataFrame进行转置(Series也有.T属性,返回的就是自身):
三、常用基本函数
为了进行举例说明,在接下来的部分和其余章节都将会使用一份learn_pandas.csv
的虚拟数据集,它记录了四所学校学生的体测个人信息。
上述列名依次代表学校、年级、姓名、性别、身高、体重、是否为转系生、体测场次、测试时间、1000米成绩,本章只需使用其中的前七列,则用上面提到的方法。
1. 汇总函数
head, tail
函数分别表示返回表或者序列的前n
行和后n
行,其中n
默认为5:
info, describe
分别返回表的信息概况和表中数值列对应的主要统计量 :
df.info()参数:
verbose:是否打印完整的摘要。 True或False会覆盖显示。
buf:可写缓冲区,默认为sys.stdout
max_cols:类似控制是否打印完整的摘要,接收int
memory_usage:指定是否应显示DataFrame元素(包括索引)的总内存使用情况。屏幕上将不显示任何内容。True或False会覆盖显示。 “ deep”的值与True相同,具有自省性。内存使用情况以人类可读的单位(以2为基数的表示形式)显示。
null_counts:是否显示非空计数。如果为None,则仅显示框架是否小于max_info_rows和max_info_columns。如果为True,则始终显示计数。如果为False,则从不显示计数。
max_cols小于DataFrame的列时,类似于verbose=False。反之,类似于verbose=True
DataFrame.describe(percentiles=None, include=None,exclude=None,datetime_is_numeric=False)
其物理意义在于观察这一系列数据的范围。大小、波动趋势等等,便于判断后续对数据采取哪类模型更合适。
1.第一个percentiles,这个参数可以设定数值型特征的统计量,默认是[.25, .5, .75],也就是返回25%,50%,75%数据量时的数字,但是这个可以修改的.默认是有50%的
2.第二个参数:include,这个参数默认是只计算数值型特征的统计量(这就是为什么只有两列的统计量),当输入include=[‘O’],会计算离散型变量的统计特征。此外传参数是‘all’的时候会把数值型和离散型特征的统计都进行显示。
3.第三个参数的设计就更贴心了,第二个参数是你可以指定选那些,第三个参数就是你可以指定不选哪些,人性化设计。这个参数默认不丢弃任何列,相当于无影响。
【NOTE】更全面的数据汇总
info, describe
只能实现较少信息的展示,如果想要对一份数据集进行全面且有效的观察,特别是在列较多的情况下,推荐使用pandas-profiling包,它将在第十一章被再次提到。
2. 特征统计函数
在Series
和DataFrame
上定义了许多统计函数,最常见的是sum, mean, median, var, std, max, min
。例如,选出身高和体重列进行演示:
此外,需要介绍的是quantile, count, idxmax
这三个函数,它们分别返回的是分位数、非缺失值个数、最大值对应的索引:
上面这些所有的函数,由于操作后返回的是标量,所以又称为聚合函数,它们有一个公共参数axis
,默认为0代表逐列聚合,如果设置为1则表示逐行聚合:
3. 唯一值函数
对序列使用unique
和nunique
可以分别得到其唯一值组成的列表和唯一值的个数:
value_counts
可以得到唯一值和其对应出现的频数:
如果想要观察多个列组合的唯一值,可以使用drop_duplicates
。其中的关键参数是keep
,默认值first
表示每个组合保留第一次出现的所在行,last
表示保留最后一次出现的所在行,False
表示把所有重复组合所在的行剔除。
DataFrame.drop_duplicates(subset=None, keep='first', inplace=False, ignore_index=False)
df_demo.drop_duplicates(['Name', 'Gender'], keep=False) #结果是164X3
df_demo.drop_duplicates(['Name', 'Gender'], keep='last')#结果是181X3
从这里可以看出keep=False,把所有重复的都删掉了。
此外,inplace=Ture则在df上原地修改,不会返回一个df
此外,duplicated
和drop_duplicates
的功能类似,但前者返回了是否为唯一值的布尔列表,其keep
参数与后者一致。其返回的序列,把重复元素设为True
,否则为False
。
就是和drop_duplicated一样,只是duplicated返回的是布尔值。 drop_duplicates
等价于把duplicated
为True
的对应行剔除。
4. 替换函数
一般而言,替换操作是针对某一个列进行的,因此下面的例子都以Series
举例。pandas
中的替换函数可以归纳为三类:映射替换、逻辑替换、数值替换。其中映射替换包含replace
方法、第八章中的str.replace
方法以及第九章中的cat.codes
方法,此处介绍replace
的用法。
DataFrame.replace(to_replace=None,value=None,inplace=False,limit=None,regex=False,method='pad')
在replace
中,可以通过字典构造,或者传入两个列表来进行替换:
使用字典构造类似于to_replace和value参数都设置了。
另外,replace
还有一种特殊的方向替换,指定method
参数为ffill
则为用前面一个最近的未被替换的值进行替换,bfill
则使用后面最近的未被替换的值进行替换。从下面的例子可以看到,它们的结果是不同的:
记忆:ffill->forward往前,bfill->back往后
最后,limit参数是规定ffill与bfill来往前或往后寻找值填充的最大gap,下面就是只在后面一位填充
【WARNING】正则替换请使用str.replace
虽然对于replace
而言可以使用正则替换,但是当前版本下对于string
类型的正则替换还存在bug
,因此如有此需求,请选择str.replace
进行替换操作,具体的方式将在第八章中讲解。
逻辑替换包括了where
和mask
,这两个函数是完全对称的:where
函数在传入条件为False
的对应行进行替换,而mask
在传入条件为True
的对应行进行替换,当不指定替换值时,替换为缺失值。
需要注意的是,传入的条件只需是与被调用的Series
索引一致的布尔序列即可:
数值替换包含了round, abs, clip
方法,它们分别表示按照给定精度四舍五入、取绝对值和截断:
【练一练】
在 clip 中,超过边界的只能截断为边界值,如果要把超出边界的替换为自定义的值,应当如何做?
5. 排序函数
排序共有两种方式,其一为值排序,其二为索引排序,对应的函数是sort_values
和sort_index
。
为了演示排序函数,下面先利用set_index
方法把年级和姓名两列作为索引,多级索引的内容和索引设置的方法将在第三章进行详细讲解。
对身高进行排序,默认参数ascending=True
为升序:
在排序中,经常遇到多列排序的问题,比如在体重相同的情况下,对身高进行排序,并且保持身高降序排列,体重升序排列:
这里就是先对Weight排序,在对Height排序,其中前者是升序后者是降序。注意这里参数传入的是列表。
索引排序的用法和值排序完全一致,只不过元素的值在索引中,此时需要指定索引层的名字或者层号,用参数level
表示。另外,需要注意的是字符串的排列顺序由字母顺序决定。
假如传入的是层号,则从外到里是0,1,2…层
6. apply方法
apply
方法常用于DataFrame
的行迭代或者列迭代,它的axis
含义与第2小节中的统计聚合函数一致,apply
的参数往往是一个以序列为输入的函数。例如对于.mean()
,使用apply
可以如下地写出:
同样的,可以利用lambda
表达式使得书写简洁,这里的x
就指代被调用的df_demo
表中逐个输入的序列。
若指定axis=1
,那么每次传入函数的就是行元素组成的Series
,其结果与之前的逐行均值结果一致。
这里再举一个例子:mad
函数返回的是一个序列中偏离该序列均值的绝对值大小的均值,例如序列1,3,7,10中,均值为5.25,每一个元素偏离的绝对值为4.25,2.25,1.75,4.75,这个偏离序列的均值为3.25。现在利用apply
计算升高和体重的mad
指标:
【TIPS】就是对序列进行操作,函数里面传入的参数就是序列。
【WARNING】谨慎使用apply
得益于传入自定义函数的处理,apply
的自由度很高,但这是以性能为代价的。一般而言,使用pandas
的内置函数处理和apply
来处理同一个任务,其速度会相差较多,因此只有在确实存在自定义需求的情境下才考虑使用apply
。
四、窗口对象
pandas
中有3类窗口,分别是滑动窗口rolling
、扩张窗口expanding
以及指数加权窗口ewm
。需要说明的是,以日期偏置为窗口大小的滑动窗口将在第十章讨论,指数加权窗口见本章练习。
1. 滑窗对象
要使用滑窗函数,就必须先要对一个序列使用.rolling
得到滑窗对象,其最重要的参数为窗口大小window
。
得到了一个Rolling对象。
在得到了滑窗对象后,能够使用相应的聚合函数进行计算,需要注意的是窗口包含当前行所在的元素,例如在第四个位置进行均值运算时,应当计算(2+3+4)/3,而不是(1+2+3)/3:
对于滑动相关系数或滑动协方差的计算,可以如下写出:
roller.cov(s2)第三个值2.5 就是(1,2,3)与(1,2,6)的cov,往后依次滑动。
此外,还支持使用apply
传入自定义函数,其传入值是对应窗口的Series
,例如上述的均值函数可以等效表示:
shift, diff, pct_change
是一组类滑窗函数,它们的公共参数为periods=n
,默认为1,分别表示取向前第n
个元素的值、与向前第n
个元素做差(与Numpy
中不同,后者表示n
阶差分)、与向前第n
个元素相比计算增长率。这里的n
可以为负,表示反方向的类似操作。
这里的增加率计算:设当前索引为k, p c t = s [ k ] − s [ k − n ] s [ k − n ] pct=\frac{s[k]-s[k-n]}{s[k-n]} pct=s[k−n]s[k]−s[k−n]
将其视作类滑窗函数的原因是,它们的功能可以用窗口大小为n+1
的rolling
方法等价代替:
【练一练】
rolling
对象的默认窗口方向都是向前的,某些情况下用户需要向后的窗口,例如对1,2,3设定向后窗口为2的sum
操作,结果为3,5,NaN,此时应该如何实现向后的滑窗操作?
2. 扩张窗口
扩张窗口又称累计窗口,可以理解为一个动态长度的窗口,其窗口的大小就是从序列开始处到具体操作的对应位置,其使用的聚合函数会作用于这些逐步扩张的窗口上。具体地说,设序列为a1, a2, a3, a4,则其每个位置对应的窗口即[a1]、[a1, a2]、[a1, a2, a3]、[a1, a2, a3, a4]。
【练一练】
cummax, cumsum, cumprod
函数是典型的类扩张窗口函数,请使用expanding
对象依次实现它们。
五、练习
Ex1:口袋妖怪数据集
2.a&b
2.c
这是去重之后的答案,但是我看到的参考答案给的188。纠结了很久,看明白了答案的意思,按我的理解修改了一下参考答案。
分歧点在于,type1和type2技能能不能重复?可以重复就是18X19-143=199 不能重复就是18X19-18-143=181
3.a
参考答案的方法:
3.b
参考答案:
df['Type 1'].apply(lambda x:str.upper(x)).head()
主要区别在lambda里
3.c
EX2:指数加权窗口
1.自己的解法:
参考答案:
自己还是用的循环的笨办法···,这里可以用数组计算。
窗口权重为 ω i = ( 1 − α ) i \omega _{i}=(1-\alpha )^{i} ωi=(1−α)i , i ∈ { 0 , 1 , . . . , N − 1 } i\in \left \{ 0,1,...,N-1 \right \} i∈{0,1,...,N−1}
即 y t = ∑ 0 N − 1 ω i x t − i ∑ 0 N − 1 ω i y_{t}=\frac{\sum_{0}^{N-1}\omega _{i}x_{t-i}}{\sum_{0}^{N-1}\omega _{i}} yt=∑0N−1ωi∑0N−1ωixt−i= ( 1 − α ) 0 x t + ( 1 − α ) 1 x t − 1 + . . . + ( 1 − α ) N − 1 x t − ( N − 1 ) 1 + ( 1 − α ) 1 + . . . + ( 1 − α ) N − 1 \frac{(1-\alpha )^{0}x_{t}+(1-\alpha )^{1}x_{t-1}+...+(1-\alpha )^{N-1}x_{t-(N-1)}}{1+(1-\alpha )^{1}+...+(1-\alpha )^{N-1}} 1+(1−α)1+...+(1−α)N−1(1−α)0xt+(1−α)1xt−1+...+(1−α)N−1xt−(N−1)
不用对apply内的函数进行改动。