Python基础数据处理库-Pandas

最近更新:2018-01-11


pandas是Python数据工作的基础库之一,它和numpy、scipy共成为Python数据处理的三剑客。pandas在数据录入、查看、预处理、统计分析、时间序列等方面具有非常强大的能力。尤其它里面的数据框跟R中的数据框类似,其具有的交互性以及对非结构化、非数值型数据的处理能力让Python的基础数据处理事半功倍。

1、Pandas读取数据文件

相对于Python默认函数以及Numpy读取文件的方法,Pandas读取数据的方法更加丰富。Pandas读取文本文件数据的常用方法如下表:

方法 描述 返回数据
read_csv 读取csv文件 DataFrame 或TextParser
read_fwf 读取表格或固定宽度格式的文本行到数据框 DataFrame 或TextParser
read_table 读取通用分隔符分隔的数据文件到数据框 DataFrame 或TextParser
1.1 使用read_cvs方法读取数据

通过read_csv方法可以读取csv格式的数据文件。

  1. read_csv(filepath_or_buffer, sep=',', delimiter=None, header='infer', names=None, index_col=None, usecols=None, **kwds)

参数(read_csv的参数众多,以下介绍最常用的几个参数):

  • filepath_or_buffer:字符串,要读取的文件对象,必填。
  • sep:字符串,分隔符号,选填,默认值为英文逗号','。
  • names:类数组,列名,选填,默认值为空。
  • skiprows:类字典或整数型,要跳过的行或行数,选填,默认为空。
  • nrows:整数型,要读取的前记录总数,选填,默认为空,常用来在大型数据集下做初步探索之用。
  • thousands:字符串,千位符符号,选填,默认为空。
  • decimal:字符串,小数点符号,选填,默认为点(.),在特定情况下应用,例如欧洲的千位符和小数点跟中国地区相反,欧洲的321,1对应中国的4,321.1。

1.2 使用read_fwf方法读取数据

通过read_fwf方法可以读取表格或固定宽度格式的文本行到数据框。

  1. read_fwf(filepath_or_buffer, colspecs='infer', widths=None, **kwds)

参数

read_fwf跟read_csv一样都具有非常多的参数(只是在语法中前者通过**kwds省略了,查询完整语法请使用help(pd.read_fwf)),并且大多数参数的用法相同。除了read_csv中的常用参数外,以下介绍几个read_fwf特有且常用的参数。

 widths:由整数组成的列表,选填,如果间隔是连续的,可以使用的字段宽度列表而不是“colspecs”。

1.3 使用read_table方法读取数据

通过read_table方法可以读取通用分隔符分隔的数据文件到数据框。

  1. read_table(filepath_or_buffer, sep='\t', delimiter=None, header='infer', names=None, index_col=None, usecols=None, **kwds)

对于read_table而言,参数与read_csv完全相同。其实read_csv本来就是read_table中分隔符是逗号的一个特例,表现在语法中是read_csv的sep=','(默认)。因此,具体参数请查阅read_csv的参数部分。

Pandas其他数据读取方法

方法 描述 返回数据
read_clipboard 读取剪贴板数据,然后将对象传递给read_table方法 DataFrame 或TextParser
read_excel 从excel中读取数据 DataFrame或DataFrame构成的字典
read_gbq 从Google Bigquery中读取数据 DataFrame
read_hdf 读取文件中的Pandas对象 所选择的数据对象
read_html 读取HTML中的表格 由DataFrame构成的字典
read_json 将JSON对象转换为Pandas对象 Series或 DataFrame,具体取决于参数typ设置
read_msgpack 从指定文件中加载msgpack Pandas对象 文件中的对象类型
read_pickle 从指定文件中加载pickled Pandas或其他pickled对象 文件中的对象类型
read_sas 读取XPORT或SAS7BDAT格式的SAS(统计分析软件)文件 DataFrame或SAS7BDATReader或XportReader,具体取决于设置
read_sql 读取SQL请求或数据库中的表 DataFrame
read_sql_query 从SQL请求读取数据 DataFrame
read_sql_table 读取SQL数据库中的表 DataFrame
read_stata 读取Stata(统计分析软件)文件 DataFrame或StataReader

如何选择最佳读取数据的方法

关于“最佳”方法其实没有固定定义,因此所谓的最佳方法往往跟以下具体因素有关:

  • 数据源情况:数据源中不同的字段类型首先会制约读取方法的选择,文本、数值、二进制数据都有各自的适应方法约束。
  • 数据处理目标:读取数据往往是第一步,后续会涉及到数据探索、预处理、统计分析等复杂过程,这些复杂过程需要用到哪些方法都会一定程度上受数据源的读取影响,影响最多的点包括格式转换、类型转换、异常值处理、分类汇总等。
  • 模型数据要求:不同的模型对于数据格式的要求是不同的,应用到实际中不同的工具对于数据的表示方法也有所差异。
  • “手感”最好的方法:很多时候,最佳方法往往是对哪个或哪些方法最熟悉,这些所谓的“手感”最好的方法便是最佳方法。

