Array in Sqlite3 speichern

Installation und Anwendung von Datenbankschnittstellen wie SQLite, PostgreSQL, MariaDB/MySQL, der DB-API 2.0 und sonstigen Datenbanksystemen.
Kornblumberg
User
Beiträge: 7
Registriert: Donnerstag 5. März 2015, 14:39

Hey Leute,

schön bei euch zu sein ;)

Ich habe folgendes Problem.. ich lese ein Signal über die serielle Schnittstelle ein... Dabei erhalte ich ein x-array, welches das Sample darstellt und ein y-array , welches die Werte des Signals darstellt. Diese plotte ich... Das funktioniert alles schick soweit.. Jetzt möchte ich genau diese Arrays in einer Datenbank abspeichern..

xar[] ... geht von 0- 1000
yar[] ... geht von 0 - 1023

Ich mache das prinzipiell wie folgt:

Code: Alles auswählen

import sqlite3

xar = [1 2 3]     #Beispiel!
yar = [0 5 2]

conn = sqlite3.connect('Desktop/Python/USBread/Name.db')
c = conn.cursor() 
c.execute("CREATE TABLE Datenspeicher(Sample INT, Amplitude INT)")
c.execute(" INSERT INTO Datenspeicher VALUES(? , ?);" , (xar , yar)) 
.. ich bekomme folgenden Fehler:

Code: Alles auswählen

Traceback (most recent call last):
File "Desktop/Python/USBread/readex.py", line 77, in <module>
c.execute(" INSERT INTO Datenspeicher VALUES(? , ?);" , (xar , yar))
sqlite3.InterfaceError: Error binding parameter 0 - probably unsupported type.
Alle Werte in den Array sin zu 100 % INT!

Vielen Dank schonmal an euch!
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Hallo und willkommen im Forum!

Das Problem ist, dass du zwei Arrays übergibst und die können so in der Form eben nicht gespeichert werden. Du musst für jede Zeile ein eigenes execute Ausführen, Python kann ja schlecht raten, was du nun genau vor hast. Wenn du dein Problem noch ein wenig umformulierst, dann kannst du auch executemany verwenden.
Das Leben ist wie ein Tennisball.
BlackJack

@Kornblumberg: So wie die Tabelle definiert ist kann man da auch nur *einmal* ein INSERT auf diese Art machen. Also man kann das schon merhfach machen, aber dann ist die Frage wie man die Daten auseinanderhalten/identifizieren kann. Tabellen haben in der Regel auch einen Primärschlüssel. Und es stellt sich die Frage ob das so überhaupt sinnvoll ist das in ein RDBMS zu speichern.
Kornblumberg
User
Beiträge: 7
Registriert: Donnerstag 5. März 2015, 14:39

Hi! Danke für die Antworten...

Das Problem an der Sache ist... Ich lese mir die Daten in einer Schleife ein.. wobei die einzelnen Werte an das Array angefügt werden... Das funktioniert an sich gut ohne signifikanten Datenverlust... Ich habe dann natürlich probiert in jedem Schritt die Werte einzeln in die Tabelle zu schreiben (funktioniert)... ABER: Dabei geht die Geschwindigkeit soweit runter, dass der Datenverlust sehr hoch wird.

Deshalb wollte ich gerne das komplette Array schnell ablegen..

Gibt es eine Möglichkeit diese Probleme dabei zu umgehen?

Wenn ihr noch mehr Details braucht lasst es mich wissen..

Dauert es denn prinzipiell solange in diese Datenbank zu schreiben?

MfG
Benutzeravatar
snafu
User
Beiträge: 6738
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Geht es hier um Echtzeit-Verarbeitung oder was ist mit Datenverlust gemeint? Wenn man doch schon die Daten in einer Schleife holt, dann kann man sie auch im selben Schleifendurchlauf in die Tabelle schreiben. Dabei kann man sogar beide Verarbeitungsschritte sauber voneinander trennen, indem man Generatoren (Stichwort: `yield`) einsetzt.

EDIT: Und sicher, dass es ein Array ist? Meinst du nicht vielleicht eher eine Liste? Insbesondere weil du davon sprichst, etwas an dein Array anzuhängen. Normalerweise haben Arrays nämlich eine feste Länge, die beim Erzeugen des Arrays angegeben wird. Demgegenüber wachsen Listen dynamisch durch Anfügen weiterer Elemente. Hier wäre etwas Klarheit ganz gut.
Kornblumberg
User
Beiträge: 7
Registriert: Donnerstag 5. März 2015, 14:39

