
嗨,habrozhiteli! 本书适用于已经使用一种或多种编程语言的经验并希望尽快,轻松地学习Python 3基础的人们,假定读者已经熟悉控制结构,OOP,文件处理,异常处理等。 e。对于需要紧凑型Python 3.1参考的早期Python版本的用户,这本书也将派上用场。
我们邀请您阅读节选“处理数据文件”
如何使用书
第1部分提供了有关Python的一般信息。 您将学习如何在系统上下载并安装Python。 它还提供了对该语言的一般概述,这对于希望对Python有较高了解的经验丰富的程序员来说非常有用。
第2部分包含本书的主要材料。 它讨论了使用Python作为通用编程语言时获得实践技能所需的要素。 本章的内容已计划好,以便刚开始学习Python的读者可以按顺序前进,掌握该语言的要点。 该部分还包含更复杂的部分,因此您可以在一个地方返回并找到有关某个设计或主题的所有必要信息。
第3部分介绍了Python的高级功能-并非绝对必要的语言元素,但对于任何认真的Python程序员来说肯定会派上用场。
第4部分将重点介绍超越该语言的简单语法的专业主题。 您可以阅读这些章节,也可以根据需要跳过它们。
鼓励Python新手程序员从第3章开始做一个总体印象,然后继续学习第2部分中感兴趣的各章。引入交互式示例以立即增强概念。 您还可以超越本文中给出的示例,并寻找尚不清楚的任何问题的答案。 这种方法将提高学习速度并加深理解。 如果您还不熟悉OOP或您的应用程序不需要OOP,则可以跳过第15章的大部分内容。
已经熟悉Python的读者也应该从第3章开始。它提供了很好的介绍性概述,并描述了Python 3与更熟悉的版本之间的区别。 它还可以用来评估您是否准备好继续学习本书第3部分和第4部分的更复杂的章节。
也许一些不熟悉Python但在其他编程语言上有丰富经验的读者可以通过阅读第3章并查看Python标准库模块(第19章)和Python文档中的Python库参考指南来获得大多数必要的信息。 。
摘录。 数据文件处理
大多数数据分布在文本文件中。 这可以是非结构化的文本(例如,消息的集合或文学文本的集合),也可以是更多的结构化数据,其中每行都是一条记录,并且字段由特殊的分隔符-逗号,制表符或竖线(|)分隔。 文本文件可能很大。 一个数据集可能占据数十个甚至数百个文件,并且其中包含的数据可能不完整或失真。 有了这种多样性,您几乎不可避免地会遇到读取和使用文本文件中的数据的任务。 本章介绍了在Python中解决此问题的基本策略。
21.1。 ETL简介
需要从文件中提取数据,解析它们,将它们转换为方便的格式,然后几乎与数据文件同时执行某些操作。 此外,此过程甚至有一个标准术语:ETL(提取-转换-加载,即“提取-转换-加载”)。 检索是指读取数据源并在必要时对其进行解析的过程。 转换可能涉及清理和规范化数据,以及合并,拆分和重组它们包含的记录。 最后,加载意味着将转换后的数据保存在新位置(另一个文件或数据库中)。 本章讨论了在Python中实现ETL的基础,从文本数据文件到将转换后的数据存储在其他文件中。 第22章讨论了更结构化的数据文件,第23章讨论了数据库中信息的存储。
21.2。 读取文字档
ETL的第一部分-提取-涉及打开文件并读取其内容。 乍一看,听起来很简单,但即使在这里也可能出现问题-例如文件大小。 如果文件太大而无法容纳在内存中,则需要对代码进行结构化,以使其适用于文件的较小部分(可能一行)。
21.2.1。 文字编码:ASCII,Unicode等
另一个可能的问题是编码。 本章专门介绍文本文件,实际上,现实世界中传输的大部分数据都存储在文本文件中。 但是,文本的确切性质可能会因应用程序,用户以及国家(地区)而异。
有时,文本带有ASCII编码的信息,包括128个字符,其中只有95个被归类为可打印。 幸运的是,ASCII编码是大多数数据传输情况下的“最小公倍数”。 另一方面,它不能应付世界上存在的众多字母和书写系统的复杂性。 以ASCII编码读取文件几乎肯定会导致以下事实:读取不受支持的字符(德语ü,葡萄牙语ç或几乎是英语以外的其他任何字符)时,将开始出现问题并出现错误。
发生这些错误的原因是ASCII使用7位值,而典型文件中的字节由8位组成,这允许表示256个可能的值,而不是7位值的128个。 这些附加代码通常用于存储附加值-从扩展的标点符号(例如中间的短划线)到各种字符(商标,版权符号和程度符号)以及带有变音符号的字母字符的版本。 总会有一个问题:读取文本文件时,您可能会遇到超出ASCII范围的128个字符的字符,并且无法确定对哪个字符进行了编码。 假设您遇到了一个代码为214的字符。这是什么? 分隔标记,字母Ö或其他字词? 没有创建此文件的源代码,就不可能找到。
Unicode和UTF-8
为了消除这种歧义,可以使用Unicode。 称为UTF-8的Unicode编码支持基本的ASCII字符,而无需进行任何更改,但是它也允许其他字符和Unicode标准中的字符集几乎不受限制。 由于其灵活性,在撰写本文时,UTF-8已用于超过85%的网页中。 这意味着在阅读文本文件时,最好专注于UTF-8。 如果文件仅包含ASCII字符,则可以正确读取它们,但是如果其他字符都以UTF-8编码,则也可以保证。 幸运的是,默认情况下,Python 3字符串数据类型旨在支持Unicode。
即使使用Unicode,当文本中出现无法成功解码的值时,也可能出现这种情况。 Python中的open函数接收一个附加的errors参数,该参数确定在读取或写入文件时如何处理编码错误。 默认值为“严格”,每次检测到编码错误时都会触发该错误。 其他有用的值是'ignore'(跳过导致错误的字符); '替换'(通常用特殊标记替换字符?); 'backslashreplace'(该字符由转义序列替换为\)和'surrogateescape'(入侵者字符在读取时转换为私有Unicode代码点,在写入时转换为原始字节序列)。 处理或解决编码错误的方法的选择取决于特定情况。
考虑一个包含无效UTF-8字符的文件的简短示例,并查看如何在不同模式下处理此字符。 首先使用字节和二进制模式写入文件:
>>> open('test.txt', 'wb').write(bytes([65, 66, 67, 255, 192,193]))
该命令的结果是,由字符“ ABC”创建文件,然后是ASCII中未包含的三个字符,根据所使用的编码方法,它们可以不同地显示。 如果使用vim查看文件,结果将如下所示:
ABCÿÀÁ ~
创建文件后,请尝试以默认的严格错误处理模式读取文件:
>>> x = open('test.txt').read() Traceback (most recent call last): File "<stdin>", line 1, in <module> File "/usr/local/lib/python3.6/codecs.py", line 321, in decode (result, consumed) = self._buffer_decode(data, self.errors, final) UnicodeDecodeError: 'utf-8' codec can't decode byte 0xff in position 3: invalid start byte
值为255的第四个字节在此位置不是有效的UTF-8字符,因此在“严格”模式下会发生异常。 现在,让我们看看其他错误处理模式如何处理同一文件,不要忘记最后三个字符会触发错误:
如果您希望有问题的字符消失,请使用“忽略”模式。 “替换”模式仅标记无效字符的位置,而其他模式则尝试以其他方式尝试保存无效字符而不进行解释。
21.2.2。 非结构化文字
读取非结构化文本文件最容易,但是它们也会在提取信息方面造成最多的问题。 根据文本的性质以及您将要处理的内容,对非结构化文本的处理可能会大相径庭,因此对文本处理的任何详细讨论都超出了本书的范围。 但是,一个简短的示例将有助于说明一些基本问题,并为讨论具有结构化文本数据的文件打下基础。
最简单的问题之一是在文件中选择基本逻辑单元。 如果您使用成千上万条Twitter消息,Moby Dick文本或新闻集合,则需要以某种方式将其分解为若干块。 对于推文,可以将每一块放在一行上,并且读取和处理文件的每一行都非常简单地组织起来。
对于Moby Dick甚至是一些新闻,问题变得更加复杂。 当然,通常不希望将小说的文本甚至新闻的文本视为一个整体。 在这种情况下,您需要确定所需的块,然后制定将文件划分为块的策略。 您可能更喜欢逐段处理文本。 在这种情况下,您应该确定如何组织文本在文件中的段落细分,并相应地编写代码。 如果段落与文本文件的行匹配,这将不会很困难。 但是,一个文本文件的一个段落通常可以在一个文本文件中包含多行,因此您将不得不努力工作。
现在考虑几个示例。
叫我以实玛利。 几年前-没关系精确到多久-
我的钱包里几乎没有钱,没有什么特别的
为了让我在岸上感兴趣,我以为我会航行约
并参观世界的水域。 这是我的一种方式
驱除脾脏和调节血液循环。
每当我发现自己的嘴巴变得越来越冷酷时,
每当我心中潮湿多雨的十一月; 每当我
发现自己在棺材仓库前不由自主地停下来,
提起我遇到的每场葬礼的后方;
尤其是当我的假冒让我占了上风时,
需要严格的道德原则来阻止我
故意走上街,有条不紊地敲门
人们脱下帽子-然后,我认为现在是时候出海了
我会尽快 这是我的手枪和球的替代品。
卡托(Cato)用哲理的兴盛使自己投身于剑上。
我悄悄地坐船。 这不足为奇。
如果他们知道的话,几乎所有程度的人都会有一段时间
或其他,几乎怀有相同的感受
海洋与我同在。
现在有您的岛屿城市曼哈顿,被码头束缚
就像印度小岛旁的珊瑚礁一样-商业围绕着她的冲浪。
左右两侧,街道将您带向水边。 其极端的市中心
是电池,其中贵重的葡萄被波浪冲刷并冷却
由微风吹拂,几个小时前就看不到土地了。
看看那里挤满水的人群。
在此示例中(以“ Moby Dick”为开头),行的分页方式或多或少地与分页方式相同,并且段落用单行表示。 如果要将每个段落视为一个整体,则需要将文本分成空白行。 幸运的是,可以通过字符串的split()方法轻松完成此任务。 文本中的每个换行符均由组合“ \ n”表示。 当然,每个段落的最后一行文本以换行符结尾,如果下一行文本为空,则第二个换行符紧随其后:
将文本解析为段落是处理非结构化文本的非常简单的步骤。 在进一步处理之前,您可能还需要对文本进行其他规范化。 假设您要计算文本文件中每个单词的出现频率。 如果仅按遗漏简单地分割文件,您将获得文件中的单词列表,但是,准确地计算出现的次数将不是那么简单,因为This,This,This。 而这个,将不会被视为同一个词。 为了使此代码正常工作,有必要通过删除标点符号并将所有文本转换为一种大小写之前对文本进行规范化处理。 在上面的文本示例中,用于构造单词标准化列表的代码如下所示:
21.2.3。 非结构化分隔文件
非结构化文件的读取非常简单,但是缺乏结构性也是它们的缺点。 通常,为文件定义某种结构以简化对单个值的选择更为方便。 在最简单的版本中,文件分为几行,每一行包含一个信息元素。 例如,它可以是要处理的文件名列表,人名列表或来自远程传感器的一系列温度读数。 在这种情况下,数据的分析非常简单:您阅读了该行,并在必要时将其转换为所需的类型。 这就是使文件准备就绪可以使用的全部步骤。
但是,情况并非如此简单。 通常,您需要将几个互连的数据元素分组,并且您的代码应将它们一起读取。 通常,为此,相关数据放在一行上并由特殊字符分隔。 在这种情况下,当读取文件的每一行时,将使用特殊字符将数据拆分为字段并将字段值存储在变量中以进行进一步处理。
以下文件包含定界格式的温度数据:
State|Month Day, Year Code|Avg Daily Max Air Temperature (F)|Record Count for Daily Max Air Temp (F) Illinois|1979/01/01|17.48|994 Illinois|1979/01/02|4.64|994 Illinois|1979/01/03|11.05|994 Illinois|1979/01/04|9.51|994 Illinois|1979/05/15|68.42|994 Illinois|1979/05/16|70.29|994 Illinois|1979/05/17|75.34|994 Illinois|1979/05/18|79.13|994 Illinois|1979/05/19|74.94|994
文件中的数据用竖线(|)分隔。 在此示例中,它们由四个字段组成:状态,观测日期,平均最高温度和提供数据的站点数。 其他标准分隔符是制表符和逗号。 也许最经常使用逗号,但是分隔符可以是值中不会出现的任何字符(稍后会详细介绍)。 逗号分隔的数据非常普遍,以致于通常将该格式称为CSV(逗号分隔的值,即逗号分隔的数据),并且这种文件类型带有.csv扩展名作为格式属性。
无论使用什么字符作为分隔符,如果您知道字符是什么,都可以编写自己的Python代码将字符串拆分为字段并将它们作为列表返回。 在前一种情况下,可以使用split()方法将字符串转换为值列表:
>>> line = "Illinois|1979/01/01|17.48|994" >>> print(line.split("|")) ['Illinois', '1979/01/01', '17.48', '994']
这项技术非常容易实现,但是所有值都以字符串形式存储,这对于后续处理可能不方便。
21.2.4。 CSV模组
如果您经常需要处理定界数据文件,则应仔细查看csv模块及其功能。 当我被要求从Python标准库中命名我最喜欢的模块时,我多次调用了csv模块-不是因为它看起来很漂亮(不是),而是因为它可能节省了我更多的时间并节省了我从我的潜在错误中获得的收益比其他任何模块都要高。
csv模块是Python“含电池”理念的完美示例。 尽管您可以完美地编写自己的代码来读取带分隔符的文件(此外,它并不那么困难),但是使用Python模块更加容易和可靠。 csv模块已经过测试和优化,它提供了许多您几乎无法实现的功能,但是这些功能非常方便并且可以节省时间。
看一下以前的数据,并决定如何使用csv模块读取它。 数据解析代码应读取每一行并删除尾随的换行符,然后按字符分隔行。 并将值列表附加到常规字符串列表。 解决方案可能看起来像这样:
>>> results = [] >>> for line in open("temp_data_pipes_00a.txt"): ... fields = line.strip().split("|") ... results.append(fields) ... >>> results [['State', 'Month Day, Year Code', 'Avg Daily Max Air Temperature (F)', 'Record Count for Daily Max Air Temp (F)'], ['Illinois', '1979/01/01', '17.48', '994'], ['Illinois', '1979/01/02', '4.64', '994'], ['Illinois', '1979/01/03', '11.05', '994'], ['Illinois', '1979/01/04', '9.51', '994'], ['Illinois', '1979/05/15', '68.42', '994'], ['Illinois', '1979/ 05/16', '70.29', '994'], ['Illinois', '1979/05/17', '75.34', '994'], ['Illinois', '1979/05/18', '79.13', '994'], ['Illinois', '1979/05/19', '74.94', '994']]
如果要对csv模块执行相同的操作,则代码可能如下所示:
>>> import csv >>> results = [fields for fields in csv.reader(open("temp_data_pipes_00a.txt", newline=''), delimiter="|")] >>> results [['State', 'Month Day, Year Code', 'Avg Daily Max Air Temperature (F)', 'Record Count for Daily Max Air Temp (F)'], ['Illinois', '1979/01/01', '17.48', '994'], ['Illinois', '1979/01/02', '4.64', '994'], ['Illinois', '1979/01/03', '11.05', '994'], ['Illinois', '1979/01/04', '9.51', '994'], ['Illinois', '1979/05/15', '68.42', '994'], ['Illinois', '1979/ 05/16', '70.29', '994'], ['Illinois', '1979/05/17', '75.34', '994'], ['Illinois', '1979/05/18', '79.13', '994'], ['Illinois', '1979/05/19', '74.94', '994']]
在这种简单情况下,与该解决方案的独立实施相比,收益不是很大。 但是,代码却缩短了两行,变得更加清晰,而且您不必担心会截断换行符。 当您面对更复杂的案件时,真正的优势就来了。
此示例中的数据是真实的,但实际上已被简化和清除。 来自源的真实数据将更加复杂。 实际数据包含更多字段,某些字段将用引号引起来,而其他字段则不会,并且第一个字段可能为空。 原始文件由制表符分隔,但出于演示目的,我用逗号将它们引号分开:
"Notes","State","State Code","Month Day, Year","Month Day, Year Code",Avg Daily Max Air Temperature (F),Record Count for Daily Max Air Temp (F),Min Temp for Daily Max Air Temp (F),Max Temp for Daily Max Air Temp (F),Avg Daily Max Heat Index (F),Record Count for Daily Max Heat Index (F),Min for Daily Max Heat Index (F),Max for Daily Max Heat Index (F),Daily Max Heat Index (F) % Coverage ,"Illinois","17","Jan 01, 1979","1979/01/ 01",17.48,994,6.00,30.50,Missing,0,Missing,Missing,0.00% ,"Illinois","17","Jan 02, 1979","1979/01/02",4.64,994,- 6.40,15.80,Missing,0,Missing,Missing,0.00% ,"Illinois","17","Jan 03, 1979","1979/01/03",11.05,994,- 0.70,24.70,Missing,0,Missing,Missing,0.00% ,"Illinois","17","Jan 04, 1979","1979/01/ 04",9.51,994,0.20,27.60,Missing,0,Missing,Missing,0.00% ,"Illinois","17","May 15, 1979","1979/05/ 15",68.42,994,61.00,75.10,Missing,0,Missing,Missing,0.00% ,"Illinois","17","May 16, 1979","1979/05/ 16",70.29,994,63.40,73.50,Missing,0,Missing,Missing,0.00% ,"Illinois","17","May 17, 1979","1979/05/ 17",75.34,994,64.00,80.50,82.60,2,82.40,82.80,0.20% ,"Illinois","17","May 18, 1979","1979/05/ 18",79.13,994,75.50,82.10,81.42,349,80.20,83.40,35.11% ,"Illinois","17","May 19, 1979","1979/05/ 19",74.94,994,66.90,83.10,82.87,78,81.60,85.20,7.85%
请注意:某些字段包含逗号。 根据这种情况下的规则,该字段用引号引起来,以指示其内容不旨在解析和搜索分隔符。 实际上(在这种情况下),通常只有一小部分字段用引号引起来,尤其是那些其值可能包含分隔符的字段。 但是(同样在此示例中),即使某些字段不太可能包含分隔符,它们也会用引号引起来。
在这种情况下,本地解决方案变得太麻烦了。 现在仅用定界符分隔行不再有效; 您需要确保仅使用不在字符串内的那些分隔符。 此外,您必须删除引号,引号可能位于任意位置或在任何地方都找不到。 使用csv模块,您根本不需要更改代码。 而且,由于逗号被视为默认的分隔符,因此甚至无需指定它:
>>> results2 = [fields for fields in csv.reader(open("temp_data_01.csv", newline=''))] >>> results2 [['Notes', 'State', 'State Code', 'Month Day, Year', 'Month Day, Year Code', 'Avg Daily Max Air Temperature (F)', 'Record Count for Daily Max Air Temp (F)', 'Min Temp for Daily Max Air Temp (F)', 'Max Temp for Daily Max Air Temp (F)', 'Avg Daily Min Air Temperature (F)', 'Record Count for Daily Min Air Temp (F)', 'Min Temp for Daily Min Air Temp (F)', 'Max Temp for Daily Min Air Temp (F)', 'Avg Daily Max Heat Index (F)', 'Record Count for Daily Max Heat Index (F)', 'Min for Daily Max Heat Index (F)', 'Max for Daily Max Heat Index (F)', 'Daily Max Heat Index (F) % Coverage'], ['', 'Illinois', '17', 'Jan 01, 1979', '1979/01/01', '17.48', '994', '6.00', '30.50', '2.89', '994', '-13.60', '15.80', 'Missing', '0', 'Missing', 'Missing', '0.00%'], ['', 'Illinois', '17', 'Jan 02, 1979', '1979/01/02', '4.64', '994', '-6.40', '15.80', '-9.03', '994', '-23.60', '6.60', 'Missing', '0', 'Missing', 'Missing', '0.00%'], ['', 'Illinois', '17', 'Jan 03, 1979', '1979/01/03', '11.05', '994', '- 0.70', '24.70', '-2.17', '994', '-18.30', '12.90', 'Missing', '0', 'Missing', 'Missing', '0.00%'], ['', 'Illinois', '17', 'Jan 04, 1979', '1979/01/04', '9.51', '994', '0.20', '27.60', '-0.43', '994', '-16.30', '16.30', 'Missing', '0', 'Missing', 'Missing', '0.00%'], ['', 'Illinois', '17', 'May 15, 1979', '1979/05/15', '68.42', '994', '61.00', '75.10', '51.30', '994', '43.30', '57.00', 'Missing', '0', 'Missing', 'Missing', '0.00%'], ['', 'Illinois', '17', 'May 16, 1979', '1979/05/ 16', '70.29', '994', '63.40', '73.50', '48.09', '994', '41.10', '53.00', 'Missing', '0', 'Missing', 'Missing', '0.00%'], ['', 'Illinois', '17', 'May 17, 1979', '1979/05/17', '75.34', '994', '64.00', '80.50', '50.84', '994', '44.30', '55.70', '82.60', '2', '82.40', '82.80', '0.20%'], ['', 'Illinois', '17', 'May 18, 1979', '1979/05/18', '79.13', '994', '75.50', '82.10', '55.68', '994', '50.00', '61.10', '81.42', '349', '80.20', '83.40', '35.11%'], ['', 'Illinois', '17', 'May 19, 1979', '1979/05/19', '74.94', '994', '66.90', '83.10', '58.59', '994', '50.90', '63.20', '82.87', '78', '81.60', '85.20', '7.85%']]
»有关这本书的更多信息,请访问
出版商的网站»
目录»
摘录小贩优惠券20%优惠-Python