当然,即使使用了不是“最佳”的数据读取方法也不必过于担心,因为Python强大的功能提供了众多可以相互进行转换的方法,从Python存储数据的基本对象类型来看,无非是字符串、列表、字典、元组、数组、矩阵等(当然不同的库对于这些对象的定义名称可能有所不同,但基本含义相同),不同对象的类型转换都非常容易。但本着少走弯路的原则,在这里笔者还是针对不同的场景提供了较为适合的数据读取方法:

  • 对于纯文本格式或非格式化、非结构化的数据,通常用于自然语言处理、非结构化文本解析、应用正则表达式等后续应用场景下,Python默认的三种方法更为适合。
  • 对于结构化的、纯数值型的数据,并且主要用于矩阵计算、数据建模的,使用Numpy的loadtxt更为方便,例如本书中使用的sklearn本身就依赖于Numpy。
  • 对于二进制的数据处理,使用Numpy的load和fromfile更为合适。
  • 对于结构化的、探索性的数据统计和分析的场景,使用Pandas进行读取效果更佳,因为其提供了类似于R的数据框,可以实现“仿SQL”式的操作方式,对数据进行任意的翻转、切片(块等)、关联等都非常方便。
  • 对于结构化的、数值型和文本型组合的数据统计分析场景,使用Pandas更为合适,因为每个数据框中几乎可以装载并处理任意格式的数据。

2、Pandas缺失值处理

先生成带有缺失值的模拟数据:

  1. import pandas as pd  # 导入pandas库
  2. import numpy as np  # 导入numpy库
  3. df = pd.DataFrame(np.random.randn(6, 4), columns=['col1', 'col2', 'col3', 'col4'])  # 生成一份数据
  4. df.iloc[1:2, 1] = np.nan  # 增加缺失值
  5. df.iloc[4, 3] = np.nan  # 增加缺失值
  6. print (df)

示例数据结果中如下 :

  1.        col1      col2      col3      col4
  2. 0 -0.424315  1.024795  0.665549  0.721605
  3. 1 -0.502295       NaN -0.147179 -0.150555
  4. 2  0.009386  0.490898 -0.128985  0.013604
  5. 3 -0.395965  0.792293 -1.416035 -0.261842
  6. 4 -0.218898  0.273137 -0.547399       NaN
  7. 5 -0.029000 -1.773710  1.190229 -1.451912

 

2.1 Pandas查看缺失值

2.1.1 查看哪些值缺失 

  1. # 查看哪些值缺失
  2. nan_all = df.isnull()  # 获得所有数据框中的NA值
  3. print (nan_all)  # 打印输出

详细缺失值结果如下:

  1.     col1   col2   col3   col4
  2. 0  False  False  False  False
  3. 1  False   True  False  False
  4. 2  False  False  False  False
  5. 3  False  False  False  False
  6. 4  False  False  False   True
  7. 5  False  False  False  False

 

2.1.2 查看哪些列具有缺失值

  1. # 查看哪些列缺失
  2. nan_col1 = df.isnull().any()  # 获得含有NA的列
  3. nan_col2 = df.isnull().all()  # 获得全部为NA的列
  4. print (nan_col1)  # 打印输出
  5. print (nan_col2)  # 打印输出

上面的方法中,第一个方法是查看所有列中,只要有一个值为NA的;在any方法中,还可以加入对行或列的判断,例如:

  1. any(axis=0):用于判断以列为单位的缺失值,如果一列中存在任何一个缺失值则为True
  2. any(axis=1):用于判断以行为单位的缺失值,如果一行中存在任何一个缺失值则为True

第二个方法是查看所有列都为NA的,结果如下:

  1. col1    False
  2. col2     True
  3. col3    False
  4. col4     True
  5. dtype: bool
  6. col1    False
  7. col2    False
  8. col3    False
  9. col4    False
  10. dtype: bool
2.2 Pandas丢弃缺失值
  1. df2 = df.dropna()  # 直接丢弃含有NA的行记录
  2. print (df2)  # 打印输出

输出结果如下:

  1.        col1      col2      col3      col4
  2. 0 -0.424315  1.024795  0.665549  0.721605
  3. 2  0.009386  0.490898 -0.128985  0.013604
  4. 3 -0.395965  0.792293 -1.416035 -0.261842
  5. 5 -0.029000 -1.773710  1.190229 -1.451912

