文本文件(txt文件)是一种由若干行字符构成的计算机文件,它是一种典型的顺序文件。使用read_table来读取文本文件:
pandas.read_table(filepath_or_buffer, sep=’\t’, header=’infer’, names=None, index_col=None, dtype=None, engine=None, nrows=None)
csv是一种逗号分隔的文件格式,因为其分隔符不一定是逗号,又被称为字符分隔文件,文件以纯文本形式存储表格数据(数字和文本)。使用read_csv函数来读取csv文件:
pandas.read_csv(filepath_or_buffer, sep=’,’, header=’infer’, names=None, index_col=None, dtype=None, engine=None, nrows=None)
read_table和read_csv常用参数及其说明。
①read_table和read_csv函数中的sep参数是指定文本的分隔符的,如果分隔符指定错误,在读取数据的时候,每一行数据将连成一片。
②header参数是用来指定列名的,如果是None则会添加一个默认的列名。
③encoding代表文件的编码格式,常用的编码有utf-8、utf-16、gbk、gb2312、gb18030等。如果编码指定错误数据将无法读取,IPython解释器会报解析错误。
import pandas as pd
data = pd.read_table(r'F:\Desktop\meal_order_info.csv', encoding='gbk', sep=',')
info = pd.read_csv(r'F:\Desktop\meal_order_info.csv', encoding='gbk')
注:pands.read_table中参数encoding默认的编码是“utf-8”,但meal_order_info.csv文件的编码格式是“gbk”,所以需要进行encoding参数的设置。一般情况下,编码格式不是“utf-8"的话,先试试是不是”gbk“的,不是再接着试utf-16、gb2312、gb18030这几个编码格式。
文本文件的存储和读取类似,结构化数据可以通过pandas中的to_csv函数实现以csv文件格式存储文件。
DataFrame.to_csv(path_or_buf=None, sep=’,’, na_rep=”, columns=None, header=True, index=True,index_label=None,mode=’w’,encoding=None)
info.to_csv(r'F:\Desktop\info.csv', encoding='gbk')
有时候保存出来的数据是乱码的情况,这时就需要设置下encoding这个参数。
pandas提供了read_excel函数来读取“xls”“xlsx”两种Excel文件。
pandas.read_excel(io, sheetname=0, header=0, index_col=None, names=None, dtype=None)
detail = pd.read_excel(r'F:\Desktop\meal_order_detail.xlsx')
将文件存储为Excel文件,可以使用to_excel方法。其语法格式如下。
DataFrame.to_excel(excel_writer=None, sheet_name=None’, na_rep=”, header=True, index=True, index_label=None, mode=’w’, encoding=None)
to_csv方法的常用参数基本一致,区别之处在于指定存储文件的文件路径参数名称为excel_writer,并且没有sep参数,增加了一个sheet_name参数用来指定存储的Excel sheet的名称,默认为sheet1。
detail.to_excel(r'F:\Desktop\detail.xlsx', sheet_name='A')
info.to_excel(r'F:\Desktop\detail.xlsx', sheet_name='B') #会覆盖原始数据
#将数据保存在一个Excel的多个字表中
with pd.ExcelWriter(r'F:\Desktop\detail.xlsx') as w:
detail.to_excel(w, sheet_name='A')
info.to_excel(w, sheet_name='B')
detail.columns #列名
detail.index #索引/行名
detail.shape #形状
detail.dtypes #类型
(1)对单列数据的访问
DataFrame的单列数据为一个Series。根据DataFrame的定义可以知晓DataFrame是一个带有标签的二维数组,每个标签相当每一列的列名。
有以下两种方式来实现对单列数据的访问:
①以字典访问某一个key的值的方式使用对应的列名,实现单列数据的访问。
②以属性的方式,实现单列数据的访问。(不建议使用,易引起混淆)
(2)访问某一列的某几行
访问DataFrame中某一列的某几行时,单独一列的DataFrame可以视为一个Series,而访问一个Series中的某几行基本和访问一个一维的ndarray相同。
比如:data['字段名'][:2]
(3)访问多列数据
访问DataFrame多列数据可以将多个列索引名称视为一个列表。
比如:data[['字段名1','字段名2','字段名3']]
(4)对某几行访问
如果只是需要访问DataFrame某几行数据的实现方式则和上述的访问多列多行相似,选择所有列,使用“:”代替即可。
比如:data[:][:2]
head和tail也可以得到多行数据,但是用这两种方法得到的数据都是从开始或者末尾获取的连续数据。默认参数为访问5行,只要在方法后方的“()”中填入访问行数即可实现目标行数的查看。
比如:data.head() # 访问data数据的前5行
data.tail() # 访问data数据的后5行
#--单列数据访问
##第一种方式:以字典形式访问
detail['order_id']
##第二种方式:以属性形式访问(不建议使用,易混淆)
detail.order_id
#--对某一列的某几行访问
detail['order_id'][:4]
#--对多列数据访问
detail[['detail_id', 'order_id', 'dishes_id']]
#--对某几行访问(所有列多行)
detail[:][:4]
detail.head(4) #得到的数据都是从开始获取的连续数据,默认访问前5行数据
detail.tail(3) #得到的数据都是从末尾获取的连续数据,默认访问的是最后5行数据
(5)loc方法是针对DataFrame行索引名称进行索引。利用loc方法,能够实现所有单层索引切片操作。在loc使用的时候内部传入的行索引名称如果为一个区间,则前后均为闭区间,loc内部还可以传入表达式,结果会返回满足表达式的所有值。
loc方法使用方法如下:
DataFrame.loc[行索引名称或条件, 列索引名称]
比如:data.loc[:2,['字段名1','字段名2','字段名3']] #loc方法:行标签索引
(6)iloc方法使用时内部传入的行索引位置或列索引位置为区间时,则为前闭后开区间。iloc方法的使用方法如下。
DataFrame.iloc[行索引位置, 列索引位置]
比如:data.iloc[:2,[0,3,5]] # iloc方法:行号索引
iloc和loc区别是iloc接收的必须是行索引和列索引的位置。
#--loc方法:DataFrame.loc[行索引名称或条件, 列索引名称]
detail.loc[:4, 'order_id'] #左闭右闭,此处提取出来的是前5行数据
detail.loc[:3, ['detail_id', 'order_id', 'dishes_id']]
detail.loc[detail['order_id'] == 417, :] #条件提取,此处提取order_id等于417的全部数据
#--iloc方法:DataFrame.iloc[行索引位置, 列索引位置]
detail.iloc[:5, 1]
更改DataFrame中的数据,原理是将这部分数据提取出来,重新赋值为新的数据。
需要注意的是,数据更改直接针对DataFrame原数据更改,操作无法撤销,如果做出更改,需要对更改条件做确认或对数据进行备份。
比如:data.loc[2,'字段名1'] = 3000
detail.loc[detail['order_id'] == 417, 'order_id'] = 41700
DataFrame添加一列的方法非常简单,只需要新建一个列索引,并对该索引下的数据进行赋值操作即可。
新增的一列值是相同的则直接赋值一个常量即可。
比如:data['字段名1'] = 列表
data['新字段名'] = 常数
#添加新列“price”
detail['price'] = detail['counts'] * detail['amounts']
detail['test'] = 5 #新增的一列值是相同的则直接赋值一个常量即可
删除某列或某行数据需要用到pandas提供的方法drop,drop方法的用法如下:
drop(labels, axis=0, level=None, inplace=False, errors='raise')
axis为0时表示删除行,axis为1时表示删除列。(x轴有变动过,axis设为1;y轴有变动的,axis设为0)
常用参数如下所示。
detail.drop('test', axis=1, inplace=True) #要对原始数据生效需要设置inplace=True
(1)数值型特征的描述性统计——NumPy中的描述性统计函数
数值型数据的描述性统计主要包括了计算数值型数据的完整情况、最小值、均值、中位数、最大值、四分位数、极差、标准差、方差、协方差和变异系数等。在NumPy库中一些常用的统计学函数如下表所示。
pandas库基于NumPy,自然也可以用这些函数对数据框进行描述性统计。
(2)数值型特征的描述性统计—— pandas描述性统计方法
pandas还提供了更加便利的方法来计算均值 ,如detail['amounts'].mean()。
pandas还提供了一个方法叫作describe,能够一次性得出数据框所有数值型特征的非空值数目、均值、四分位数、标准差。
detail['amounts'].mean() #均值
detail['amounts'].max() #最大值
detail['amounts'].median() #中位数
detail.describe() #一次性得出数据框所有数值型特征
描述类别型特征的分布状况,可以使用频数统计表。pandas库中实现频数统计的方法为value_counts。
pandas提供了categories类,可以使用astype方法将目标特征的数据类型转换为category类别。
describe方法除了支持传统数值型以外,还能够支持对category类型的数据进行描述性统计,四个统计量分别为列非空元素的数目,类别的数目,数目最多的类别,数目最多类别的数目。
detail['dishes_name'].value_counts() #频数统计
#转变为category类型的数据,之后即可使用describe()进行描述性统计
detail['dishes_name'] = detail['dishes_name'].astype('category')
detail['dishes_name'].describe()
数据分析的分析对象不仅仅限于数值型和类别型两种,常用的数据类型还包括了时间类型。通过时间类型数据能够获取到对应的年月日和星期等信息。但时间类型数据在读入Python后常常以字符串形式出现,无法实现大部分与时间相关的分析。pandas库继承了numpy库的datetime64以及timedelta64模块,能够快速地实现时间字符串的转换、信息提取和时间运算。
在多数情况下,对时间类型数据进行分析的前提就是将原本为字符串的时间转换为标准时间类型。pandas继承了NumPy库和datetime库的时间相关模块,提供了6种时间相关的类。
Timestamp:时间戳,只能表示1677-2262年的时间。如 pd.Timestamp('2016-07-10 10:10')。
Period:固定周期,如 pd.Period('2016-01')
Timedelta:时间间隔,如 pd.Timedelta('1 day')
Timestamp作为时间类中最基础的,也是最为常用的。在多数情况下,时间相关的字符串都会转换成为Timestamp。pandas提供了to_datetime函数,能够实现这一目标。
值得注意的是,Timestamp类型时间是有限制的,只能表示1677-2262年的时间。
info['use_start_time'] = pd.to_datetime(info['use_start_time']) #转换为标准时间格式数据
info.dtypes
pd.Timestamp.min #Timestamp('1677-09-21 00:12:43.145225')
pd.Timestamp.max #Timestamp('2262-04-11 23:47:16.854775807')
除了将数据字原始DataFrame中直接转换为Timestamp格式外,还可以将数据单独提取出来将其转换为DatetimeIndex或者PeriodIndex。
转换为PeriodIndex的时候需要注意,需要通过freq参数指定时间间隔,常用的时间间隔有Y为年,M为月,D为日,H为小时,T为分钟,S为秒。两个函数可以用来转换数据还可以用来创建时间序列数据,其参数非常类似。
DatetimeIndex和PeriodIndex两者区别在日常使用的过程中相对较小,其中DatetimeIndex是用来指代一系列时间点的一种数据结构,而PeriodIndex则是用来指代一系列时间段的数据结构。
#DatetimeIndex函数
pd.DatetimeIndex(info['lock_time']) #DatetimeIndex是用来指代一系列时间点的一种数据结构
#PeriodIndex函数
pd.PeriodIndex(info['use_start_time'], freq='D')#PeriodIndex是用来指代一系列时间段的数据结构
Timestamp类常用属性
在多数涉及时间相关的数据处理,统计分析的过程中,需要提取时间中的年份,月份等数据。使用对应的Timestamp类属性就能够实现这一目的。
结合Python列表推导式,可以实现对DataFrame某一列时间信息数据的提取。
a = info['use_start_time'][0]
a.year #年份
a.month #月份
a.dayofyear #一年中的第几天
Timedelta类
Timedelta是时间相关的类中的一个异类,不仅能够使用正数,还能够使用负数表示单位时间,例如1秒,2分钟,3小时等。使用Timedelta类,配合常规的时间相关类能够轻松实现时间的算术运算。目前Timedelta函数中时间周期中没有年和月。所有周期名称,对应单位及其说明如下表所示。
①使用Timedelta ,可以很轻松地实现在某个时间上加减一段时间 。
②除了使用Timedelta实现时间的平移外,还能够直接对两个时间序列进行相减,从而得出一个Timedelta。
info['use_start_time'] + pd.Timedelta(days=1, seconds=10) #pd.Timedelta(days=1, seconds=10)构造的是一个“1天10秒”的Timedelta
# 数据,此处的操作是可实现对“use_start_time”一列的时间数据加上一天10秒。
pd.to_datetime('2020-09-24') - info['use_start_time'] #“use_start_time”一列时间数据距离“2020-09-24”的时间差
该方法提供的是分组聚合步骤中的拆分功能,能根据索引或字段对数据进行分组。其常用参数与使用格式如下。
DataFrame.groupby(by=None, axis=0, level=None, as_index=True, sort=True, group_keys=True, squeeze=False, **kwargs)
by参数的特别说明:
①如果传入的是一个函数则对索引进行计算并分组。
②如果传入的是一个字典或者Series则字典或者Series的值用来做分组依据。
③如果传入一个NumPy数组则数据的元素作为分组依据。
④如果传入的是字符串或者字符串列表则使用这些字符串所代表的字段作为分组依据。
用groupby方法分组后的结果并不能直接查看,而是被存在内存中,输出的是内存地址。实际上分组后的数据对象GroupBy类似Series与DataFrame,是pandas提供的一种对象。GroupBy对象常用的描述性统计方法如下。
detail.groupby(by='order_id') #用groupby方法分组后的结果并不能直接查看,而是被存在内存中,输出的是内存地址
detail.groupby(by='order_id').count()
agg,aggregate方法都支持对每个分组应用某函数,包括Python内置函数或自定义函数。同时这两个方法能够也能够直接对DataFrame进行函数应用操作。
在正常使用过程中,agg函数和aggregate函数对DataFrame对象操作时功能几乎完全相同,因此只需要掌握其中一个函数即可。它们的参数说明如下表。
DataFrame.agg(func, axis=0, *args, **kwargs)
DataFrame.aggregate(func, axis=0, *args, **kwargs)
①可以使用agg方法一次求出当前数据中所有菜品销量和售价的总和与均值,如
detail[['counts','amounts']].agg([np.sum,np.mean])
②对于某个字段希望只做求均值操作,而对另一个字段则希望只做求和操作,可以使用字典的方式,将两个字段名分别作为key,然后将NumPy库的求和与求均值的函数分别作为value,如
detail.agg({'counts':np.sum,'amounts':np.mean})
③在某些时候还希望求出某个字段的多个统计量,某些字段则只需要求一个统计量,此时只需要将字典对应key的value变为列表,列表元素为多个目标的统计量即可,如
detail.agg({'counts':np.sum,'amounts':[np.mean,np.sum]})
import numpy as np
detail[['counts','amounts']].agg([np.sum,np.mean]) #一次求出当前数据中所有菜品销量和售价的总和与均值
detail.agg({'counts':np.mean, 'amounts':np.sum}) #对所有菜品销量求均值,售价求总和
detail.agg({'counts':np.mean, 'amounts':[np.sum, np.mean]}) #对所有菜品销量求均值,售价求总和和均值
#分组聚合
detail.groupby(by='order_id').agg({'counts':np.sum}) #按“order_id”进行分组,再对菜品销量“counts”求和
detail.groupby(by=['order_id', 'dishes_id']).agg({'counts':np.sum}) #先按“order_id”分组,再按“dishes_id”分组,再对菜品销量“counts”求和
apply方法类似agg方法能够将函数应用于每一列。不同之处在于apply方法相比agg方法传入的函数只能够作用于整个DataFrame或者Series,而无法像agg一样能够对不同字段,应用不同函数获取不同结果。
使用apply方法对GroupBy对象进行聚合操作其方法和agg方法也相同,只是使用agg方法能够实现对不同的字段进行应用不同的函数,而apply则不行。
DataFrame.apply(func, axis=0, broadcast=False, raw=False, reduce=None, args=(), **kwds)
detail.groupby(by='order_id').apply(np.sum) #单一操作,即此处只能对按“order_id”分组之后的整个数据中的每列数据求和
利用pivot_table函数可以实现透视表,pivot_table()函数的常用参数及其使用格式如下。
pandas.pivot_table(data, values=None, index=None, columns=None, aggfunc='mean', fill_value=None, margins=False, dropna=True, margins_name='All')
①在不特殊指定聚合函数aggfunc时,会默认使用numpy.mean进行聚合运算,numpy.mean会自动过滤掉非数值类型数据。可以通过指定aggfunc参数修改聚合函数。
和groupby方法分组的时候相同,pivot_table函数在创建透视表的时候分组键index可以有多个。
②通过设置columns参数可以指定列分组。
③当全部数据列数很多时,若只想要显示某列,可以通过指定values参数来实现。
④当某些数据不存在时,会自动填充NaN,因此可以指定fill_value参数,表示当存在缺失值时,以指定数值进行填充。
⑤可以更改margins参数,查看汇总数据。
pd.pivot_table(detail[['order_id', 'counts']], index='order_id', aggfunc=np.sum)
pd.pivot_table(detail[['order_id', 'counts', 'dishes_id']], index=['order_id', 'dishes_id'], aggfunc=np.sum)
pd.pivot_table(detail[['order_id', 'counts', 'dishes_id']], index='order_id', columns='dishes_id', aggfunc=np.sum)
交叉表是一种特殊的透视表,主要用于计算分组频率。利用pandas提供的crosstab函数可以制作交叉表,crosstab函数的常用参数和使用格式如下。
由于交叉表是透视表的一种,其参数基本保持一致,不同之处在于crosstab函数中的index,columns,values填入的都是对应的从Dataframe中取出的某一列。
pandas.crosstab(index, columns, values=None, rownames=None, colnames=None, aggfunc=None, margins=False, dropna=True, normalize=False)
crosstab的常用参数及其说明
pd.crosstab(index=detail['order_id'], columns=detail['dishes_id'], values=detail['counts'], aggfunc=np.sum)