2013-09-04 7 views
15

मैं एक sqlite3 डेटाबेस में लगभग 1000 फ्लोट्स की एक numpy सरणी को स्टोर करने की कोशिश कर रहा हूं, लेकिन मुझे त्रुटि मिल रही है "इंटरफ़ेस त्रुटि: त्रुटि बाध्यकारी पैरामीटर 1 - शायद असमर्थित प्रकार"।Python sqlite3 डेटाबेस में numpy सरणी डालें

मैं इंप्रेशन के तहत था कि एक बीएलओबी डेटा प्रकार कुछ भी हो सकता है लेकिन यह निश्चित रूप से एक numpy सरणी के साथ काम नहीं करता है। यहां मैंने कोशिश की है:

import sqlite3 as sql 
import numpy as np 
con = sql.connect('test.bd',isolation_level=None) 
cur = con.cursor() 
cur.execute("CREATE TABLE foobar (id INTEGER PRIMARY KEY, array BLOB)") 
cur.execute("INSERT INTO foobar VALUES (?,?)", (None,np.arange(0,500,0.5))) 
con.commit() 

क्या कोई अन्य मॉड्यूल है जिसका उपयोग मैं तालिका में numpy सरणी प्राप्त करने के लिए कर सकता हूं? या क्या मैं पाइथन में किसी अन्य रूप में numpy सरणी को परिवर्तित कर सकता हूं (जैसे एक सूची या स्ट्रिंग जिसे मैं विभाजित कर सकता हूं) कि स्क्लाइट स्वीकार करेगा? प्रदर्शन प्राथमिकता नहीं है। मैं बस इसे काम करना चाहता हूँ!

धन्यवाद!

+0

पता नहीं है, लेकिन सूची बदलने की कोशिश? np.arange (1000) .tolist() – reptilicus

+0

या शायद json.dumps (np.arange (1000) .tolist()) – reptilicus

उत्तर

23

आप sqlite3 के साथ एक नया array डेटा प्रकार रजिस्टर कर सकते हैं:

import sqlite3 
import numpy as np 
import io 

def adapt_array(arr): 
    """ 
    http://stackoverflow.com/a/31312102/190597 (SoulNibbler) 
    """ 
    out = io.BytesIO() 
    np.save(out, arr) 
    out.seek(0) 
    return sqlite3.Binary(out.read()) 

def convert_array(text): 
    out = io.BytesIO(text) 
    out.seek(0) 
    return np.load(out) 


# Converts np.array to TEXT when inserting 
sqlite3.register_adapter(np.ndarray, adapt_array) 

# Converts TEXT to np.array when selecting 
sqlite3.register_converter("array", convert_array) 

x = np.arange(12).reshape(2,6) 

con = sqlite3.connect(":memory:", detect_types=sqlite3.PARSE_DECLTYPES) 
cur = con.cursor() 
cur.execute("create table test (arr array)") 
इस स्थापना के साथ

, तो आप बस वाक्य रचना में कोई परिवर्तन नहीं NumPy सरणी सम्मिलित कर सकते हैं :

cur.execute("insert into test (arr) values (?)", (x,)) 

और सीधे सर से सरणी पुनर्प्राप्त करें एक NumPy सरणी के रूप में लाइट:

cur.execute("select arr from test") 
data = cur.fetchone()[0] 

print(data) 
# [[ 0 1 2 3 4 5] 
# [ 6 7 8 9 10 11]] 
print(type(data)) 
# <type 'numpy.ndarray'> 
+6

यह मेरे लिए बहुत अच्छा काम करता है। बस दूसरों के लिए स्पष्ट करने के लिए, कनेक्शन detect_types = sqlite3.PARSE_DECLTYPES विकल्प के साथ कनेक्शन खोला जाना चाहिए क्योंकि मैं परेशानी में भाग गया क्योंकि मैं इसे अंदर रखना भूल गया था। –

+0

सुंदर! धन्यवाद! –

+0