所有带有缺失值的行记录被删除

pandas支持按行或列做删除,例如删除带有缺失值的列,并且以指定所有数据都是NA还是只有一个值为NA。指定按行/列删除用axis参数,指定NA是含有任意一个还是全部都是NA使用how参数。具体用法如下:

df.dropna(axis=1, how='all')

其中:

axis取值为0 ('index')或1 ('columns')

how取值为'any'或'all'

2.2 Pandas填充缺失值

pandas填充缺失值有很多种方法:

  1. # 使用pandas将缺失值替换为特定值
  2. nan_result_pd1 = df.fillna(method='backfill')  # 用后面的值替换缺失值
  3. nan_result_pd2 = df.fillna(method='bfill', limit=1)  # 用后面的值替代缺失值,限制每列只能替代一个缺失值
  4. nan_result_pd3 = df.fillna(method='pad')  # 用前面的值替换缺失值
  5. nan_result_pd4 = df.fillna(0)  # 用0替换缺失值
  6. nan_result_pd5 = df.fillna({'col2': 1.1, 'col4': 1.2})  # 用不同值替换不同列的缺失值
  7. nan_result_pd6 = df.fillna(df.mean()['col2':'col4'])  # 用平均数代替,选择各自列的均值替换缺失值
  8. # 打印输出
  9. print (nan_result_pd1)  # 打印输出
  10. print (nan_result_pd2)  # 打印输出
  11. print (nan_result_pd3)  # 打印输出
  12. print (nan_result_pd4)  # 打印输出
  13. print (nan_result_pd5)  # 打印输出
  14. print (nan_result_pd6)  # 打印输出

填充后的结果如下:

  1.        col1      col2      col3      col4
  2. 0 -0.424315  1.024795  0.665549  0.721605
  3. 1 -0.502295  0.490898 -0.147179 -0.150555
  4. 2  0.009386  0.490898 -0.128985  0.013604
  5. 3 -0.395965  0.792293 -1.416035 -0.261842
  6. 4 -0.218898  0.273137 -0.547399 -1.451912
  7. 5 -0.029000 -1.773710  1.190229 -1.451912
  8.        col1      col2      col3      col4
  9. 0 -0.424315  1.024795  0.665549  0.721605
  10. 1 -0.502295  0.490898 -0.147179 -0.150555
  11. 2  0.009386  0.490898 -0.128985  0.013604
  12. 3 -0.395965  0.792293 -1.416035 -0.261842
  13. 4 -0.218898  0.273137 -0.547399 -1.451912
  14. 5 -0.029000 -1.773710  1.190229 -1.451912
  15.        col1      col2      col3      col4
  16. 0 -0.424315  1.024795  0.665549  0.721605
  17. 1 -0.502295  1.024795 -0.147179 -0.150555
  18. 2  0.009386  0.490898 -0.128985  0.013604
  19. 3 -0.395965  0.792293 -1.416035 -0.261842
  20. 4 -0.218898  0.273137 -0.547399 -0.261842
  21. 5 -0.029000 -1.773710  1.190229 -1.451912
  22.        col1      col2      col3      col4
  23. 0 -0.424315  1.024795  0.665549  0.721605
  24. 1 -0.502295  0.000000 -0.147179 -0.150555
  25. 2  0.009386  0.490898 -0.128985  0.013604
  26. 3 -0.395965  0.792293 -1.416035 -0.261842
  27. 4 -0.218898  0.273137 -0.547399  0.000000
  28. 5 -0.029000 -1.773710  1.190229 -1.451912
  29.        col1      col2      col3      col4
  30. 0 -0.424315  1.024795  0.665549  0.721605
  31. 1 -0.502295  1.100000 -0.147179 -0.150555
  32. 2  0.009386  0.490898 -0.128985  0.013604
  33. 3 -0.395965  0.792293 -1.416035 -0.261842
  34. 4 -0.218898  0.273137 -0.547399  1.200000
  35. 5 -0.029000 -1.773710  1.190229 -1.451912
  36.        col1      col2      col3      col4
  37. 0 -0.424315  1.024795  0.665549  0.721605
  38. 1 -0.502295  0.161482 -0.147179 -0.150555
  39. 2  0.009386  0.490898 -0.128985  0.013604
  40. 3 -0.395965  0.792293 -1.416035 -0.261842
  41. 4 -0.218898  0.273137 -0.547399 -0.225820
  42. 5 -0.029000 -1.773710  1.190229 -1.451912

 

3、Pandas数据切片/切块/筛选/过滤

