truncnorm() in python

mit matplotlib, NumPy, pandas, SciPy, SymPy und weiteren mathematischen Programmbibliotheken.
asahdkhaled
User
Beiträge: 29
Registriert: Samstag 28. Oktober 2017, 22:07

@narpfel: Komischerweise habe ich mit deiner Methode auch keine Probleme, sprich es wird kein Datensatz außerhalb der Grenzen erzeugt. Wieso ist das bei mir nicht so??? Ich hole mir lower und upper aus der DB, den Rest mache ich ja genau so wie du
narpfel
User
Beiträge: 643
Registriert: Freitag 20. Oktober 2017, 16:10

Mal abgesehen davon, dass der Code immer noch für SQL-Injections anfällig ist und der Datenbankentwurf so eher ungewöhnlich ist (normalerweise verändert man Tabellen nicht)...

Ich würde empfehlen, nochmal einen Schritt zurück zu gehen und erstmal zu versuchen, den Code ohne Datenbankinteraktion zu Laufen zu bekommen. Das dann in eine Funktion stecken. Die Datenbankinteraktion sinnvoll in Funktionen aufteilen. Sprich: Eine Funktion, die die Datensätze aus der Datenbank holt und zurückgibt. Eine, die die Zufallszahl einfügt (und dafür die ID übergeben bekommt). Usw...

Die innere `for`-Schleife lässt sich übrigens ziemlich vereinfachen:

Code: Alles auswählen

for (id, lower, upper) in _content_category:
    mean = (lower + upper) / 2
    sd = (upper - lower) / 6
    a = (lower - mean) / sd
    b = (upper - mean) / sd
    sample = float(truncnorm.rvs(a, b, mean, sd, 1))
    cur.execute("UPDATE {} SET {}_category = %s WHERE ID=%s".format(_tabelle, name_convert_column), (sample, id))
Dabei ist zu beachten, dass man eigentlich nicht mit dynamischen Tabellen- und Spaltennamen arbeitet und du deinen Datenbankentwurf nochmal überarbeiten solltest.

Ansonsten hilft es vielleicht, in der `for`-Schleife abzufragen, ob ein Wert außerhalb des Intervalls liegt und dann die relevanten Werte auszugeben. Dann könnte man vielleicht sehen, woran es liegt. Eventuell hilft es auch, den Seed des Zufallszahlengenerators zu setzen, damit die Tests nachvollziehbar werden.

Am einfachsten wäre es aber wahrscheinlich, ein wenig Abstand zum Code zu nehmen und das ganze ein wenig übersichtlicher und auf Funktionen aufgeteilt anzugehen.

Nochmal die Frage: Wieso soll die eine Zahl normalverteilt sein? Bist du sicher, dass du nicht eine gleichverteilte Zahl willst?
asahdkhaled
User
Beiträge: 29
Registriert: Samstag 28. Oktober 2017, 22:07

Das mit den SQL Injektions ist mir bewusst und das werde ich, sobald es endlich mal klappt ändern :)
Und ja, normalverteilung ist gewünscht, keine gleichverteilung :)

Ich bin echt am verzweifeln. Manchmal klappt es, manchmal nicht. Ich probiere mal weiter und werde das ganze ohne DB Interaktion nochmal weiter versuchen. Wenn ich nämlich das ganze mit 100 Datensätzen durchlaufen lasse, klappt es immer. Wenn ich meine ganze tabelle verwende, also 2000 Zeilen, klappt etwas nicht....

Darübe rhinaus muss ich auch noch sagen, dass dieses Problem nur bei dieser einen Spalte auftritt, in denen die Intervalle sehr klein sind.
Ich habe 4 Spalten die ich auf diese Art bearbeite, nur eine davon macht Schwierigkeiten :K
Das lässt für mich die eine Begründung zu: Es liegt daran, dass teilweise die Intervalle zu klein sind? Gibt es da eine Grenze?
Wenn ich nämlich nur 100 Datensätze haben, gibt es auch weniger Intervalle, weil es weniger Kategorien gibt. Daher sind die Intervalle auch größer...

Bei allen andern Spalten gibt es weniger Kategorien,d.h. Intervalle größer. Vielleicht ist das der Grund. Weiß jemand woran das liegen könnte?

*Edit: Darin liegt es nicht, die Kategorien, welche falsche Ergebnisse liefern, sind komplett unterschiedlich groß. D.h. sowohl kleine als auch große Intervalle und es klappt trotzdem nicht..*

Nervig :)
asahdkhaled
User
Beiträge: 29
Registriert: Samstag 28. Oktober 2017, 22:07

*EDIT2:

Wenn ich einfach

Code: Alles auswählen

        for (id, lower, upper) in _content_category:
           mean = (lower + upper) / 2
           sd = (upper - lower) / 6
           a = (lower - mean) / sd
           b = (upper - mean) / sd
           sample = float(truncnorm.rvs(a, b, mean, sd, 1))
           print np.any((sample < lower) | (sample> upper))
 
VErsuche, also ohne den Update in die DB, kommt nirgendwo ein "TRUE". Das würde ja bedeuten das das Skript an sich funktioniert, nur das Schreiben in die DB irgendwie fehl schlägt...
asahdkhaled
User
Beiträge: 29
Registriert: Samstag 28. Oktober 2017, 22:07

*Edit 3:

Ich habe mir jetzt nochmal mit "print" Ausgaben genau angeschaut was dort genau vor sich geht. Es hat sich herausgestellt, dass in Python alles stimmt.
Die lower und upper Grenzen werden korrekt aus der DB geholt und auch stets ein Wert gesampled, der zwischen den Grenzen liegt. Also genau so wie ich es haben will. Komischerweise werden aber teilweise komplett andere Zahlen in die DB geschrieben, als sie Python generiert.

Bsp:

In der Python Ausgabe steht für einen Datensatz:
lower sample upper
0.672778561354 0.676266450236 0.679360601787

In der DB steht allerdings

0,672778561 0,669212106927 0,679360601787

D.h. es wird ein Wert per Update in die DB geschrieben, der nichts mit dem tatsächlichen Wert zutun hat. Und das anscheinend zufällig.
Es ist auch kein "ID" Fehler, also das er irgendwie durcheinander kommt. Die Sample Zahl aus der DB wird in Python nirgendswo generiert.

Jemand eine idee wie man den Update-Befehl überarbeiten könnte? Der Code scheint bis zum Update soweit zu funktionieren.
asahdkhaled
User
Beiträge: 29
Registriert: Samstag 28. Oktober 2017, 22:07

*EDIT 4:Am Update Befehl scheint es also auch nicht zu liegen. Es liegt glaube ich an den SQL Statements.
In denen im Fall falsche lower bzw. Upper Grenzen mitgegeben werden.

Die Query mit der ich prüfe ob datenästze außerhalb der Range erzeugt wurden, weist andere Grenzen auf. Muss wol anscheinend die erstmal ins Gleichhewicht bringen
asahdkhaled
User
Beiträge: 29
Registriert: Samstag 28. Oktober 2017, 22:07

EDIT 5: An den SQL Queries liegt es anscheinend auch nicht. Es liegt anscheinend daran, dass bei Beginn der for schlefe, die falschen Werte für lower und upper mitgegeben werden. D.h. für einen bestimmten Datensatz gibt es lower und upper, allerdings werden die falschen Werte an die truncnorm weitergegeben.

Dies passiert komischerweise unregelmäßig. Also für ein paar Datensätze stimmt alles, fpr manche wiederum nicht...
Antworten