वह 'बफर' टूटता है 3.x संगतता (जो कोड में ऐसा करने के लिए एक अजीब चीज है जो 'io' मॉड्यूल और' प्रिंट 'को फ़ंक्शन के रूप में उपयोग करती है), और यह मेरे 2.7 में आवश्यक नहीं प्रतीत होता है। 6 या 2.7.9। हो सकता है कि 'sqlite3' के पुराने संस्करणों में कोई समस्या हो, लेकिन यदि 2.6+ इसके बिना काम करता है, तो आपको शायद इसे हटा देना चाहिए। यह भी देखें [यह प्रश्न] (http://stackoverflow.com/questions/30063437/trouble-storing-numpy-array-in-sqlite3-with-python/30064209#30064209)। – abarnert

4

यह मेरे लिए काम करता है:

import sqlite3 as sql 
import numpy as np 
import json 
con = sql.connect('test.db',isolation_level=None) 
cur = con.cursor() 
cur.execute("DROP TABLE FOOBAR") 
cur.execute("CREATE TABLE foobar (id INTEGER PRIMARY KEY, array BLOB)") 
cur.execute("INSERT INTO foobar VALUES (?,?)", (None, json.dumps(np.arange(0,500,0.5).tolist()))) 
con.commit() 
cur.execute("SELECT * FROM FOOBAR") 
data = cur.fetchall() 
print data 
data = cur.fetchall() 
my_list = json.loads(data[0][1]) 
2

मुबारक छलांग दूसरा यह करीब है लेकिन मैं स्ट्रिंग के लिए एक स्वचालित कास्टिंग हो रही है। यदि आप इस अन्य पोस्ट को भी चेक करते हैं: a fun debate on using buffer or Binary to push non text data into sqlite आप देखते हैं कि दस्तावेज दृष्टिकोण बफर से बचने और कोड के इस हिस्से का उपयोग करने के लिए है।

def adapt_array(arr): 
    out = io.BytesIO() 
    np.save(out, arr) 
    out.seek(0) 
    return sqlite3.Binary(out.read() 

मैं भारी अजगर 3 में इस परीक्षण नहीं किया है, लेकिन यह अजगर 2.7

+0

इस सुधार के लिए धन्यवाद; यह Python3 और 2.7 दोनों में काम करता प्रतीत होता है। मैंने 'sqlite3.Binary' का उपयोग करने के लिए अपना उत्तर अपडेट कर लिया है। – unutbu

1

मुझे लगता है कि matlab प्रारूप की दुकान और NumPy सरणी प्राप्त करने के लिए वास्तव में आसान तरीका है में काम करने लगता है। वास्तव में तेज़ और डिस्क और मेमोरी पदचिह्न काफी समान है।

Load/Save/Disk Comparison

(mverleg benchmarks से छवि)

लेकिन मैं कुछ संपीड़न क्षमताओं को जोड़ने के लिए सुझाव है कि यदि किसी भी कारण से आप SQLite में NumPy सरणी के स्टोर करने के लिए की जरूरत है।

unutbu कोड से अतिरिक्त लाइनें बहुत सरल है

compressor = 'zlib' # zlib, bz2 

def adapt_array(arr): 
    """ 
    http://stackoverflow.com/a/31312102/190597 (SoulNibbler) 
    """ 
    # zlib uses similar disk size that Matlab v5 .mat files 
    # bz2 compress 4 times zlib, but storing process is 20 times slower. 
    out = io.BytesIO() 
    np.save(out, arr) 
    out.seek(0) 
    return sqlite3.Binary(out.read().encode(compressor)) # zlib, bz2 

def convert_array(text): 
    out = io.BytesIO(text) 
    out.seek(0) 
    out = io.BytesIO(out.read().decode(compressor)) 
    return np.load(out) 

MNIST डेटाबेस के साथ परिणाम परीक्षण किए गए थे देता है:

$ ./test_MNIST.py 
[69900]: 99% remain: 0 secs 
Storing 70000 images in 379.9 secs 
Retrieve 6990 images in 9.5 secs 
$ ls -lh example.db 
-rw-r--r-- 1 agp agp 69M sep 22 07:27 example.db 
$ ls -lh mnist-original.mat 
-rw-r--r-- 1 agp agp 53M sep 20 17:59 mnist-original.mat 
``` 

zlib, और

$ ./test_MNIST.py 
[69900]: 99% remain: 12 secs 
Storing 70000 images in 8536.2 secs 
Retrieve 6990 images in 37.4 secs 
$ ls -lh example.db 
-rw-r--r-- 1 agp agp 19M sep 22 03:33 example.db 
$ ls -lh mnist-original.mat 
-rw-r--r-- 1 agp agp 53M sep 20 17:59 mnist-original.mat 

का उपयोग कर bz2

का उपयोग कर

SQLite पर bz2 के साथ Matlab V5 प्रारूप की तुलना में, bz2 संपीड़न लगभग 2.8 है, लेकिन पहुंच का समय Matlab प्रारूप (लगभग तुरंत 30 सेकंड से अधिक बनाम) की तुलना में काफी लंबा है। हो सकता है कि केवल वास्तव में विशाल डेटाबेस के लिए योग्य हो जहां सीखने की प्रक्रिया एक्सेस समय से अधिक समय लेती है या जहां संभव हो सके डेटाबेस पदचिह्न की आवश्यकता होती है।

अंत में ध्यान दें कि bipz/zlib अनुपात लगभग 3.7 और zlib/matlab के लिए 30% अधिक स्थान की आवश्यकता है।

पूर्ण कोड आप अपने आप को खेलने के लिए चाहते हैं:

import sqlite3 
import numpy as np 
import io 

compressor = 'zlib' # zlib, bz2 

def adapt_array(arr): 
    """ 
    http://stackoverflow.com/a/31312102/190597 (SoulNibbler) 
    """ 
    # zlib uses similar disk size that Matlab v5 .mat files 
    # bz2 compress 4 times zlib, but storing process is 20 times slower. 
    out = io.BytesIO() 
    np.save(out, arr) 
    out.seek(0) 
    return sqlite3.Binary(out.read().encode(compressor)) # zlib, bz2 

def convert_array(text): 
    out = io.BytesIO(text) 
    out.seek(0) 
    out = io.BytesIO(out.read().decode(compressor)) 
    return np.load(out) 

sqlite3.register_adapter(np.ndarray, adapt_array) 
sqlite3.register_converter("array", convert_array) 

dbname = 'example.db' 
def test_save_sqlite_arrays(): 
    "Load MNIST database (70000 samples) and store in a compressed SQLite db" 
    os.path.exists(dbname) and os.unlink(dbname) 
    con = sqlite3.connect(dbname, detect_types=sqlite3.PARSE_DECLTYPES) 
    cur = con.cursor() 
    cur.execute("create table test (idx integer primary key, X array, y integer);") 

    mnist = fetch_mldata('MNIST original') 

    X, y = mnist.data, mnist.target 
    m = X.shape[0] 
    t0 = time.time() 
    for i, x in enumerate(X): 
     cur.execute("insert into test (idx, X, y) values (?,?,?)", 
        (i, y, int(y[i]))) 
     if not i % 100 and i > 0: 
      elapsed = time.time() - t0 
      remain = float(m - i)/i * elapsed 
      print "\r[%5d]: %3d%% remain: %d secs" % (i, 100 * i/m, remain), 
      sys.stdout.flush() 

    con.commit() 
    con.close() 
    elapsed = time.time() - t0 
    print 
    print "Storing %d images in %0.1f secs" % (m, elapsed) 

def test_load_sqlite_arrays(): 
    "Query MNIST SQLite database and load some samples" 
    con = sqlite3.connect(dbname, detect_types=sqlite3.PARSE_DECLTYPES) 
    cur = con.cursor() 

    # select all images labeled as '2' 
    t0 = time.time() 
    cur.execute('select idx, X, y from test where y = 2') 
    data = cur.fetchall() 
    elapsed = time.time() - t0 
    print "Retrieve %d images in %0.1f secs" % (len(data), elapsed) 


if __name__ == '__main__': 
    test_save_sqlite_arrays() 
    test_load_sqlite_arrays() 
संबंधित मुद्दे