3.1 通过列名选择特定列
  1. # 生成数据   
  2. df = pd.DataFrame({'id': [3566841, 6541227, 3512441],
  3.                    'sex': ['male', 'Female', 'Female'],
  4.                    'level': ['hight', 'low', 'middle']})
  5. # 建立针对特定列名的列表并过滤数据   
  6. col_name = ['id','sex']
  7. col_data = df[col_name]  # 获得每列数据   
  8. print(col_data)

过滤后的数据如下:

  1.         id     sex
  2. 0  3566841    male
  3. 1  6541227  Female
  4. 2  3512441  Female

在针对列名的过滤中,如果过滤单一列,COL_NAME可以是字符串,也可以是由一个字符串组成的列表。但前者过滤后是一个series,后者过滤后是一个DataFrame,二者在后续的操作上会有差异。

3.2 通过列名属性的选择方法选择特定列数据

Pandas提供了直接通过属性选择列值的方法,格式为:

  1. # 使用列名做为属性选择特定列数据
  2. df.sex

上面代码返回如下结果:

  1. 0      male
  2. 1    Female
  3. 2    Female
  4. Name: sex, dtype: object

注意:这种操作方法需要对DataFrame已经做过列命名,如果创建数据框时没有定义列名(例如使用默认的index),那么这种操作方法是不可行的。

3.3 通过loc方法选择列数据或切块数据

Pandas提供了loc方法选择特定数据,格式为:

  1. # df.loc[index1:index2,[col1,col2]]
  2. df.loc[0:1,['id','sex']] # 选择前2行以及id和sex列数据

上面代码返回如下结果:

  1.         id     sex
  2. 0  3566841    male
  3. 1  6541227  Female

其中:index1和index2为行索引值(注意从0开始);col1、col2等是列名,如果要选择所有列,按脉直接使用:即可,例如df.loc[0:1,:]

3.4 通过iloc方法选择列数据或切块数据

Pandas提供了iloc方法可以灵活的选择特定数据,它的用法跟loc基本一致,但二者的区别在于loc方法中,可以通过列名选择数据,而iloc只能通过列索引值选择数据,格式为:

  1. # df.loc[index1:index2,col_index1,col_index2]]   
  2. df.loc[0:1,0:1] # 选择前2行以及id和sex列数据 

上面代码返回如下结果:

  1. id
  2. 41

其中:index1和index2为行索引值(注意从0开始);col_index1、col_index2是列索引名

3.5 通过ix方法选择数据

Pandas提供了ix方法,这个方法可以看成是iloc和loc的结合体,由于它结合了二者的用法,在做列选取时即可使用索引值,也可以使用列名标签。因此是实用性最广的灵活选择方法。格式为:

  1. df.ix[0:1,0:1] # 索引选择
  2. df.ix[0:1,['id']]  # 列名选择

以上两种写法是等效的,上面代码返回如下结果:

  1.         id
  2. 0  3566841
  3. 1  6541227

总结

  • 在官方的建议中,不建议使用ix方法。
  • 对于列名类的选择,建议使用的是loc方法;
  • 对于索引类的选择,建议使用的是iloc方法;
  • 对于单纯列(单列或多列)的选择,使用属性的方法选择单列最简单,但列名方法却更实用,因此它可以灵活定义可变列。

 

4、Pandas字符串与日期转换和解析

pandas中的datetime库是处理与日期相关主要功能库,其中的strftime用来将字符串解析为日期格式,与strptime方法对应的是strftime方法,用来将日期转换为字符串。关于日期的格式,pandas采用的是python默认的日期格式,完整见https://docs.python.org/2/library/datetime.html#strftime-and-strptime-behavior。以下是常用的日期格式字符串如下:

表4-6 日期字符串

字符串 日期格式 示例
%y 2个数字表示的年份 99
%Y 4个数字表示的年份 1999
%b 月份的简写 Jan
%B 月份的全写 January
%m 月份([01,12]) 10
%a 星期的简写 Mon
%A 星期的全写 Monday
%w 周几([0, 6])0表示周一,以此类推 5
%U 当年的第几周,星期日作为周的第一天([00,53]) 30
%W 当年的第几周,星期一作为周的第一天([00,53]) 30
%d 日是这个月的第几天,范围[01,31] 12
%p AM或PM AM
%H 小时(24小时制,[00, 23]) 20
%I 小时(12小时制,[01, 12]) 12
%j 日在年中的天数 [001,366] 360
%M 分钟([00,59]) 59
%S 秒([00,59]) 59
%f 微秒([000000,999999]) 0

将字符串 转化为日期

  1. # 定义一个时间字符串
  2. date_str = '01-12-2017'
  3. date_formate = pd.datetime.strptime(date_str, '%m-%d-%Y')
  4. print(date_formate)

