Python之数据载入、存储及文件格式(2)

本博客为《利用Python进行数据分析》的读书笔记,请勿转载用于其他商业用途。

1. 分块读入文本文件

当处理大型文件或找出正确的参数集来正确处理大文件时,我们可能需要读入文件的一个小片段或者按小块遍历文件。
在尝试大文件之前,我们可以先对pandas的现实设置进行调整,使之更为紧凑:

pd.options.display.max_rows = 10

现在我们可以得到:

result = pd.read_csv('C:/ex6.csv')
print(result)
#
      one    two  three   four key
0    0.12  -0.34   0.56  -0.78   A
1    1.12   0.66   1.56   0.22   J
2    2.12   1.66   2.56   1.22   L
3    3.12   2.66   3.56   2.22   F
4    4.12   3.66   4.56   3.22   B
..    ...    ...    ...    ...  ..
94  94.12  93.66  94.56  93.22   T
95  95.12  94.66  95.56  94.22   R
96  96.12  95.66  96.56  95.22   E
97  97.12  96.66  97.56  96.22   W
98  98.12  97.66  98.56  97.22   Q

[99 rows x 5 columns]

如果你只想读取一小部分(避免读取整个文件),可以指明nrows

result = pd.read_csv('C:/ex6.csv', nrows=5)
print(result)
#
    one   two  three  four key
0  0.12 -0.34   0.56 -0.78   A
1  1.12  0.66   1.56  0.22   J
2  2.12  1.66   2.56  1.22   L
3  3.12  2.66   3.56  2.22   F
4  4.12  3.66   4.56  3.22   B

为了分块读入文件,可以指定chunksize作为每一块的行数:

chunker = pd.read_csv('ex6.csv', chunksize=50)
print(chunker)
#
<pandas.io.parsers.TextFileReader object at 0x02F6F8B0>

read_csv返回的TextParser对象允许你根据chunksize遍历文件。例如,我们可以遍历ex6.csv,并对’key’列聚合获得计数值:

chunker = pd.read_csv('ex6.csv', chunksize=50)
tot = pd.Series([])
for piece in chunker:
    tot = tot.add(piece['key'].value_counts(), fill_value=0)
tot = tot.sort_values(ascending=False)
print(tot[:10])

#
L    13.0
R    11.0
E    11.0
Y     6.0
T     6.0
Q     6.0
W     6.0
I     5.0
C     5.0
G     5.0
dtype: float64

该代码的意思是,在key列中,以上字母共出现了多少次。
TextParser还具有get_chunk方法,允许你按照任意大小读取数据块。

2. 将数据写入文本格式

数据可以导出为分隔的形式:

data = pd.read_csv('ex5.csv')
print(data)

#
  something  a   b     c   d message
0       one  1   2   3.0   4     NaN
1       two  5   6   NaN   8   world
2     three  9  10  11.0  12     foo

使用DataFrame的to_csv方法,我们可以将数据导出为逗号分隔的文件:
略。
当然,其他的分隔符也是可以的(写入到sys.stdout时,控制台中打印机的文本结果):

import sys
result = data.to_csv(sys.stdout, sep='|')
print(result)

#
|Unnamed: 0|something|a|b|c|d|message
0|0|one|1|2|3.0|4|
1|1|two|5|6||8|world
2|2|three|9|10|11.0|12|foo

缺失值在输出时以空字符串出现。你也许想要用其他标识值对缺失值进行标注:

result = data.to_csv(sys.stdout, na_rep='NULL')
print(result)

#
,Unnamed: 0,something,a,b,c,d,message
0,0,one,1,2,3.0,4,NULL
1,1,two,5,6,NULL,8,world
2,2,three,9,10,11.0,12,foo

如果没有其他按选项被指定的话,行和列的标签都会被写入。不过二者也都可以禁止写入:

result = data.to_csv(sys.stdout, index=False, header=False)
print(result)

#
0,one,1,2,3.0,4,
1,two,5,6,,8,world
2,three,9,10,11.0,12,foo
None

