使用数据库
在许多应用中,数据很少取自文本文件,因为用这种方式存储大量数据很低效。基于SQL的关系型数据库(如SQL Server、PostgreSQL和MySQL等)使用非常广泛,此外还有一些非SQL(即所谓的NoSQL)型数据库也变得非常流行。数据库的选择通常取决于性能、数据完整性以及应用程序的伸缩性需求。
将数据从SQL加载到DataFrame的过程很简单,此外pandas还有一些能够简化该过程的函数。例如,我将使用一款嵌入式的SQLite数据库(通过Python内置的sqlite3驱动器):
- import sqlite3
- query = """
- CREATE TABLE test
- (a VARCHAR(20), b VARCHAR(20),
- c REAL, d INTEGER
- );"""
- con = sqlite3.connect(':memory:')
- con.execute(query)
- con.commit()
然后插入几行数据:
- data = [('Atlanta', 'Georgia', 1.25, 6),
- ('Tallahassee', 'Florida', 2.6, 3),
- ('Sacramento', 'California', 1.7, 5)]
- stmt = "INSERT INTO test VALUES(?, ?, ?, ?)"
- con.executemany(stmt, data)
- con.commit()
从表中选取数据时,大部分Python SQL驱动器(PyODBC、psycopg2、MySQLdb、pymssql等)都会返回一个元组列表:
- In [956]: cursor = con.execute('select * from test')
- In [957]: rows = cursor.fetchall()
- In [958]: rows
- Out[958]:
- [(u'Atlanta', u'Georgia', 1.25, 6),
- (u'Tallahassee', u'Florida', 2.6, 3),
- (u'Sacramento', u'California', 1.7, 5)]
你可以将这个元组列表传给DataFrame的构造器,但还需要列名(位于游标的description属性中):
- In [959]: cursor.description
- Out[959]:
- (('a', None, None, None, None, None, None),
- ('b', None, None, None, None, None, None),
- ('c', None, None, None, None, None, None),
- ('d', None, None, None, None, None, None))
- In [960]: DataFrame(rows, columns=zip(*cursor.description)[0])
- Out[960]:
- a b c d
- 0 Atlanta Georgia 1.25 6
- 1 Tallahassee Florida 2.60 3
- 2 Sacramento California 1.70 5
这种数据规整操作相当多,你肯定不想每查一次数据库就重写一次。pandas有一个可以简化该过程的read_frame函数(位于pandas.io.sql模块)。只需传入select语句和连接对象即可:
- In [961]: import pandas.io.sql as sql
- In [962]: sql.read_frame('select * from test', con)
- Out[962]:
- a b c d
- 0 Atlanta Georgia 1.25 6
- 1 Tallahassee Florida 2.60 3
- 2 Sacramento California 1.70 5
存取MongoDB中的数据
NoSQL数据库有许多不同的形式。有些是简单的字典式键值对存储(如BerkeleyDB和Tokyo Cabinet),另一些则是基于文档的(其中的基本单元是字典型的对象)。本例选用的是MongoDB(http://mongodb.org)。我先在自己的电脑上启动一个MongoDB实例,然后用pymongo(MongoDB的官方驱动器)通过默认端口进行连接:
- import pymongo
- con = pymongo.Connection('localhost', port=27017)
存储在MongoDB中的文档被组织在数据库的集合(collection)译注8中。MongoDB服务器的每个运行实例可以有多个数据库,而每个数据库又可以有多个集合。假设你想保存之前通过Twitter API获取的数据。首先,我可以访问tweets集合(暂时还是空的):
- tweets = con.db.tweets
然后,我将那组tweet加载进来并通过tweets.save(用于将Python字典写入MongoDB)逐个存入集合中:
- import requests, json
- url = 'http://search.twitter.com/search.json?q=python%20pandas'
- data = json.loads(requests.get(url).text)
- for tweet in data['results']:
- tweets.save(tweet)
现在,如果我想从该集合中取出我自己发的tweet(如果有的话),可以用下面的代码对集合进行查询:
- cursor = tweets.find({'from_user': 'wesmckinn'})
返回的游标是一个迭代器,它可以为每个文档产生一个字典。跟之前一样,我可以将其转换为一个DataFrame。此外,还可以只获取各tweet的部分字段:
- tweet_fields = ['created_at', 'from_user', 'id', 'text']
- result = DataFrame(list(cursor), columns=tweet_fields)
译注8:如果实在不明白,可直接想象成表。