上述代码执行后,格式化的日期为:

  1. 2017-01-12 00:00:00

将日期转化为字符串

  1. date_convert = pd.datetime.strftime(date_formate, '%Y-%m-%d')
  2. print(date_convert)

转换后的结果如下:

  1. 2017-01-12

实际上,由于该操作是针对单个字符串对象进行的,我们更多的会使用“批量”的方式做字符串格式解析,例如:

  1. date_parse = lambda dates: pd.datetime.strptime(dates, '%m-%d-%Y')  # 创建解析列的功能对象
  2. df = pd.read_table('time_series.txt', delimiter='\t', index_col='date', date_parser=date_parse)  # 读取数据

上述代码中,在使用pandas的read_table读取数据文件时,通过index_col指定date列为索引列,代替默认的数值索引;通过date_parser参数指定刚才定义的日期解析功能项。

5、Pandas基本数据查看

先创建一个demo数据框

  1. cols = ['col_'+str(i) for i in range(3)]   # 自定义列名
  2. df = pd.DataFrame(np.arange(12).reshape(4,3),columns = cols) #创建数据框
  3. df.iloc[1,1] = 'a' # 为了方便,我们将其中加入字符串数据
  4. print(df) # 输出查看

示例数据如下:

  1.    col_0 col_1  col_2
  2. 0      0     1      2
  3. 1      3     a      5
  4. 2      6     7      8
  5. 3      9    10     11
5.1 描述性统计

使用describe方法查看,描述性统计结果:

  1. df.describe()

结果如下:

  1.           col_0      col_2
  2. count  4.000000   4.000000
  3. mean   4.500000   6.500000
  4. std    3.872983   3.872983
  5. min    0.000000   2.000000
  6. 25%    2.250000   4.250000
  7. 50%    4.500000   6.500000
  8. 75%    6.750000   8.750000
  9. max    9.000000  11.000000

结果发现,统计结果中,没有col_1的结果,原因是其中有一个字符串a。我们通过设置参数来查看所有列的情况:

  1. df.describe(include='all')

这次返回结果如下:

  1.            col_0  col_1      col_2
  2. count   4.000000    4.0   4.000000
  3. unique       NaN    4.0        NaN
  4. top          NaN    7.0        NaN
  5. freq         NaN    1.0        NaN
  6. mean    4.500000    NaN   6.500000
  7. std     3.872983    NaN   3.872983
  8. min     0.000000    NaN   2.000000
  9. 25%     2.250000    NaN   4.250000
  10. 50%     4.500000    NaN   6.500000
  11. 75%     6.750000    NaN   8.750000
  12. max     9.000000    NaN  11.000000

这次我们看到了出现了一些新的统计指标,包括unique、top、freq,这些是针对字符串列出现的新指标。

5.2 查看各列类型

在上面的示例中,我们已经发现,col_1无法做普通的描述性统计,这个问题其实在最开始可以通过查看dtype来发现。
查看所有列的属性

  1. df.dtypes

返回结果如下:

  1. col_0     int32
  2. col_1    object
  3. col_2     int32
  4. dtype: object

我们看到第2列是object属性,也就是字符串列。

5.3查看前n条数据

查看基本数据状态是非常常用的操作,要查看TOP N条数据,使用head方法,具体为:

  1. df.head(n)

其中n是要查看的数据记录的数量,默认n为5。如果设置n为2,上述结果如下:

  1. #df.head(2)   
  2.    col_0 col_1  col_2
  3. 0      0     1      2
  4. 1      3     a      5
5.4查看后n条数据

查看后n条数据跟前n条数据的用法类似,其方法是tail,具体为:

  1. df.tail(n)

n默认也是5,如果设置2,那么后2条数据为:

  1. #df.tail(2)
  2.    col_0 col_1  col_2
  3. 2      6     7      8
  4. 3      9    10     11
5.5查看所有列名

通过columns查看所有列名

  1. df.columns   
  2. Index([u'col_0', u'col_1', u'col_2'], dtype='object')  
5.6查看所有index

通过index查看所有index索引信息

  1. df.index  
  2. RangeIndex(start=0, stop=4, step=1)  

6、数据基本处理

先生成一个demo数据:

  1. # 生成数据   
  2. df = pd.DataFrame({'num': [12, 8, 2,1],
  3.                    'sex': ['male', 'Female', 'Female','Female'],
  4.                    'level': ['hight', 'low', 'middle','middle']})
6.1 分类汇总