Hi,

richtig es handelt sich um eine Liste welche beim Schleifendurchlauf um den eingelesenen Wert erweitert. Es handelt sich nicht wirklich um eine Echtzeitverarbeitung, da ich noch am Anfang bin und mich an die Sache herantasten werde. Ich habe einen Arduino, welcher ein analoges Signal einliest und dieser sendet über USB die Werte rüber und ich lese sie dann, speichere diese in einer .csv und möchte diese zusätzlich (hauptsächlich um es etwas zu können) in einer Datenbank speichern. Graph wird auch geplottet.

Wenn ich diese Werte in der Schleife allerdings direkt in der Datenbank speichere verringert sich die Geschwindigkeit auf gut da doppelte bei nur 1000 Samples.
Also dachte ich das es da besser wäre, diese Liste im Anschluss wo auch geplottet werden kann in der Datenbank zu speichern.



Für Vorschläge wie das in die Schleife integriert werden könnte folgt hier die Schleife:

Danke schonmal

Code: Alles auswählen

if(not(UART.isOpen())):
	if Aktiv == False:
		Aktiv = True
		UART.open()
		print 'UART open'	
	while x <= 1000:
		y = UART.readline()
		xar.append(x)
		try: 
			y = int(y)
		except:
			y = yM
			Err += 1
		if (y > 1023):	
			y = yM
			Err += 1
		yar.append(int(y))
		yM = y
		print x,y
		f.write(str(x) + " , " + str(y) + '\n')
		x += 1
	if (Aktiv):
		UART.close()
		print 'UART geschlossen'
BlackJack

@Kornblumberg: Das sieht alles ein wenig unvollständig und komisch aus.

Bei einer Schleife bei der man vor Beginn weiss oder ermitteln kann wie oft sie durchlaufen wird nimmt man ``for`` und nicht ``while``.

Wo wird `x` das erste mal an einen Wert gebunden und an welchen? 1 oder 0? Falls ja ist `xar` ziemlich überflüssig, denn die Werte 1 bis 1000 aufsteigend, ohne Lücken, braucht man nicht wirklich in einer Liste zu sammeln. Falls man die irgendwann einmal braucht, zum Beispiel zum Plotten, kann man sie auch dann noch mit einem einfachen Ausdruck erstellen.

Einige Namen sind schlecht. `xar`, `yar`, `yM`, `f` — man sollte aussagekräftige Bezeichner verwenden und keine kryptischen Kürzel wo der Leser raten muss was sie wohl bedeuten mögen.

Es gibt Namenskonventionen was Gross- und Kleinschreibung angeht, und auch so einiges andere: Style Guide for Python Code. Besonders möchte ich da die Einrücktiefe hervorheben: Vier Leerzeichen pro Ebene.

Falls die Samplerate von der Auslese- und Verarbeitungsgeschwindigkeit dieser Schleife abhängen sollte (Deine Beiträge klingen irgendwie so), dann möchtest Du in dieser Schleife wahrscheinlich wirklich nur die Werte auslesen. Nicht nur weil weitere Arbeit hier die Samplerate drücken können, sondern auch weil Datenbanken und unter Umständen sogar Dateien nicht für jeden Schreibvorgang die gleiche Zeit benötigen. Es wäre auch gut wenn man die einzelnen Schritte in verschiedenen Funktionen schreibt und nicht alles als einen Riesencodeklumpen auf Modulebene sammelt.

Bei den ``if``-Bedingungen sind viele Klammern unnötig.

Man vergleicht normalerweise nicht mit literalen Wahrheitswerten. Denn da kommt am Ende nur wieder ein Wahrheitswert heraus und den hatte man ja vorher schon. Das ist entweder immer der gleiche oder aber immer das Gegenteil vom Ausgangswert. Im ersten Fall kann man den Ausgangswert direkt nehmen und im zweiten kann man ``not`` verwenden. Also statt ``if active == False:`` würde man ``if not active:`` schreiben.

Wobei diese ganze `Aktiv`-Geschichte komisch bis falsch aussieht. Der erste Test ist ob `UART` geschlossen ist. Dann wird in Abhängigkeit von `Aktiv` die Verbindung geöffnet. Nur wissen wir ja das sie geschlossen sein muss. Wenn `Aktiv` also `True` ist, dann wird diese geschlossene Verbindung *nicht* geöffnet, aber dann in einer Schleife versucht daraus zu lesen. Das kracht dann mit einer Ausnahme.