你也可以仅写入列的子集,并且按照你选择的顺序写入:

result = data.to_csv(sys.stdout, index=False, columns=['a', 'b', 'c'])
print(result)

#
a,b,c
1,2,3.0
5,6,
9,10,11.0
None

3. 使用分隔格式

绝大多数的表型数据都可以使用函数pandas.read_table从硬盘中读出。然而,在某些情况下,一些手动操作可能是必不可少的。接受一个带有一行或者多行错误的文件并不少见,read_table也无法解决这种情况。为了介绍一些基础工具,考虑如下的小型csv文件:
Python之数据载入、存储及文件格式(2)
对于任何带有单字符分隔符的文件,我们可以使用Python内置的内建csv模块。要使用它,需要将任一打开的文件或文件类型对象传给csv.reader

import csv
f = open('ex7.csv')
reader = csv.reader(f)

像遍历文件那样遍历reader会产生元组,元组的值为删除了引号的字符:

import csv
f = open('ex7.csv')
reader = csv.reader(f)
for line in reader:
    print(line)
    
#
['"a"', '"b"', '"c"']
['"1"', '"2"', '"3"']
['"1"', '"2"', '"3"']    

按照书中的操作,理论上应该得到去掉双引号的字符,然而事实并不是这样的……不管了,我们继续。

表:CSV方言选项

参数 描述
delimiter 一个用于分隔字段的字符,默认是‘,’
lineterminator 行终止符,默认是‘\r\n’,读取器会忽略行终止符并识别跨平台行终止符
quotechar 用在含有特殊字符字段中的引号,默认是’ " ’
quoting 引用惯例。选项包括csv.QUOTE_ALL(引用所有的字段),cdv.QUOTE_MINIMAL(只使用特殊字符,如分隔符),csv.QUOTE_NONNUMERICcsv.QUOTE_NONE(不引用)。细节请参考Python的文档。默认是QUOTE_MINIMAL
skipinitialspace 忽略每个分隔符后的空白,默认是False
doublequote 如何处理字段内部的引号。如果为True,则是双引号
escapechar 当引用设置为csv.QUOTE_NONE时用于转移分隔符的字符串,默认是禁用的

对于具有更复杂或固定的多字符分隔符的文件,你将无法使用csv模块。在此类情况下,你将不得不使用字符串的split方法或正则表达式方法re.split进行行拆分和其他清理工作。

需要手动写入被分隔的文件时,可以使用csv.writer。这个函数接受一个已经打开的可写入文件对象以及和csv.reader相同的CSV方言、格式选项:

with open('mydata.csv', 'w')as f:
    writer = csv.writer(f, dialect=my_dialect)
    writer.writerow(('one', 'two', 'three'))
    writer.writerow(('1', '2', '3'))
    writer.writerow(('4', '5', '6'))
    writer.writerow(('7', '8', '9'))

4. JSON数据

JSON(JavaScript Object Notation)已经成为Web浏览器和其他应用间通过HTTP请求发送数据的标准格式。它是一种比CSV表格文本形式更为*的数据形式。请看下面的例子:

obj = """
{"name":"Wes",
"places_lived": ["United States", "Spain", "Germany"],
"pet": null
"siblings":[{"name":"Scott", "age":30, "pets":["Zeus", "Zuko"]},
            {"name":"Katie", "age":38,
            "pets":["Sixes", "Stache", "Cisco"]}]
}
"""

JSON非常接近有效的Python代码,除了它的值null和一些其他的细微差别(例如不允许列表末尾的逗号)之外。基本类型是对象(字典)、数组(列表)、字符串、数字、布尔值和空值。对象中的所有键必须是字符串。有几个Python库用于读写JSON数据。我们将在这里使用json,因为它是内置在Python标准库中的。将JSON字符串转换为Python时,使用json.loads方法:

import json
result = json.loads(obj)
print(result)