分类汇总的基本格式为:

  1. df.groupby(col_names1)[col_name2].function
    其中:

  • col_names1指的是分类的目标字段,例如对age做分类,那么这里需要写['age'];如果对多个字段做汇总,例如age和sex,那么需要分别填写['age','sex']
  • col_name2指的是要计算的字段,例如对上述的age做汇总, 是基于哪个字段做计算,可能是收入、订单量或业务量
  • function指的是汇总的方式,一般常用的是mean()、sum()、count()等

示例:
对sex列做统计,统计指标为num列,汇总方式为求和

  1. df.groupby(['sex'])['num'].sum() # 查看
  2. # 输出
  3. sex
  4. Female    11
  5. male      12
  6. Name: num, dtype: int64

对sex列做统计,统计指标为level列,汇总方式为计数

  1. df.groupby(['sex'])['level'].count() # 查看
  2. # 输出
  3. sex
  4. Female    3
  5. male      1
  6. Name: level, dtype: int64

对sex和level分别做统计,统计指标为num,汇总方式为均值

  1. df.groupby(['sex','level'])['num'].mean() # 查看
  2. # 输出
  3. sex     level
  4. Female  low        8.0
  5.         middle     1.5
  6. male    hight     12.0
  7. Name: num, dtype: float64
6.2 排序

pandas的排序使用的是sort_values方法,具体应用为:

  1. df.sort_values(by='num', ascending=True)

其中,by后是要排序的列,ascending用来指定排序是正序(True)还是倒序(False)。上面方法排序后的输出为:

  1.     level  num     sex
  2. 3  middle    1  Female
  3. 2  middle    2  Female
  4. 1     low    8  Female
  5. 0   hight   12    male
6.3 查看替换

pandas中的replace方法是一个非常强大的字符串替换功能,它可以实现字符串、字典、列表、数字甚至正则表达式级别的转换。
语法:

  1. replace(self, to_replace=None, value=None, inplace=False, limit=None, regex=False, method='pad', axis=None)

其中关键参数如下:
to_replace:要替换的对象。它可以是str、regex、list、dict、Series、numeric、None。

  • str是完全替换和匹配的字符串。
  • regex是匹配符合正则表达式模式的对象。
  • list可以是字符串列表、正则表达式列表或数值列表。如果to_replace(原始对象)和value(替换后的对象)都是列表格式,那么列表长度必须一致;如果regex参数设置为True,那么两个列表中的所有字符串将被应用正则表达式。
  • dict:可以使用嵌套字典直接做匹配模式定义,例如嵌套字典({'a':{'b':nan}})将在列'a'中查找值'b',并将其替换为nan,嵌套中也可以使用正则表达式。

value:替换后的值。它也可以是scalar、dict、list、str、regex,其中dict对象可以将每个列指定为不同的替换值,例如{'a':1,'b':2}可以将列a替换为1,列b替换为2。
示例

  1. df.replace('male','m') # 将字符串male替换为m
  2. # 替换后的结果
  3.     level  num     sex
  4. 0   hight   12       m
  5. 1     low    8  Female
  6. 2  middle    2  Female
  7. 3  middle    1  Female
6.4 数据框合并、组合、匹配

Pandas对数据框的合并、组合和匹配,主要有两种方式,一种是concat,一种是merge。
我们先生成一段示例数据:

  1. col_names = ['col_' + str(i) for i in range(3)] # demo数据的列名
  2. df1 = pd.DataFrame(np.arange(12).reshape(4,3),columns=col_names) # 第一份demo数据
  3. df2 = pd.DataFrame(np.arange(12,24).reshape(4,3),columns=col_names) # 第二份demo数据
  4. print(df1) # 打印输出
  5. print(df2) # 打印输出

demo数据如下:

  1.    col_0  col_1  col_2
  2. 0      0      1      2
  3. 1      3      4      5
  4. 2      6      7      8
  5. 3      9     10     11
  6.    col_0  col_1  col_2
  7. 0     12     13     14
  8. 1     15     16     17
  9. 2     18     19     20
  10. 3     21     22     23

使用concat来组合数据
在应用中,我们经常需要将不同的数据框组合起来,包括按行合并或按列合并。这时需要使用concat方法,具体应用如下:
按行组合

  1. df3 = pd.concat((df1,df2),'index')

其中index可以写0,二者都可以指定为行合并。合并后结果如下:

  1.    col_0  col_1  col_2
  2. 0      0      1      2
  3. 1      3      4      5
  4. 2      6      7      8
  5. 3      9     10     11
  6. 0     12     13     14
  7. 1     15     16     17
  8. 2     18     19     20
  9. 3     21     22     23

按列组合
按列合并跟安行合并的方法类似,只是后面指定axis为1或columns

  1. df4 = pd.concat((df1,df2),'columns')

