- Preface 前言
- 第1章 引论
- 第2章 编程惯用法
- 第3章 基础语法
- 建议19:有节制地使用 from…import 语句
- 建议20:优先使用 absolute import 来导入模块
- 建议21:i+=1 不等于 ++i
- 建议22:使用 with 自动关闭资源
- 建议23:使用 else 子句简化循环(异常处理)
- 建议24:遵循异常处理的几点基本原则
- 建议25:避免 finally 中可能发生的陷阱
- 建议26:深入理解 None 正确判断对象是否为空
- 建议27:连接字符串应优先使用 join 而不是 +
- 建议28:格式化字符串时尽量使用 .format 方式而不是 %
- 建议29:区别对待可变对象和不可变对象
- 建议30:[]、() 和 {}:一致的容器初始化形式
- 建议31:记住函数传参既不是传值也不是传引用
- 建议32:警惕默认参数潜在的问题
- 建议33:慎用变长参数
- 建议34:深入理解 str() 和 repr() 的区别
- 建议35:分清 staticmethod 和 classmethod 的适用场景
- 第4章 库
- 建议36:掌握字符串的基本用法
- 建议37:按需选择 sort() 或者 sorted()
- 建议38:使用 copy 模块深拷贝对象
- 建议39:使用 Counter 进行计数统计
- 建议40:深入掌握 ConfigParser
- 建议41:使用 argparse 处理命令行参数
- 建议42:使用 pandas 处理大型 CSV 文件
- 建议43:一般情况使用 ElementTree 解析 XML
- 建议44:理解模块 pickle 优劣
- 建议45:序列化的另一个不错的选择 JSON
- 建议46:使用 traceback 获取栈信息
- 建议47:使用 logging 记录日志信息
- 建议48:使用 threading 模块编写多线程程序
- 建议49:使用 Queue 使多线程编程更安全
- 第5章 设计模式
- 第6章 内部机制
- 建议54:理解 built-in objects
- 建议55:init() 不是构造方法
- 建议56:理解名字查找机制
- 建议57:为什么需要 self 参数
- 建议58:理解 MRO 与多继承
- 建议59:理解描述符机制
- 建议60:区别 getattr() 和 getattribute() 方法
- 建议61:使用更为安全的 property
- 建议62:掌握 metaclass
- 建议63:熟悉 Python 对象协议
- 建议64:利用操作符重载实现中缀语法
- 建议65:熟悉 Python 的迭代器协议
- 建议66:熟悉 Python 的生成器
- 建议67:基于生成器的协程及 greenlet
- 建议68:理解 GIL 的局限性
- 建议69:对象的管理与垃圾回收
- 第7章 使用工具辅助项目开发
- 第8章 性能剖析与优化
建议42:使用 pandas 处理大型 CSV 文件
CSV(Comma Separated Values)作为一种逗号分隔型值的纯文本格式文件,在实际应用中经常用到,如数据库数据的导入导出、数据分析中记录的存储等。因此很多语言都提供了对CSV文件处理的模块,Python也不例外,其模块csv提供了一系列与CSV处理相关的API。我们先来看一下其中几个常见的API:
1)reader(csvfile[, dialect='excel'][, fmtparam]),主要用于CSV文件的读取,返回一个reader对象用于在CSV文件内容上进行行迭代。
参数csvfile,需要是支持迭代(Iterator)的对象,通常对文件(file)对象或者列表(list)对象都是适用的,并且每次调用next()方法的返回值是字符串(string);参数dialect的默认值为excel,与excel兼容;fmtparam是一系列参数列表,主要用于需要覆盖默认的Dialect设置的情形。当dialect设置为excel的时候,默认Dialect的值如下:
class excel(Dialect): delimiter = ',' # 单个字符,用于分隔字段 quotechar = '"' # 用于对特殊符号加引号,常见的引号为" doublequote = True # 用于控制quotechar 符号出现的时候的表现形式 skipinitialspace = False # 设置为true 的时候delimiter 后面的空格将会忽略 lineterminator = '\r\n' # 行结束符 quoting = QUOTE_MINIMAL # 是否在字段前加引号,QUOTE_MINIMAL 表示仅当一个字段包 含引号或者定义符号的时候才加引号
2)csv.writer(csvfile, dialect='excel', **fmtparams),用于写入CSV文件。参数同上。来看一个使用例子。
with open('data.csv', 'wb') as csvfile: csvwriter = csv.writer(csvfile, dialect='excel',delimiter="|",quotechar='"', quoting=csv.QUOTE_MINIMAL) csvwriter .writerow(["1/3/09 14:44","'Product1'","1200''","Visa","Gouya"]) # 写入行 输出形式为: 1/3/09 14:44|'Product1'|1200''|Visa|Gouya
3)csv.DictReader(csvfile, fieldnames=None, restkey=None, restval=None, dialect='excel', *args, **kwds),同reader()方法类似,不同的是将读入的信息映射到一个字典中去,其中字典的key由fieldnames指定,该值省略的话将使用CSV文件第一行的数据作为key值。如果读入行的字段的个数大于filednames中指定的个数,多余的字段名将会存放在restkey中,而restval主要用于当读取行的域的个数小于fieldnames的时候,它的值将会被用作剩下的key对应的值。
4)csv.DictWriter(csvfile, fieldnames, restval='', extrasaction='raise', dialect='excel', *args, **kwds),用于支持字典的写入。
import csv #DictWriter with open('test.csv', 'wb') as csv_file: # 设置列名称 FIELDS = ['Transaction_date', 'Product', 'Price', 'Payment_Type'] writer = csv.DictWriter(csv_file, fieldnames=FIELDS) # 写入列名称 writer.writerow(dict(zip(FIELDS, FIELDS))) d = {'Transaction_date':'1/2/09 6:17','Product':'Product1','Price':'1200', 'Payment_Type':'Mastercard'} # 写入一行 Writer.writerow(d) with open('test.csv', 'rb') as csv_file: for d in csv.DictReader(csv_file): print d #output d is:{'Product': 'Product1', 'Transaction_date': '1/2/09 6:17', 'Price': '1200', 'Payment_Type': 'Mastercard'}
csv模块使用非常简单,基本可以满足大部分需求。但你有没有思考过这个问题:有些应用中需要解析和处理的CSV文件可能有上百MB甚至几个GB,这种情况下csv模块是否能够应付呢?先来做个实验,临时创建一个1GB的CSV文件并将其加载到内存中,看看会有什么问题发生。
>>> f = open('large.csv',"wb") >>> f.seek(1073741824-1) # 创建大文件的技巧 >>> f.write("\0") >>> f.close() >>> import os >>> os.stat("large.csv").st_size # 输出文件的大小 1073741824L >>> with open("large.csv","rb") as csvfile: ... mycsv = csv.reader(csvfile,delimiter=';') ... for row in mycsv: ... print row ... Traceback (most recent call last): File "<stdin>", line 3, in <module> MemoryError # 发生了内存异常 >>>
上面的例子中当企图读入这个CSV文件的时候抛出了MemoryError异常。这是为什么?因为csv模块对于大型CSV文件的处理无能为力。这种情况下就需要考虑其他解决方案了,pandas模块便是较好的选择。
Pandas即Python Data Analysis Library,是为了解决数据分析而创建的第三方工具,它不仅提供了丰富的数据模型,而且支持多种文件格式处理,包括CSV、HDF5、HTML等,能够提供高效的大型数据处理。其支持的两种数据结构——Series和DataFrame——是数据处理的基础。下面先来介绍这两种数据结构。
Series:它是一种类似数组的带索引的一维数据结构,支持的类型与NumPy兼容。如果不指定索引,默认为0到N-1。通过obj.values()和obj.index()可以分别获取值和索引。当给Series传递一个字典的时候,Series的索引将根据字典中的键排序。如果传入字典的时候同时重新指定了index参数,当index与字典中的键不匹配的时候,会出现时数据丢失的情况,标记为NaN。
在pandas中用函数isnull()和notnull()来检测数据是否丢失。
>>> obj1 = Series([1, 'a', (1,2), 3], index=['a', 'b', 'c', 'd']) >>> obj1#value 和index 一一匹配 a 1 b a c (1, 2) d 3 dtype: object >>> obj2=Series({"Book":"Python","Author":"Dan","ISBN":"011334","Price":25},inde x=['book','Author','ISBM','Price']) >>> obj2.isnull() book True # 指定的index 与字典的键不匹配,发生数据丢失 Author False ISBM True # 指定的index 与字典的键不匹配,发生数据丢失 Price False dtype: bool >>>
DataFrame:类似于电子表格,其数据为排好序的数据列的集合,每一列都可以是不同的数据类型,它类似于一个二维数据结构,支持行和列的索引。和Series一样,索引会自动分配并且能根据指定的列进行排序。使用最多的方式是通过一个长度相等的列表的字典来构建。构建一个DataFrame最常用的方式是用一个相等长度列表的字典或NumPy数组。DataFrame也可以通过columns指定序列的顺序进行排序。
>>> data = {'OrderDate': ['1-6-10', '1-23-10', '2-9-10', '2-26-10', '3-15-10'], ... 'Region': ['East', 'Central', 'Central', 'West', 'East'], ... 'Rep': ['Jones', 'Kivell', 'Jardine', 'Gill', 'Sorvino']} >>> >>> DataFrame(data,columns=['OrderDate','Region','Rep'])# 通过字典构建,按照cloumns 指定的顺序排序 OrderDate Region Rep 0 1-6-10 East Jones 1 1-23-10 Central Kivell 2 2-9-10 Central Jardine 3 2-26-10 West Gill 4 3-15-10 East Sorvino
Pandas中处理CSV文件的函数主要为read_csv()和to_csv()这两个,其中read_csv()读取CSV文件的内容并返回DataFrame,to_csv()则是其逆过程。两个函数都支持多个参数,由于其参数众多且过于复杂,本节不对各个参数一一介绍,仅选取几个常见的情形结合具体例子介绍。下面举例说明,其中需要处理的CSV文件格式如图4-2所示。
图4-2 CSV文件示例
1)指定读取部分列和文件的行数。具体的实现代码如下:
>>> df = pd.read_csv("SampleData.csv",nrows=5,usecols=['OrderDate','Item','Total ']) >>> df OrderDate Item Total 0 1-6-10 Pencil 189.05 1 1-23-10 Binder 999.50 2 2-9-10 Pencil 179.64 3 2-26-10 Pen 539.73 4 3-15-10 Pencil 167.44
方法read_csv()的参数nrows指定读取文件的行数,usecols指定所要读取的列的列名,如果没有列名,可直接使用索引0、1、...、n-1。上述两个参数对大文件处理非常有用,可以避免读入整个文件而只选取所需要部分进行读取。
2)设置CSV文件与excel兼容。dialect参数可以是string也可以是csv.Dialect的实例。如果将图4-2所示的文件格式改为使用“|”分隔符,则需要设置dialect相关的参数。error_bad_lines设置为False,当记录不符合要求的时候,如记录所包含的列数与文件列设置不相等时可以直接忽略这些列。下面的代码用于设置CSV文件与excel兼容,其中分隔符为“|”,而error_bad_lines=False会直接忽略不符合要求的记录。
>>> dia = csv.excel() >>> dia.delimiter="|" # 设置分隔符 >>> pd.read_csv("SD.csv") OrderDate|Region|Rep|Item|Units|Unit Cost|Total 0 1-6-10|East|Jones|Pencil|95|1.99 |189.05 1 1-23-10|Central|Kivell|Binder|50|19.99 |999.50... >>> pd.read_csv("SD.csv",dialect = dia,error_bad_lines=False) Skipping line 3: expected 7 fields, saw 10 # 所有不符合格式要求的列将直接忽略 OrderDate Region Rep Item Units Unit Cost Total 0 1-6-10 East Jones Pencil 95 1.99 189.05 >>>
3)对文件进行分块处理并返回一个可迭代的对象。分块处理可以避免将所有的文件载入内存,仅在使用的时候读入所需内容。参数chunksize设置分块的文件行数,10表示每一块包含10个记录。将参数iterator设置为True时,返回值为TextFileReader,它是一个可迭代对象。来看下面的例子,当chunksize=10、iterator=True时,每次输出为包含10个记录的块。
>>> reader = pd.read_table("SampleData.csv",chunksize=10,iterator=True) >>> reader <pandas.io.parsers.TextFileReader object at 0x0314BE70> >>> iter(reader).next() # 将TextFileReader 转换为迭代器并调用next 方法 OrderDate,Region,Rep,Item,Units,Unit Cost,Total # 每次读入10 行 0 1-6-10,East,Jones,Pencil,95, 1.99 , 189.05 1 1-23-10,Central,Kivell,Binder,50, 19.99 , 999.50 2 2-9-10,Central,Jardine,Pencil,36, 4.99 , 179.64 3 2-26-10,Central,Gill,Pen,27, 19.99 , 539.73 4 3-15-10,West,Sorvino,Pencil,56, 2.99 , 167.44 5 4-1-10,East,Jones,Binder,60, 4.99 , 299.40 6 4-18-10,Central,Andrews,Pencil,75, 1.99 , 149.25 7 5-5-10,Central,Jardine,Pencil,90, 4.99 , 449.10 8 5-22-10,West,Thompson,Pencil,32, 1.99 , 63.68 9 6-8-10,East,Jones,Binder,60, 8.99 , 539.40
4)当文件格式相似的时候,支持多个文件合并处理。以下例子用于将3个格式相同的文件进行合并处理。
>>> filelst = os.listdir("test") >>> print filelst # 同时存在3 个格式相同的文件 ['s1.csv', 's2.csv', 's3.csv'] >>> os.chdir("test") >>> dfs =[pd.read_csv(f) for f in filelst] >>> total_df = pd.concat(dfs) # 将文件合并 >>> total_df OrderDate Region Rep Item Units Unit Cost Total 0 1-6-10 East Jones Pencil 95 1.99 189.05 1 1-23-10 Central Kivell Binder 50 19.99 999.5
了解完pandas后,读者可以自行实验一下使用pandas处理前面生成的1GB的文件,看看还会不会抛出MemoryError异常。
在处理CSV文件上,特别是大型CSV文件,pandas不仅能够做到与csv模块兼容,更重要的是其CSV文件以DataFrame的格式返回,pandas对这种数据结构提供了非常丰富的处理方法,同时pandas支持文件的分块和合并处理,非常灵活,由于其底层很多算法采用Cython实现运行速度较快。实际上pandas在专业的数据处理与分析领域,如金融等行业已经得到广泛的应用。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论