7.Python中不同文件的读取

  1. Csv的读取

对于CSV的读取,python直接提供了csv库,就好比我们有一个如下的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

对于这样一个文件,只需要在外面使用csv包上一层即可

with open(‘stocks.csv’) as f:

f_csv = csv.reader(f)

headers = next(f_csv)

for row in f_csv:

之后对于row,就是一个列表,我们通过row[0] 来访问Symbol,row[4]访问Change

如果想要直接访问,可以考虑使用命名元组

from collections import namedtuple

with 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)

这时候就可以使用row.Symbol或者row.Change来访问了

Csv模块中还支持将文件读取位字典格式

with open(‘stocks.csv’) as f:

f_csv = csv.DictReader(f)

for row in f_csv:

# process row

会形成一个列表,其中每一个item都是一个字典,对应的就是row

当然csv模块也提供了写入功能,不过要先创建一个writer对象

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)

上面我们先写入了一行,header,然后利用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)

需要注意的是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))

如果希望,有更进阶的使用方式,则可以看Pandas包

其中提供了pandas.read_csv() 可以将csv文件中的数据加载到一个DataFrame中

  1. Json文件的读写

Json模块提供了一种很简单的方式来使用Json,只需要json模块下的dumps和loads就可以了

我们简单看一个示例

import json

data = {

‘name’ : ‘ACME’,

‘shares’ : 100,

‘price’ : 542.23

}

json_str = json.dumps(data)

同样loads就可以将其家在为数据结构

对于json和python的数据类型,是有一些差异的,python的json模块也会进行映射

比如True – true,False – false None映射null

>>> json.dumps(False)

‘false’

>>> d = {‘a’: True,

… ‘b’: ‘Hello’,

… ‘c’: None}

>>> json.dumps(d)

‘{“b”: “Hello”, “c”: null, “a”: true}’

>>>

JSON模块一般会根据数据创建lists或者dict,但是如果我们想要创建其他类型的对象,则应该在object_paris_hook或object_hook中设置

如果希望自定义的对象支持反序列化,则可以实现一个init函数,其中接收一个dict对象

>>> class JSONObject:

… def __init__(self, d):

… self.__dict__ = d

>>>

>>> data = json.loads(s, object_hook=JSONObject)

如果希望支持序列化,则应该提供一个函数,输入一个实例,返回一个字典

classes = {

‘Point’ : Point

}

def unserialize_object(d):

clsname = d.pop(‘__classname__’, None)

if clsname:

cls = classes[clsname]

obj = cls.__new__(cls) # Make instance without calling __init__

for key, value in d.items():

setattr(obj, key, value)

return obj

else:

return d

当然,如果希望打印json,则可以考虑使用pprint这个函数进行打印输出

会考虑更加美观的打印方式

  1. 解析XML

如果希望解析XMl

使用xml.etree.ElementTree就可以提取,比如如下代码

# 数据例如

<?xml version=”1.0″?>

<rss version=”2.0″ xmlns:dc=”http://purl.org/dc/elements/1.1/”>

<channel>

<title>Planet Python</title>

<link>http://planet.python.org/</link>

<language>en</language>

<description>Planet Python – http://planet.python.org/</description>

<item>

<title>Steve Holden: Python for Data Analysis</title>

<guid>http://holdenweb.blogspot.com/…-data-analysis.html</guid>

<link>http://holdenweb.blogspot.com/…-data-analysis.html</link>

<description>…</description>

<pubDate>Mon, 19 Nov 2012 02:13:51 +0000</pubDate>

</item>

<item>

<title>Vasudev Ram: The Python Data model (for v2 and v3)</title>

<guid>http://jugad2.blogspot.com/…-data-model.html</guid>

<link>http://jugad2.blogspot.com/…-data-model.html</link>

<description>…</description>

<pubDate>Sun, 18 Nov 2012 22:06:47 +0000</pubDate>

</item>

<item>

<title>Python Diary: Been playing around with Object Databases</title>

<guid>http://www.pythondiary.com/…-object-databases.html</guid>

<link>http://www.pythondiary.com/…-object-databases.html</link>

<description>…</description>