Für den Fall das gelesen werden kann, muss `UART` im ersten ``if``-Zweig geöffnet worden sein. Dort wird auch `Aktiv` auf `True` gesetzt. Das ist die einzige Möglichkeit das man zum letzen ``if`` gelangt. Und da *muss* `Aktiv` dann `True` sein, weshalb es sinnlos ist das zu testen.

Kann es sein das `Aktiv` total überflüssig ist wenn man die `isOpen()`-Methode von dem `UART`-Objekt direkt verwenden würde um festzustellen ob man das öffnen oder schliessen muss/kann? Muss das überhaupt sein?

Falls `UART` ein `serial.Serial`-Exemplar ist kann man übrigens über dieses Objekt iterieren und bekommt die Zeilen als Werte geliefert. Das verhält sich da wie Dateiobjekte. Und diese Objekte sind auch Kontextmanager, das heisst man kann die mit ``with`` verwenden und sich diesen ”testen und öffnen und schliessen”-Code ganz sparen.

Werte und Teilzeichenketten mit `str()` und ``+`` zusammenzusetzen ist eher BASIC als Python. Python hat dafür Zeichenkettenformatierung mittels der `format()`-Methode auf Zeichenketten. Weniger Tipparbeit, flexibler, und man sieht auch ohne farbige Syntaxhervorhebung noch einfach wie das Ergebnis wohl aussehen wird und was literale Zeichenkette und was Code ist. Für CSV-Dateien hat Python allerdings auch ein Modul in der Standardbibliothek. Und wenn man im Programm auch plotten möchte hat man fast immer auch eine Abhängigkeit zu `numpy` — dort gibt es auch Funktionen um solche Textdateien zu erstellen.

Und mir wird immer unklarer was die Datenbanktabelle soll. Das macht so keinen Sinn.
Kornblumberg
User
Beiträge: 7
Registriert: Donnerstag 5. März 2015, 14:39

Kurz:

- Die Liste is zum plotten
- Die Datenbank soll genutzt werden um später noch auf die Werte zugreifen zu können... Ich weiß, dass die .csv oder .txt auch dazu reichen würde.. aber von Datenbanken was gehört zu haben wird nicht schaden..

Danke auf jedenfall für die Hinweise.. in einigen gerade was sich auf UART.open bezieht stimme ich dir zu...

Aber zurück zum Thema...

Kann man so eine Liste direkt in eine Tabelle schreiben? Oder muss ich die einzelnen Werte aus Liste oder Datei neu auslesen um sie in der Datenbank abzulegen?

Oder gibt es einen ganz anderen Ansatz diese zu verarbeiten..
BlackJack

@Kornblumberg: Nochmal: eine relationale Datenbank dafür zu verwenden macht hier absolut keinen Sinn, auch nicht „um da mal etwas von gehört zu haben”. Denn letztendlich lernst Du dabei nichts wichtiges oder sinnvolles über relationale Datenbanken sondern hast im Gegenteil einen Fall den man ganz sicher *nicht* so lösen würde. Das ist wie einen Nagel mit dem Griff von einem Schraubendreher in die Wand zu hauen weil man mal etwas mit einem Schraubendreher machen wollte. Es ist das falsche Werkzeug und falsch angewendet.

Es gibt das schon erwähnte `executemany()` wenn man mehrere Datensätze, die in einer geeigneten Form vorliegen oder in eine solche gebracht werden können, ohne eine explizite Schleife in eine Datenbank stecken möchte. Sagte ich schon das das hier gar keinen Sinn macht? ;-)

Bevor man unsinnige Sachen hinzufügt, macht es vielleicht mehr Sinn das bisherige sauberer zu lösen und zum Beispiel sinnvoll auf Funktionen aufzuteilen, den Modulnamensraum von Variablen und Hauptprogramm zu befreien, die Eingabe über die serielle Schnittstelle von der oder den Ausgaben zu trennen, bevor man sich noch mehr (unnötige) Komplexität in ein ohnehin schon leicht unübersichtliches Programm einbaut.

Ungetestet:

Code: Alles auswählen

import csv
from itertools import islice

import numpy as np
from matplotlib import pyplot as plt
from serial import Serial


