博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
《Python Cookbook(第3版)中文版》——第6章 数据编码与处理 6.1 读写CSV数据
阅读量:6637 次
发布时间:2019-06-25

本文共 4445 字,大约阅读时间需要 14 分钟。

本节书摘来自异步社区《Python Cookbook(第3版)中文版》一书中的第6章,第6.1节,作者[美]David Beazley , Brian K.Jones,陈舸 译,更多章节内容可以访问云栖社区“异步社区”公众号查看。

第6章 数据编码与处理

本章主要关注的重点是利用Python来处理以各种常见编码形式所呈现出的数据,比如CSV文件、JSON、XML以及二进制形式的打包记录。与数据结构那章不同,本章不会把重点放在特定的算法之上,而是着重处理数据在程序中的输入和输出问题上。

6.1 读写CSV数据

6.1.1 问题

我们想要读写CSV文件中的数据。

6.1.2 解决方案

对于大部分类型的CSV数据,我们都可以用csv库来处理。比如,假设在名为stocks.csv的文件中包含有如下的股票市场数据:

Symbol,Price,Date,Time,Change,Volume    "AA",39.48,"6/11/2007","9:36am",-0.18,181800    "AIG",71.38,"6/11/2007","9:36am",-0.15,195500    "AXP",62.58,"6/11/2007","9:36am",-0.46,935000    "BA",98.31,"6/11/2007","9:36am",+0.12,104800    "C",53.08,"6/11/2007","9:36am",-0.25,360900    "CAT",78.29,"6/11/2007","9:36am",-0.23,225400

下面的代码示例告诉我们如何将这些数据读取为元组序列:

import csvwith open('stocks.csv') as f:    f_csv = csv.reader(f)    headers = next(f_csv)    for row in f_csv:        # Process row        ...

在上面的代码中,row将会是一个元组。因此,要访问特定的字段就需要用到索引,比如row[0](表示Symbol)和row[4](表示Change)。

由于这样的索引常常容易混淆,因此这里可以考虑使用命名元组。示例如下:

from collections import namedtuplewith open('stock.csv') as f:    f_csv = csv.reader(f)    headings = next(f_csv)    Row = namedtuple('Row', headings)    for r in f_csv:        row = Row(*r)        # Process row        ...

这样就可以使用每一列的标头比如row.Symbol和row.Change来取代之前的索引了。应该要指出的是,这个方法只有在每一列的标头都是合法的Python标识符时才起作用。如果不是的话,就必须调整原始的标头(比如,把非标识符字符用下划线或其他类似的符号取代)。

另一种可行的方式是将数据读取为字典序列。可以用下面的代码实现:

import csvwith open('stocks.csv') as f:    f_csv = csv.DictReader(f)    for row in f_csv:        # process row        ...

在这个版本中,可以通过行标头来访问每行中的元素。比如,row['Symbol']或者row['Change']。

要写入CSV数据,也可以使用csv模块来完成,但是要创建一个写入对象。示例如下:

headers = ['Symbol','Price','Date','Time','Change','Volume']rows = [('AA', 39.48, '6/11/2007', '9:36am', -0.18, 181800),        ('AIG', 71.38, '6/11/2007', '9:36am', -0.15, 195500),        ('AXP', 62.58, '6/11/2007', '9:36am', -0.46, 935000),       ]with open('stocks.csv','w') as f:    f_csv = csv.writer(f)    f_csv.writerow(headers)    f_csv.writerows(rows)

如果数据是字典序列,那么可以这样处理:

headers = ['Symbol', 'Price', 'Date', 'Time', 'Change', 'Volume']rows = [{'Symbol':'AA', 'Price':39.48, 'Date':'6/11/2007',          'Time':'9:36am', 'Change':-0.18, 'Volume':181800},        {'Symbol':'AIG', 'Price': 71.38, 'Date':'6/11/2007',          'Time':'9:36am', 'Change':-0.15, 'Volume': 195500},        {'Symbol':'AXP', 'Price': 62.58, 'Date':'6/11/2007',          'Time':'9:36am', 'Change':-0.46, 'Volume': 935000},        ]with open('stocks.csv','w') as f:    f_csv = csv.DictWriter(f, headers)    f_csv.writeheader()    f_csv.writerows(rows)

6.1.3 讨论

