使用数据库

在许多应用中,数据很少取自文本文件,因为用这种方式存储大量数据很低效。基于SQL的关系型数据库(如SQL Server、PostgreSQL和MySQL等)使用非常广泛,此外还有一些非SQL(即所谓的NoSQL)型数据库也变得非常流行。数据库的选择通常取决于性能、数据完整性以及应用程序的伸缩性需求。

将数据从SQL加载到DataFrame的过程很简单,此外pandas还有一些能够简化该过程的函数。例如,我将使用一款嵌入式的SQLite数据库(通过Python内置的sqlite3驱动器):

  1. import sqlite3
  2.  
  3. query = """
  4. CREATE TABLE test
  5. (a VARCHAR(20), b VARCHAR(20),
  6. c REAL, d INTEGER
  7. );"""
  8. con = sqlite3.connect(':memory:')
  9. con.execute(query)
  10. con.commit()

然后插入几行数据:

  1. data = [('Atlanta', 'Georgia', 1.25, 6),
  2.      ('Tallahassee', 'Florida', 2.6, 3),
  3.      ('Sacramento', 'California', 1.7, 5)]
  4. stmt = "INSERT INTO test VALUES(?, ?, ?, ?)"
  5.  
  6. con.executemany(stmt, data)
  7. con.commit()

从表中选取数据时,大部分Python SQL驱动器(PyODBC、psycopg2、MySQLdb、pymssql等)都会返回一个元组列表:

  1. In [956]: cursor = con.execute('select * from test')
  2.  
  3. In [957]: rows = cursor.fetchall()
  4.  
  5. In [958]: rows
  6. Out[958]:
  7. [(u'Atlanta', u'Georgia', 1.25, 6),
  8. (u'Tallahassee', u'Florida', 2.6, 3),
  9. (u'Sacramento', u'California', 1.7, 5)]

你可以将这个元组列表传给DataFrame的构造器,但还需要列名(位于游标的description属性中):

  1. In [959]: cursor.description
  2. Out[959]:
  3. (('a', None, None, None, None, None, None),
  4. ('b', None, None, None, None, None, None),
  5. ('c', None, None, None, None, None, None),
  6. ('d', None, None, None, None, None, None))
  7.  
  8. In [960]: DataFrame(rows, columns=zip(*cursor.description)[0])
  9. Out[960]:
  10. a b c d
  11. 0 Atlanta Georgia 1.25 6
  12. 1 Tallahassee Florida 2.60 3
  13. 2 Sacramento California 1.70 5

这种数据规整操作相当多,你肯定不想每查一次数据库就重写一次。pandas有一个可以简化该过程的read_frame函数(位于pandas.io.sql模块)。只需传入select语句和连接对象即可:

  1. In [961]: import pandas.io.sql as sql
  2.  
  3. In [962]: sql.read_frame('select * from test', con)
  4. Out[962]:
  5. a b c d
  6. 0 Atlanta Georgia 1.25 6
  7. 1 Tallahassee Florida 2.60 3
  8. 2 Sacramento California 1.70 5

存取MongoDB中的数据

NoSQL数据库有许多不同的形式。有些是简单的字典式键值对存储(如BerkeleyDB和Tokyo Cabinet),另一些则是基于文档的(其中的基本单元是字典型的对象)。本例选用的是MongoDB(http://mongodb.org)。我先在自己的电脑上启动一个MongoDB实例,然后用pymongo(MongoDB的官方驱动器)通过默认端口进行连接:

  1. import pymongo
  2. con = pymongo.Connection('localhost', port=27017)

存储在MongoDB中的文档被组织在数据库的集合(collection)译注8中。MongoDB服务器的每个运行实例可以有多个数据库,而每个数据库又可以有多个集合。假设你想保存之前通过Twitter API获取的数据。首先,我可以访问tweets集合(暂时还是空的):

  1. tweets = con.db.tweets

然后,我将那组tweet加载进来并通过tweets.save(用于将Python字典写入MongoDB)逐个存入集合中:

  1. import requests, json
  2. url = 'http://search.twitter.com/search.json?q=python%20pandas'
  3. data = json.loads(requests.get(url).text)
  4.  
  5. for tweet in data['results']:
  6. tweets.save(tweet)

现在,如果我想从该集合中取出我自己发的tweet(如果有的话),可以用下面的代码对集合进行查询:

  1. cursor = tweets.find({'from_user': 'wesmckinn'})

返回的游标是一个迭代器,它可以为每个文档产生一个字典。跟之前一样,我可以将其转换为一个DataFrame。此外,还可以只获取各tweet的部分字段:

  1. tweet_fields = ['created_at', 'from_user', 'id', 'text']
  2. result = DataFrame(list(cursor), columns=tweet_fields)

译注8:如果实在不明白,可直接想象成表。