class SampleReader(object):

    def __init__(self, lines, max_value, error_value=None):
        self.lines = iter(lines)
        self.max_value = max_value
        self.error_value = error_value
        self.error_count = 0

    def __iter__(self):
        return self

    def next(self):
        line = next(self.lines)
        try:
            result = int(line)
        except ValueError:
            self.error_count += 1
            result = self.error_value
        else:
            if result > self.max_value:
                self.error_count += 1
                result = self.error_value
        return result


def read_samples(port, count, max_value):
    with Serial(port) as lines:
        reader = SampleReader(lines, max_value)
        values = list(islice(reader, count))
    return (reader.error_count, values)


def save_samples(filename, values):
    with open(filename, 'wb') as csv_file:
        writer = csv.writer(csv_file)
        writer.writerow(['sample no.', 'value'])
        writer.writerows(enumerate(values, 1))


def plot_samples(values):
    plt.plot(np.arange(1, len(values) + 1), values)
    plt.show()


def main():
    values, error_count = read_samples('<port>', 1000, 1023)
    print values
    print error_count
    save_samples('test.csv', values)
    plot_samples(values)


if __name__ == '__main__':
    main()
Kornblumberg
User
Beiträge: 7
Registriert: Donnerstag 5. März 2015, 14:39

Naja laut TU Berlin ist es nicht so sinnlos...

Die haben laut dem Schema auch erst die Daten eingelesen diese in einer Datenbank abgelegt und anschließend mit Hilfe eines schnelleren Systems verarbeitet.

Was wäre denn deiner Meinung nach eine gute alternative zur Datenbank?
Benutzeravatar
noisefloor
User
Beiträge: 3856
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: WW
Kontaktdaten:

Hallo,

eine Alternative ist Redis. Ein netzwerkfähiges KV-Store, welches Listen (=Arrays) als nativen Datentyp unterstützt.

Gruß, noisefloor
BlackJack

@Kornblumberg: Sorry aber das glaube ich nicht. Das „die TU Berlin” das so gemacht hat. Wenn dann wird das eine konkrete Person (oder Gruppe) gemacht haben, und falls die das tatsächlich mit diesem DB-Schema gemacht hat, dann hat diese Person (oder Gruppe) keine Ahnung was sie da tut. Das was Du da machst bietet keinen Vorteil gegenüber einer CSV-Datei. Ein Datenbankentwurf in einem RDBMS mit nur *einer* Tabelle die mit nichts in Relation gebracht wird (das R in RDBMS) und in die dann auch nur *eine* Messung gespeichert wird — mehr kann man bei dem DB-Entwurf nicht auseinanderhalten — macht schlicht keinen Sinn. Die Datenbank wird dabei überhaupt nicht wirklich benutzt. Warum also die ganze zusätzliche Komplexität wenn die einem überhaupt nichts bringt?

Was ich mir vorstellen könnte was die *tatsächlich* gemacht haben ist einen *sinnvollen* Datenbankentwurf wo nicht nur eine Messung gespeichert werden kann, sondern wo man *viele* Messungen mit *vielen* Samples speichern kann und dann auch gezielt wieder abfragen kann. Und dann vielleicht auch noch Metainformationen über die Messungen — was für Messgeräte/Sensoren, was wurde gemessen, welche Einheiten haben die Werte, Zeitstempel, und so weiter. *Dafür* könnte man eine Datenbank einsetzen. Aber nicht für ein paar Samples von einer einzelnen Messung.

Selbst dann bleibt noch die Frage ob es ein RDBMS sein muss. Bei grösseren Datenmengen dieser Art bietet sich zum Beispiel auch HDF als effizientes und auch gebräuchliches Datenformat an.
Benutzeravatar
pillmuncher
User
Beiträge: 1484
Registriert: Samstag 21. März 2009, 22:59
Wohnort: Pfaffenwinkel

BlackJack hat geschrieben:Ein Datenbankentwurf in einem RDBMS mit nur *einer* Tabelle die mit nichts in Relation gebracht wird (das R in RDBMS) [...] macht schlicht keinen Sinn. Die Datenbank wird dabei überhaupt nicht wirklich benutzt.
In den meisten Fällen ist das sinnlos, ja. Aber wenn die Anzahl der Records entsprechend groß ist - also im GB oder TB Bereich ist - und viel in der Tabelle gesucht wird, hat ein RDBMS schon Vorteile.
Nebenbei: das R in RDBMS bezieht sich auf die Tabellen selbst, nicht auf deren Beziehungen untereinander. Es handelt sich bei einer Tabelle um eine Relation im logischen Sinne: (name='Hans Mustermann', strasse='Schlossallee 1', plz=12345, ort='Irgendwohausen') ist zB. ein Element der Relation, die angibt, dass name in strasse, plz, ort wohnt.
In specifications, Murphy's Law supersedes Ohm's.
Sirius3
User
Beiträge: 17741
Registriert: Sonntag 21. Oktober 2012, 17:20