合并后结果如下:

  1.    col_0  col_1  col_2  col_0  col_1  col_2
  2. 0      0      1      2     12     13     14
  3. 1      3      4      5     15     16     17
  4. 2      6      7      8     18     19     20
  5. 3      9     10     11     21     22     23

注意:一般情况下,如果两个dataframe的index不同,会导致合并错误,因此合并前需要保持index相同;如果不同,可以使用df1.index=df2.index先做处理

使用merge来匹配数据
Pandas的merge类似与SQL的多表关联查询,能实现leftjoin、rightjoin、where、innerjoin、fulljoin等操作。
为了模拟实际关联查询时index通常都是不匹配的情况,我们对两个数据框都分别新增一个列主键,用于匹配。

  1. df1['key'] =  [1,3,2,4] # 设置df1的主键
  2. df2['key'] =  [2,1,4,3] # 设置df2的主键
  3. print(df1)
  4. print(df2)

新增主键后两个数据框的数据:

  1.    col_0  col_1  col_2  key
  2. 0      0      1      2    1
  3. 1      3      4      5    3
  4. 2      6      7      8    2
  5. 3      9     10     11    4
  6.    col_0  col_1  col_2  key
  7. 0     12     13     14    2
  8. 1     15     16     17    1
  9. 2     18     19     20    4
  10. 3     21     22     23    3

下面我们开始匹配:

  1. df5 = pd.merge(df1,df2,on='key',how='inner')

其中:

  • df1和df2为两个要关联的数据框
  • on是关联的主键,由于两个数据框有相同的主键命名,因此可以直接用on设置。如果不是,需要单独使用left_on=name1,right_on=name2设置
  • how是设置关联的方式,可选值为'left', 'right', 'outer', 'inner',默认值是'inner'

上述代码执行后,我们print输出查看下结果:

  1. print(df5)
  2.    col_0_x  col_1_x  col_2_x  key  col_0_y  col_1_y  col_2_y
  3. 0        0        1        2    1       15       16       17
  4. 1        3        4        5    3       21       22       23
  5. 2        6        7        8    2       12       13       14
  6. 3        9       10       11    4       18       19       20

为了方便,上述方法也可以写为:

  1. df5 = df6.merge(df2,on='key',how='inner')

二者是等效的。

6.5 数据离散化

数据离散化,常用的方法是cut和qcut。二者的应用方法相似,以cut为例,具体应用如下:

  1. df = pd.DataFrame({'mount': np.random.randint(1,100,100)}) # 生成一个100行1列的数据框
  2. df['cut1'] = pd.cut(df['mount'], 4, labels=['bad', 'medium', 'good', 'awesome']) # 为每个分区加标签
  3. df['cut2'] = pd.cut(df['mount'], 4) # 使用默认的区间
  4. print(df.head(5)) # 输出前5条

上述代码中:

  • df['mount']要分区/离散化的列
  • 4是要分区的数量
  • labels是是每个分区的标签,个数需要跟分区数量相同

输出结果如下:

  1.    mount     cut1            cut2   
  2. 0     69     good   (48.5, 72.25]   
  3. 1     82  awesome   (72.25, 96.0]   
  4. 2     82  awesome   (72.25, 96.0]   
  5. 3     17      bad  (0.905, 24.75]   
  6. 4      9      bad  (0.905, 24.75]  

其中,cut2每行对应的区间左侧是区间开始值(不包含),右侧是区间结束值(包含)。分区的标准是默认的4分位数方法。如果要自定义分区边界,则可以这样处理。

  1. bins = [1,20,60,100] # 自定义边界   
  2. df['cut3'] = pd.cut(df['mount'], bins) # 切分   
  3. print(df.head(5))  

处理后的结果如下:

  1.    mount     cut1            cut2       cut3   
  2. 0     69     good   (48.5, 72.25]  (60, 100]   
  3. 1     82  awesome   (72.25, 96.0]  (60, 100]   
  4. 2     82  awesome   (72.25, 96.0]  (60, 100]   
  5. 3     17      bad  (0.905, 24.75]    (1, 20]   
  6. 4      9      bad  (0.905, 24.75]    (1, 20]  

 

6.6 改变数据形状

数据框形状的改变在基于单条数据处理后再做合并或建模非常重要,方法是reshape。

  1. df7 = df['mount'] # 建立一个可变对象   
  2. df8 = df7.values.reshape((25,4)) # 改为25*4的矩阵   
  3. df9 = df7.values.reshape((-1,1)) # 改为100*1的矩阵   
  4. df10 = df7.values.reshape((1,-1)) # 改为1*100的矩阵   
  5. print(df8.shape)   
  6. print(df9.shape)   
  7. print(df10.shape)  