应该总是选择使用csv模块来处理,而不是自己手动分解和解析CSV数据。比如,我们可能会倾向于写出这样的代码:

with open('stocks.csv') as f:    for line in f:        row = line.split(',')        # process row        ...

这种方式的问题在于仍然需要自己处理一些令人厌烦的细节问题。比如说,如果有任何字段是被引号括起来的,那么就要自己去除引号。此外,如果被引用的字段中恰好包含有一个逗号,那么产生出的那一行会因为大小错误而使得代码崩溃(因为原始数据也是用逗号分隔的)。

默认情况下,csv库被实现为能够识别微软Excel所采用的CSV编码规则。这也许是最为常见的CSV编码规则了,能够带来最佳的兼容性。但是,如果查阅csv的文档,就会发现有几种方法可以将编码微调为其他的格式(例如,修改分隔字符等)。比方说,如果想读取以tab键分隔的数据,可以使用下面的代码:

# Example of reading tab-separated valueswith open('stock.tsv') as f:    f_tsv = csv.reader(f, delimiter='\t')    for row in f_tsv:        # Process row        ...

如果正在读取CSV数据并将其转换为命名元组,那么在验证列标题时要小心。比如,某个CSV文件中可能在标题行中包含有非法的标识符字符,就像下面的示例这样:

Street Address,Num-Premises,Latitude,Longitude5412 N CLARK,10,41.980262,-87.668452

这会使得创建命名元组的代码出现ValueError异常。要解决这个问题,应该首先整理标题。例如,可以对非法的标识符字符进行正则替换,示例如下:

import rewith open('stock.csv') as f:    f_csv = csv.reader(f)    headers = [ re.sub('[^a-zA-Z_]', '_', h) for h in next(f_csv) ]    Row = namedtuple('Row', headers)    for r in f_csv:        row = Row(*r)        # Process row        ...

此外,还需要重点强调的是,csv模块不会尝试去解释数据或者将数据转换为除字符串之外的类型。如果这样的转换很重要,那么这就是我们需要自行处理的问题。下面这个例子演示了对CSV数据进行额外的类型转换:

col_types = [str, float, str, str, float, int]with open('stocks.csv') as f:    f_csv = csv.reader(f)    headers = next(f_csv)    for row in f_csv:        # Apply conversions to the row items        row = tuple(convert(value) for convert, value in zip(col_types, row))        ...

作为另外一种选择,下面这个例子演示了将选中的字段转换为字典:

print('Reading as dicts with type conversion')field_types = [ ('Price', float),                ('Change', float),                ('Volume', int) ]with open('stocks.csv') as f:    for row in csv.DictReader(f):        row.update((key, conversion(row[key]))                    for key, conversion in field_types)        print(row)

一般来说,对于这样的转换都应该小心为上。在现实世界中,CSV文件可能会缺少某些值,或者数据损坏了,以及出现其他一些可能会使类型转换操作失败的情况,这都是很常见的。因此,除非可以保证数据不会出错,否则就需要考虑这些情况(也许需要加上适当的异常处理代码)。

转载地址:http://yrdvo.baihongyu.com/

你可能感兴趣的文章
查询语句
查看>>
带图,解决本页不但包含安全的内容,也包含不安全的内容是否显示不安全的内容...
查看>>
Windows Phone开发之路(6) XAML基础(下)
查看>>
第8章 Service基础
查看>>
Linux编译程序时的一些注意事项
查看>>
413 Request Entity Too Large
查看>>
perl 释放内存问题【转】
查看>>
Xcode4.2新特性之storyboards (故事板)
查看>>
gdb调试器命令学习总结笔记
查看>>
Quartz.NET 2.0 学习笔记(1) :Quartz.NET简介
查看>>
android gif view
查看>>
Enum
查看>>
HDOJ1232 ( 畅通工程 ) 【并查集】
查看>>
【转载】已知经纬度查询Landsat TM 、ETM+ 、MSS 数据的行带 整理版 V1.0
查看>>
深入理解CSS溢出overflow
查看>>
mysql之limit m,n
查看>>
Java设计模式系列之策略模式
查看>>
jquery的ajax同步和异步
查看>>
使用ModelForm表单验证
查看>>
php中empty()、isset()、is_null()和变量本身的布尔判断区别(转)
查看>>