@pillmuncher: [klugscheißermodus]eine Datenbank wird erst dann relational, wenn man darauf mit einer relationalen Algebra arbeiten kann; dass ein Element dieser Algebra Relation heißt, macht die Datenbank noch nicht relational.[/klugscheißermodus]
Benutzeravatar
snafu
User
Beiträge: 6738
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

@pillmuncher: Ist bei großen Messdaten nicht trotzdem HDF besser? Schließlich wurde es ja für genau diesen Zweck entworfen und ist durchaus erprobt. Nur weil das Speichern in einer Datenbank unter gewissen Umständen geeigneter erscheint als das Speichern z.B. in einer CSV-Datei, ist es ja trotzdem nicht das am besten geeignete Werkzeug für diese Aufgabe.
Benutzeravatar
pillmuncher
User
Beiträge: 1484
Registriert: Samstag 21. März 2009, 22:59
Wohnort: Pfaffenwinkel

@Sirius3: Eine Relationale Algebra über einer 1-elementigen Menge ist zwar ziemlich langweilig, aber immer noch eine Relationale Algebra. Immerhin kann man darauf Selektionen, Projektionen und Self-Joins ausführen.

@snafu: Klar ist ein RDBMS nicht immer die geeignete oder sogar beste Lösung, aber unter bestimmten Bedingungen ist eine DB mit einer einzigen Tabelle immer noch besser, als eine CSV-Datei.
In specifications, Murphy's Law supersedes Ohm's.
Kornblumberg
User
Beiträge: 7
Registriert: Donnerstag 5. März 2015, 14:39

Hey Leute,

das schöne an solchen Foren ist ja immer das sich der TE erstmal ne Weile rechtfertigen und erklären soll :roll: :) .

Das eigentliche Thema Zwecks der Geschwindigkeit wurde noch nicht geklärt...

Um es nochmal zu erwähnen... Die Geschwindigkeit ging beim Lesen über den seriellen Port so in den Keller das ich gerne die Liste komplett in einem Abwasch in die Datenbank geschrieben hätte.. Ist das normal? Habt ihr diese Probleme auch oder geht das bei euch alles relativ zügig??

Um mich nochmal zu rechtfertigen.. Natürlich ist es für diese spezielle Anwendung etwas sinnfrei eine Datenbank zu nutzen...
Wenn wir jetzt aber mal ein paar Wochen/Monate vorraus denken dann kann es gut kommen das der Zeitpunkt der Messung festgehalten wird.. bei/von wem es durchgeführt wurde.. Das gefilterte Signal erstellt wird... Events bestimmt werden usw... Soweit bin ich jetzt aber noch nicht.. Das Problem nach hinten zu schieben wird mich aber auch nicht vorwärts bringen...

MfG

Und wenn einer explizit zu meiner Fragestellung noch was sagen würde wäre ich sehr dankbar.
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Kornblumberg hat geschrieben: das schöne an solchen Foren ist ja immer das sich der TE erstmal ne Weile rechtfertigen und erklären soll :roll: :) .
Nein, das schöne an so einem Forum wie dem unseren ist, dass sich die Leute hier *Gedanken* um *Dein* Problem machen und eben nicht stumpf alles daran setzen, die von Dir als mutmaßlich sinnvoll erachtete Lösung auf Biegen und Brechen zu realisieren. Dafür ist es oft wichtg zu kapieren, *was* Deine Anforderungen und Restriktionen sind und ggf. auch zu ermitteln, ob es sich evtl. nicht doch um ein XY-Problem handelt. Dies ist leider oft der Fall...

Oft bekommt man dann auch Hinweise auf Alternativen, die man selber gar nicht kennt oder an die man nicht gedacht hat. So etwas erachte ich als enorm wertvoll und bin dankbar dafür!
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
Kornblumberg
User
Beiträge: 7
Registriert: Donnerstag 5. März 2015, 14:39

natürlich ist das auch gut so!

Sonst wäre es auch quatsch.. aber manchmal wäre eine direkte Antwort auch super :)
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

BlackJack hatte Dir doch einen feinen, sauberen Ansatz gegeben! Hast Du damit schon experimentiert?
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
Antworten