上述代码执行后的输出如下:

  1. (25L, 4L)   
  2. (100L, 1L)   
  3. (1L, 100L)  

提示:对于单行数据的形状reshape,直接使用(-1,1)或(1,-1)来建立一列或一行的shape。

6.7 丢弃数据

Pandas使用drop方法丢弃数据,常用于丢弃特定行或特定列。dropna数据在上面已经介绍,这里介绍对整行或整列数据做丢弃处理。

  1. print(df.shape) # 查看原始数据形状   
  2.   
  3. new_df = df.drop(['cut1'],'columns') # 丢弃cut1,设置为1或columns   
  4. print(new_df.shape)#查看丢弃一列后的形状   
  5. print(new_df.head(3)) #打印输出   
  6.   
  7. new_df2 = df.drop(0,0) # 丢弃第一条数据,设置为0或index   
  8. print(new_df2.shape)#查看丢弃一行后的形状   
  9. print(new_df2.head(3)) #打印输出  

上面代码执行后结果如下:

  1. (100, 4) # 原始数据形状   
  2. (100, 3) # 丢弃一列后的形状   
  3. # 详细数据前3条   
  4.    mount           cut2       cut3   
  5. 0     69  (48.5, 72.25]  (60, 100]   
  6. 1     82  (72.25, 96.0]  (60, 100]   
  7. 2     82  (72.25, 96.0]  (60, 100]   
  8. (99, 4)# 丢弃一条数据后的形状   
  9. # 前3条数据   
  10.    mount     cut1            cut2       cut3   
  11. 1     82  awesome   (72.25, 96.0]  (60, 100]   
  12. 2     82  awesome   (72.25, 96.0]  (60, 100]   
  13. 3     17      bad  (0.905, 24.75]    (1, 20]  
6.8 改变数据列的类型

本小节开始的数据框df,其中num默认为int64格式

  1. df.dtypes# 查看数据列类型   
  2. # 输出结果   
  3. level    object  
  4. num       int64   
  5. sex      object  
  6. dtype: object  

通过astype可以更改为其他格式,例如字符串,方法为:

  1. df['num']= df['num'].astype(np.str)   
  2. df.dtypes# 查看数据列类型   
  3. # 输出结果   
  4. level    object  
  5. num      object  
  6. sex      object  
  7. dtype: object  

7、数据框的输出

Pandas支持将数据框输出为各种目标格式,例如csv、json、excel等,这些方法都非常简单。以下是输出格式的截图:
pandas输出
pandas输出2
以输出csv为例,直接使用:

  1. df.to_csv('my_file.csv')  

当然,如果读者感兴趣,可以对index、columns、分隔符等细节做更多设置。

案例-基于自动PDQ值的ARIMA时间序列预测应用

Python的科学计算和数据挖掘相关库中,pandas和statsmodels都提供了时间序列相关分析功能,本示例使用的是statsmodels做时间序列预测应用。有关时间序列算法的选择,实际场景中最常用的是ARIMA或ARMA了,因此本示例将使用ARIMA/ARMA来做时间序列分析。 继续阅读案例-基于自动PDQ值的ARIMA时间序列预测应用

案例-基于自动K值的KMeans广告效果聚类分析

案例背景

某企业由于投放的广告渠道比较多,需要对其做广告效果分析以实现有针对性的广告效果测量和优化工作。跟以应用为目的的案例不同的是,由于本案例是一个分析型案例,该过程的输出其实是不固定的,因此需要跟业务运营方具体沟通需求。

以下是在开展研究之前的基本预设条件:

  • 广告渠道的范畴是什么?具体包括哪些渠道?——所有站外标记的广告类渠道(以ad_开头)。
  • 数据集时间选择哪个时间段?——最近90天的数据。
  • 数据集选择哪些维度和指标?——渠道代号、日均UV、平均注册率、平均搜索量、访问深度、平均停留时间、订单转化率、投放总时间、素材类型、广告类型、合作方式、广告尺寸、广告卖点。
  • 专题分析要解决什么问题?——将广告分类并找出其重点特征,为接下来的业务讨论和数据分析提供支持。

明确了上述具体需求后,下面开始案例的主要工作部分。本节案例的输入源数据ad_performance.txt和源代码chapter7_code2.py位于“附件-chapter7”中,默认工作目录为“附件-chapter7”(如果不是,请cd切换到该目录下,否则会报“IOError: File ad_performance.txt does not exist”)。程序的输出为不同聚类类别的详细信息数据以及雷达图。 继续阅读案例-基于自动K值的KMeans广告效果聚类分析