truncnorm() in python

mit matplotlib, NumPy, pandas, SciPy, SymPy und weiteren mathematischen Programmbibliotheken.
__deets__
User
Beiträge: 14480
Registriert: Mittwoch 14. Oktober 2015, 14:29

Aber er füttert das Ding doch danach. Wenn er das nicht mit ebenfalls adaptierten Intervallgrenzen tut, kommt da auch Unsinn raus.
asahdkhaled
User
Beiträge: 29
Registriert: Samstag 28. Oktober 2017, 22:07

Kommando zurück, komischerweise kommen wieder falsche Werte raus :D Bin also genauso schlau wie vorher
__deets__
User
Beiträge: 14480
Registriert: Mittwoch 14. Oktober 2015, 14:29

Wie fütterst du das denn? Zeig mal ein bisschen mehr statt nur die Umrechnungsfunktion.
narpfel
User
Beiträge: 643
Registriert: Freitag 20. Oktober 2017, 16:10

@__deets__: Das von `truncnorm` zurückgegebene Objekt hat alle Parameter der Verteilung fest eingebaut. Wenn man darauf später z. B. `rvs` aufruft, dann muss man die Parameter nicht nochmal angeben.

@asahdkhaled: Mehr Code wäre tatsächlich hilfreich.
asahdkhaled
User
Beiträge: 29
Registriert: Samstag 28. Oktober 2017, 22:07

Ich blicke nicht mehr durch. Eben waren noch alle Werte korrekt. Jetzt nochmal durchlaufen lassen, jetzt sind wieder ca. 50% falsch....
Der Code ist fast der gleiche wie vorher, alles was zuvor passiert hat damit nichts zu tun...)

Code: Alles auswählen

for datatypes in datentypen_columns:
    name_convert_column = results_as_list_new[i]
    if datatypes =='VARCHAR2':
        convert_cat=(name_convert_column,name_convert_column,_tabelle,name_convert_column,_tabelle,_tabelle,name_convert_column)
        drop_view=(name_convert_column)
        calculate=(name_convert_column,name_convert_column,name_convert_column,name_convert_column,name_convert_column,_tabelle,name_convert_column,name_convert_column)
        cur.execute("CREATE VIEW convert_cat_%s (quotient, %s, rnum) AS SELECT (COUNT(*)/(SELECT COUNT(*) FROM %s ) ) as quotient, %s, row_number() over ( order by (COUNT(*)/(SELECT COUNT(*) FROM %s ) ) desc ) as rnum FROM     %s  GROUP BY %s ORDER BY quotient desc" %convert_cat)
        cur.execute("Select b.ID,a.unten,a.oben FROM( SELECT t3.RNUM, t3.%s, lag(t3.com_Pr,1,0) OVER (order by rnum asc) as unten , t3.com_PR as oben FROM( SELECT t1.rnum, t1.%s , SUM(t2.quotient) as com_Pr FROM CONVERT_CAT_%s t1 INNER JOIN CONVERT_CAT_%s t2 ON t1.rnum >= t2.rnum group by t1.rnum, t1.%s, t1.quotient ORDER BY RNUM asc ) t3) a INNER JOIN %s b ON b.%s = a.%s order by ID asc" %calculate)
        _content_category = cur.fetchall()
        add_category_number_column = (_tabelle, name_convert_column)
        cur.execute("ALTER TABLE %s ADD %s_category NUMBER(15,14)" % add_category_number_column)
        x=0
        for ID in _content_category:
            id = _content_category[0]
            id_category = [j[0] for j in _content_category]
            lower = [j[1] for j in _content_category]
            upper = [j[2] for j in _content_category]
            mean_category = ((lower[x] + upper[x]) / 2)
            sd_category = (upper[x] - lower[x]) / 6
            a = (lower[x] - mean_category) / sd_category
            b = (upper[x] - mean_category) / sd_category
            samples = float(truncnorm.rvs(a, b, mean_category, sd_category, 1))
            #X = get_truncated_normal(mean= mean_category[x], sd=sd_category[x], low=unten_category[x], upp=oben_category[x])
            #update_cells_value = float(X.rvs(1))
            category = (_tabelle, name_convert_column,samples,id_category[x])
            cur.execute("UPDATE %s SET %s_category = %s WHERE ID=%s" % category)
            x += 1
        drop_view = (name_convert_column)
        #cur.execute("DROP VIEW convert_cat_%s" % drop_view)

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