#
{'name': 'Wes', 'places_lived': ['United States', 'Spain', 'Germany'],
'pet': None, 'siblings': [{'name': 'Scott', 'age': 30, 'pets': ['Zeus', 'Zuko']},
{'name': 'Katie', 'age': 38, 'pets': ['Sixes', 'Stache', 'Cisco']}]}

另一方面,json.dumps方法可以将Python对象转换为JSON:

asjson = json.dumps(result)

你将自行决定如何将JSON对象或对象列表转换为DataFrame或其他数据结构。比较方便的方式是将字典构成的列表(之前是JSON对象)传入DataFrame构造函数,并选出数据字段的子集:

siblings = pd.DataFrame(result['siblings'], columns=['name', 'age'])
print(siblings)

#
    name  age
0  Scott   30
1  Katie   38

pandas.read_json可以自动将JSON数据集按照指定次序转换为Series或DataFrame。
首先我们创建一个JSON文件:
Python之数据载入、存储及文件格式(2)
pandas.read_json的默认选项是假设JSON数组中的没个对象是表里的一行:

data = pd.read_csv('example.json')
print(data)
#
   [{"a": 1   "b": 2    "c": 3}  Unnamed: 3
0   {"a": 4   "b": 5    "c": 6}         NaN
1   {"a": 7   "b": 8   "c": 9}]         NaN

得到是这个鬼东西……跟书上的不一样啊……算了……
如果需要从pandas中将数据导出为JSON,一种办法是对Series和DataFrame使用to_json方法:

print(data.to_json())

5. XML和HTML:网络抓取

Python拥有很多可以对HTML和XML格式进行读取、写入数据的库。例如lxml、Beautiful Soup和htmal5lib。尽管lxml是相对更快的库,但其他库可以更好地处理异常的HTML和XML文件。
pandas的内建函数read_hml可以使用lxml和Beautiful Soup等库将HTML中的表自动解析为DataFrame对象。为了展示这个功能,我们从美国FDIC*机构下载了显示银行倒闭数据的HTML文件(在pandas文档中使用)。
Python之数据载入、存储及文件格式(2)
pandas.read_html函数有很多选项,但是默认情况下,它会搜索并尝试解析所有包含在<table>标签中的表格型数据,返回的结果是DataFrame对象的列表:

tables = pd.read_html('FDIC_ Failed Bank List.html')
print(len(tables))

#
1
failures = tables[0]
print(failures)
#
 Bank Name  ...       Closing Date
0       City National Bank of New Jersey  ...   November 1, 2019
1                          Resolute Bank  ...   October 25, 2019
2                  Louisa Community Bank  ...   October 25, 2019
3                   The Enloe State Bank  ...       May 31, 2019
4    Washington Federal Bank for Savings  ...  December 15, 2017
..                                   ...  ...                ...
554                   Superior Bank, FSB  ...      July 27, 2001
555                  Malta National Bank  ...        May 3, 2001
556      First Alliance Bank & Trust Co.  ...   February 2, 2001
557    National State Bank of Metropolis  ...  December 14, 2000
558                     Bank of Honolulu  ...   October 13, 2000

[559 rows x 6 columns]

以上是Pycharm显示的结果,我们再看下Conda显示的结果:
Python之数据载入、存储及文件格式(2)
我去,爱了爱了……
此处我们可以着手一些数据清理和分析工作,比如计算每年银行倒闭的数量:

close_timestamps = pd.to_datetime(failures['Closing Date'])
print(close_timestamps.dt.year.value_counts())

#
2010    157
2009    140
2011     92
2012     51
2008     25
2013     24
2014     18
2002     11
2015      8
2017      8
2016      5
2001      4
2019      4
2004      4
2003      3
2007      3
2000      2
Name: Closing Date, dtype: int64
Python之数据载入、存储及文件格式(2)Python之数据载入、存储及文件格式(2) Chrishany 发布了23 篇原创文章 · 获赞 6 · 访问量 496 私信 关注
上一篇:Java学习第二十五天


下一篇:Java学习之线程间通讯