<pubDate>Sun, 18 Nov 2012 20:40:29 +0000</pubDate>

</item>

</channel>

</rss>

from urllib.request import urlopen

from xml.etree.ElementTree import parse

# Download the RSS feed and parse it

u = urlopen(‘http://planet.python.org/rss20.xml’)

doc = parse(u)

# Extract and output tags of interest

for item in doc.iterfind(‘channel/item’):

title = item.findtext(‘title’)

date = item.findtext(‘pubDate’)

link = item.findtext(‘link’)

print(title)

print(date)

print(link)

print()

上面我们首先使用parse解析为一个XML文件

然后从其中的获取到’channel/item’下的数据

并且依次获取到了’title’,’pubDate’,’link’的数据

类似的查找函数有find iterfind findtext查找

而item元素中,tag属性包含了标签的名字,text包含了内部文本,get() 获取了属性值

而类似xml的还有lxml,使用方式一样

除了parse可以获取到数据之外,还有着iterparse可以获取到数据,以一种迭代的,内存占用更少的方式

比如下面代码

def parse_and_remove(filename, path):

path_parts = path.split(‘/’)

doc = iterparse(filename, (‘start’, ‘end’))

# Skip the root element

next(doc)

tag_stack = []

elem_stack = []

for event, elem in doc:

if event == ‘start’:

tag_stack.append(elem.tag)

elem_stack.append(elem)

elif event == ‘end’:

if tag_stack == path_parts:

yield elem

elem_stack[-2].remove(elem)

try:

tag_stack.pop()

elem_stack.pop()

except IndexError:

pass

我们在代码中不断的遍历,并且在其中指定了事件列表,包含starth额end

Start对应某一个元素刚遇见,end则表示已经创建完成元素

我们就当遇到end的时候,返回着这个元素,然后将其从数组中移除

elem_stack[-2].remove(elem)

这时候因为没有引用了,就会被自动移除,从而减少内存占用

那么我们是否可以插入XML呢,或者说创建XML文档?

当然可以,利用Element对象即可

from xml.etree.ElementTree import Element

def dict_to_xml(tag, d):

”’

Turn a simple dict of key/value pairs into XML

”’

elem = Element(tag)

for key, val in d.items():

child = Element(key)

child.text = str(val)

elem.append(child)

return elem

我们直接创建了一个Element,然后在下面添加了数据

那么我们有了Element之后,如何进行XML的插入修改呢?

只需要考虑使用其中的insert函数即可

比如

>>> e = Element(‘spam’)

>>> e.text = ‘This is a test’

>>> root.getchildren().index(root.find(‘nm’))

1

>>> root = doc.getroot()

>>> root.insert(root.getchildren().index(root.find(‘nm’))+ 1, e)

移除则是

>>> root.remove(root.find(‘sri’))

>>> root.remove(root.find(‘cr’))

最后写入直接是利用parse后的对象进行write

>>> doc.write(‘newpred.xml’, xml_declaration=True)

  1. 数据库的交互

如果想要和数据库进行交互的话,python中都提供了不同的库进行使用

比如我们希望连接sqllite,则可以使用python标准库中的sqlite3,如果是使用不同的数据库,则还需要安装不同的第三方库

首先是连接到数据库,通常要执行connect() 函数,提供一些数据库名,主机,用户名等信息,不过sqlite比较简单

>>> import sqlite3

>>> db = sqlite3.connect(‘database.db’)

然后我们希望执行语句的话,直接使用execute即可

>>> c = db.cursor()

>>> c.execute(‘create table portfolio (symbol text, shares integer, price real)’)

<sqlite3.Cursor object at 0x10067a730>

>>> db.commit()

如果希望插入多条数据的话,则可以考虑如下语句

>>> c.executemany(‘insert into portfolio values (?,?,?)’, stocks)

<sqlite3.Cursor object at 0x10067a730>

>>> db.commit()

其中的stocks是一个序列,序列中包含的每一个元素都是一个元组,正好三个

如果是希望获取到查询结果,sqlite中直接,可以

>>> for row in db.execute(‘select * from portfolio’):

print(row)

并且也支持使用 ? 作为占位符

不过需要注意的是python中的数据类型和数据库中的数据类型的映射

不同的数据库的映射规则是不一样的

如果希望能够更高层次的抽象不同数据库的差异,可以考虑使用ORM框架,比如SQLAlchemy这样的库,可以以一个类的方式映射一个数据库表

  1. 编解码十六进制数

如果希望将十六进制的字符串解码为一个字节字符串或者将一个字节字符串编码为一个十六进制字符串

如果是简单的编解码的话,使用binascii即可

>>> s = b’hello’

>>> import binascii

>>> h = binascii.b2a_hex(s)

>>> h

b’68656c6c6f’

>>> binascii.a2b_hex(h)

b’hello’

或者是使用base64模块也可以做到,其中包含了b16encode,b16decode可以进行解码和编码

需要注意的是b16decode和a2b_hex都可以接受字节以及unicode字符串,但是对于unicode 字符串,必须要求只包含ASCII编码的十六进制数

同理,Base64其中的b64encode和b64decode更加符合之前使用base64的习惯

>>> s = b’hello’

>>> import base64

>>> a = base64.b64encode(s)

>>> a

b’aGVsbG8=’

>>> base64.b64decode(a)

b’hello’

别忘了将字节转换为字符串需要进行decode

  1. 简单介绍下pandas

我们这里简单介绍下Pandas库,支持分析大量数据

>>> import pandas

>>> # Read a CSV file, skipping last line

# 读取

>>> rats = pandas.read_csv(‘rats.csv’, skip_footer=1)

>>> rats

<class ‘pandas.core.frame.DataFrame’>

Int64Index: 74055 entries, 0 to 74054

Data columns:

Creation Date 74055 non-null values

Status 74055 non-null values

Completion Date 72154 non-null values

Service Request Number 74055 non-null values

Type of Service Request 74055 non-null values

Number of Premises Baited 65804 non-null values

Number of Premises with Garbage 65600 non-null values

Number of Premises with Rats 65752 non-null values

Current Activity 66041 non-null values

Most Recent Action 66023 non-null values

Street Address 74055 non-null values

ZIP Code 73584 non-null values

X Coordinate 74043 non-null values

Y Coordinate 74043 non-null values

Ward 74044 non-null values

Police District 74044 non-null values

Community Area 74044 non-null values

Latitude 74043 non-null values

Longitude 74043 non-null values

Location 74043 non-null values

dtypes: float64(11), object(9)

>>> # Investigate range of values for a certain field

>>> rats[‘Current Activity’].unique()

array([nan, Dispatch Crew, Request Sanitation Inspector], dtype=object)

>>> # Filter the data

# 直接过滤

>>> crew_dispatched = rats[rats[‘Current Activity’] == ‘Dispatch Crew’]

# 获取数量

>>> len(crew_dispatched)

65676

>>>

# 聚合统计zip code

>>> # Find 10 most rat-infested ZIP codes in Chicago

>>> crew_dispatched[‘ZIP Code’].value_counts()[:10]

60647 3837

60618 3530

60614 3284

60629 3251

60636 2801

60657 2465

60641 2238

60609 2206

60651 2152

60632 2071

>>>

>>> # Group by completion date

# 根据日期进行聚合

>>> dates = crew_dispatched.groupby(‘Completion Date’)

<pandas.core.groupby.DataFrameGroupBy object at 0x10d0a2a10>

>>> len(dates)

472

>>>

>>> # Determine counts on each day

>>> date_counts = dates.size()

>>> date_counts[0:10]

Completion Date

01/03/2011 4

01/03/2012 125

01/04/2011 54

01/04/2012 38

01/05/2011 78

01/05/2012 100

01/06/2011 100

01/06/2012 58

01/07/2011 1

01/09/2012 12

>>>

# 排序后获取前十个

>>> # Sort the counts

>>> date_counts.sort()

>>> date_counts[-10:]

Completion Date

10/12/2012 313

10/21/2011 314

09/20/2011 316

10/26/2011 319

02/22/2011 325

10/26/2012 333

03/17/2011 336

10/13/2011 378

10/14/2011 391

10/07/2011 457

>>>

发表评论

邮箱地址不会被公开。 必填项已用*标注