如何将带有索引的Pandas DataFrame写入SQLite数据库

49

我有一个从雅虎财经上拉取的股票市场数据列表,存储在pandas的DataFrame中(格式如下)。日期作为DataFrame中的索引。我想将数据(包括索引)写入SQLite数据库。

             AAPL     GE
Date
2009-01-02  89.95  14.76
2009-01-05  93.75  14.38
2009-01-06  92.20  14.58
2009-01-07  90.21  13.93
2009-01-08  91.88  13.95

根据我对Pandas中write_frame代码的阅读,目前不支持写入索引。我尝试使用to_records代替,但遇到Numpy 1.6.2和日期时间问题。现在我正在尝试使用.itertuples编写元组,但SQLite报错,表示不支持该数据类型(请参见下面的代码和结果)。我对Python、Pandas和Numpy相对较新,因此完全有可能我会忽略一些明显的东西。我认为我正在尝试将日期时间写入SQLite时遇到问题,但我认为我可能过于复杂化了这个问题。

我认为我可以通过升级到Numpy 1.7或Pandas的开发版本来解决此问题,该版本已在GitHub上发布了修复程序。我更喜欢使用软件的发布版本进行开发-我对此还很陌生,我不想使稳定性问题进一步混淆事情。

是否有一种方法可以使用Python 2.7.2、Pandas 0.10.0和Numpy 1.6.2来完成此操作?也许可以对日期时间进行清理?我有点超出自己的能力,任何帮助都将不胜感激。

代码:

import numpy as np
import pandas as pd
from pandas import DataFrame, Series
import sqlite3 as db

# download data from yahoo
all_data = {}

for ticker in ['AAPL', 'GE']:
    all_data[ticker] = pd.io.data.get_data_yahoo(ticker, '1/1/2009','12/31/2012')

# create a data frame
price = DataFrame({tic: data['Adj Close'] for tic, data in all_data.iteritems()})

# get output ready for database export
output = price.itertuples()
data = tuple(output)

# connect to a test DB with one three-column table titled "Demo"
con = db.connect('c:/Python27/test.db')
wildcards = ','.join(['?'] * 3)
insert_sql = 'INSERT INTO Demo VALUES (%s)' % wildcards
con.executemany(insert_sql, data)

结果:

---------------------------------------------------------------------------
InterfaceError                            Traceback (most recent call last)
<ipython-input-15-680cc9889c56> in <module>()
----> 1 con.executemany(insert_sql, data)

InterfaceError: Error binding parameter 0 - probably unsupported type.

如果您只是想要在表格中将索引作为一列,那您不仅可以为DataFrame添加一个与索引重复的列吗? - BrenBarn
5个回答

68
最近的pandas中,索引将保存在数据库中(以前必须先reset_index)。
根据docs(在内存中设置SQLite连接):
import sqlite3
# Create your connection.
cnx = sqlite3.connect(':memory:')

注意:您也可以在此处传递SQLAlchemy引擎(请参见答案末尾)。
我们可以将price2保存到cnx中:
price2.to_sql(name='price2', con=cnx)

我们可以通过read_sql检索:

p2 = pd.read_sql('select * from price2', cnx)

然而,当存储(和检索)日期时,它们是unicode而不是Timestamp。要将其转换回我们开始的格式,我们可以使用pd.to_datetime

p2.Date = pd.to_datetime(p2.Date)
p = p2.set_index('Date')

我们得到与prices相同的DataFrame:
In [11]: p2
Out[11]: 
<class 'pandas.core.frame.DataFrame'>
DatetimeIndex: 1006 entries, 2009-01-02 00:00:00 to 2012-12-31 00:00:00
Data columns:
AAPL    1006  non-null values
GE      1006  non-null values
dtypes: float64(2)

你可以使用SQLAlchemy引擎
from sqlalchemy import create_engine
e = create_engine('sqlite://')  # pass your db url

price2.to_sql(name='price2', con=cnx)

这将使您能够使用read_sql_table(只能与SQLAlchemy一起使用):
pd.read_sql_table(table_name='price2', con=e)
#         Date   AAPL     GE
# 0 2009-01-02  89.95  14.76
# 1 2009-01-05  93.75  14.38
# 2 2009-01-06  92.20  14.58
# 3 2009-01-07  90.21  13.93
# 4 2009-01-08  91.88  13.95

2
在我看来,price2.to_sql(name='price2', con=cnx) 应该改为 price2.to_sql(name='price2', con=e)。否则,price2 数据怎么会出现在对应于“传递您的数据库URL”的磁盘SQLite数据库中,以便可以通过 read_sql_table 检索呢?无论如何,这对我来说是有效的。虽然我觉得自2013年以来没有人明显地评论过这一点,这让我感到困惑。 - Faheem Mitha

21

很遗憾,pandas.io.write_frame在Pandas的更新版本中不再存在,这与当前被接受的答案有关。例如,我正在使用的是pandas 0.19.2。你可以做类似以下的操作:

from sqlalchemy import create_engine

disk_engine = create_engine('sqlite:///my_lite_store.db')
price.to_sql('stock_price', disk_engine, if_exists='append')

然后使用以下内容预览您的表格:

df = pd.read_sql_query('SELECT * FROM stock_price LIMIT 3',disk_engine)
df.head()

if_exists='append' 可以帮助防止 ValueError: Table 'abc' already exists 的错误,非常有用,谢谢。 - Cam

16

以下是对我有效的代码。我能够将其写入SQLite数据库。

import pandas as pd
import sqlite3 as sq
data = <This is going to be your pandas dataframe>
sql_data = 'D:\\SA.sqlite' #- Creates DB names SQLite
conn = sq.connect(sql_data)
cur = conn.cursor()
cur.execute('''DROP TABLE IF EXISTS SA''')
data.to_sql('SA', conn, if_exists='replace', index=False) # - writes the pd.df to SQLIte DB
pd.read_sql('select * from SentimentAnalysis', conn)
conn.commit()
conn.close()

9

使用sqlite3的最简示例

参考Keertesh Kumar的答案

将df写入sqlite

import pandas as pd
import sqlite3 as sq

df = pd.DataFrame({'col1': [1, 2], 'col2': [3, 4]})
table_name = "test" # table and file name

conn = sq.connect('{}.sqlite'.format(table_name)) # creates file
df.to_sql(table_name, conn, if_exists='replace', index=False) # writes to file
conn.close() # good practice: close connection

读取SQLite到数据框中

conn = sq.connect('{}.sqlite'.format(table_name))
df = pd.read_sql('select * from {}'.format(table_name), conn)
conn.close()

1
Pandas的read_sql可以为您设置索引。
Andy Hayden上面的答案为例,不需要:
p2 = pd.read_sql('select * from price2', cnx)
# When stored (and retrieved) dates are unicode rather than Timestamp. 
# Convert back to what we started with we can use pd.to_datetime:
p2.Date = pd.to_datetime(p2.Date)
p2 = p2.set_index('Date')

您可以简单地这样做:
p2 = pd.read_sql('select * from price2', cnx, index_col='Date', parse_dates=['Date'])

这将自动将日期列设置为索引,并同时将其转换为时间戳。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接