Inversenberechnung _ Arrayübergabe

mit matplotlib, NumPy, pandas, SciPy, SymPy und weiteren mathematischen Programmbibliotheken.
Antworten
StudArne
User
Beiträge: 4
Registriert: Montag 20. April 2020, 15:39

Liebes Forum,

Ich sitze seit einer ganzen Weile an der Erstellung eines Programms für statistische Auswertung.
Der Vergleichsdatensatz geht über 10k Zeilen und 7 Spalten, Ziel ist ein Array von 7 Werten, bestehend aus den Mahalanobis-Distanzen zum Mittelwert.

Im Großen und Ganzen funktionieren sämtliche Zwischenschritte, aber ein ärgerliches Problem habe ich derzeit noch und das Gefühl, als Anfänger in Python da einfach was ganz arg blödes zu übersehen:
Für Testzwecke, habe ich das Ganze einfach mal mit einem kleinen 3x3 Datensatz ausprobiert, den ich per Hand und per Excel berechnet habe, um das Programm zu testen.

Ich berechne die Kovarianz-Varianzmatrix, diese stimmt überein, aber irgendetwas scheint beim Einschreiben in das Array nicht zu funktionieren, weil die Folgeberechnungen nicht stimmen.

Code: Alles auswählen

'''------------------------------------------------------------
Berechnung Zeilendurchschnitt [Zeitreihendurchschnitt]
------------------------------------------------------------'''

TimeArr = []
for CalcRow in range(len(mtx)):
    TimeArr.append(0)
for Col in range(SPALTENANZ):
    for CalcRow in range(len(mtx)):
        TimeArr[CalcRow] += mtx[CalcRow][Col]    
for CalcRow in range(len(mtx)):
    TimeArr[CalcRow] = TimeArr[CalcRow] / SPALTENANZ
    #print ('Zeilendurchschnitt :', [CalcRow], '=', TimeArr[CalcRow])

print ('Zeilendurchschnittsarray :', TimeArr)

'''------------------------------------------------------------
	CovarianceVarianceMatrix
------------------------------------------------------------'''

CovVarMtx =[]
StdDev =[]
CovRow =[]
for CalcRow in range(len(mtx)):
    for ComRow in range(len(mtx)):
        StdDev = ((mtx[CalcRow] - TimeArr[CalcRow]) * (mtx[ComRow]-TimeArr[ComRow]))
        CovVarEle = sum(StdDev[0:len(StdDev)])/(SPALTENANZ)#-1)
        CovRow.append(CovVarEle)    
    CovVarMtx.append(CovRow)    
    CovRow = []
D = np.array(CovVarMtx)
#print (CovVarMtx)

#Umformatierung des Arrays
#------------------------------------------------------------

df = pd.DataFrame(CovVarMtx, dtype=float)
Cmtx = 0
Cmtx = np.array(df)
print ('Cmtx', '\n', Cmtx)
SPALTENANZ_CMtx = 0
SPALTENANZ_CMtx = len(df.columns)
ZEILENANZ_CMtx = 0
ZEILENANZ_CMtx = anzRows
print ('Rows/Cols :', ZEILENANZ_CMtx, SPALTENANZ_CMtx)

Allerdings gehen die Folgeberechnungen auf, sobald ich die Kovarianz-Matrix händisch in ein Array einschreibe und damit weiterrechne (Aus meiner Sicht mit gleicher Syntax - die Werte sind gleich).

Folgende Varianten habe ich probiert:

- Die Zwischenspeicherung in ein csv.file, um es auszulesen und damit weiterzurechnen

Code: Alles auswählen

[/i]

#Zwischenspeicherung der Covariance-Variance-Matrix
#------------------------------------------------------------

np.savetxt("Covariance.csv", Cmtx, delimiter= ',')
print ('CVMtx: ','\n', Cmtx)



'''------------------------------------------------------------
	Teilberechnungen Mahalanobis
------------------------------------------------------------'''

#Auslesen des für die Berechnungen notwendigen Zwischenfiles
#------------------------------------------------------------
file = open( "Covariance.csv")
rowArr = []
start = 0
for line in file.readlines():
    spFullArr = [value for value in line.split(',')]
    spFilterArr = []
    for i in range(len(spFullArr)):
        spFilterArr.append(spFullArr[i])
    rowArr.append(spFilterArr)
start += 1
file.close()

[Die händisch eingeschriebene Kovarianzmatrix wirft das Gleiche csv. aus, habe ich schon getestet.]

Code: Alles auswählen

#Alternative - Inverse und Determinante, Zwischenchecks
#------------------------------------------------------------

A = np.array([[4173.25415838,4168.991966,4153.1742671],[4168.991966,4164.73419886,4148.93308044],[4153.1742671,4148.93308044,4133.19442491]])
np.savetxt("Covariance2.csv", A, delimiter= ',')
print (A)
print (A[0][0])
a = np.linalg.det(A)
print ('DET:', '\n', a)
print ('INV:', '\n', np.linalg.inv(A))
print ('EIN:', '\n', A.dot(np.linalg.inv(A))) 
Z = np.linalg.inv(A)
print ('RÜCK:', '\n', np.linalg.inv(Z))
- verschiedene Umformatierungen der Kovarianzmatrix (pd.dataframe, np.matrix, np.asarray, ...)

Code: Alles auswählen

#Umformatierung des Arrays
#------------------------------------------------------------

df = pd.DataFrame(CovVarMtx, dtype=float)
Cmtx = 0
Cmtx = np.array(df)
print ('Cmtx', '\n', Cmtx)
SPALTENANZ_CMtx = 0
SPALTENANZ_CMtx = len(df.columns)
ZEILENANZ_CMtx = 0
ZEILENANZ_CMtx = anzRows
print ('Rows/Cols :', ZEILENANZ_CMtx, SPALTENANZ_CMtx)

- Aufrufen sämtlicher Zwischenschritte als print-Ausgaben, um zu testen, ob die Kovarianzmatrix auch indizierbar ist - passt alles, die Berechnungen stimmen leider dennoch nicht.


Ein letzter Hinweis - beim Vergleich der Printausgaben der berechneten und der eingeschrieben Matrix fällt mir auf, dass das händisch eingeschriebene Array die erste eckige Klammer extra vorrückt, sodass die Zahlenwerte untereinander strukturiert stehen - bei der ausgegebenen Matrix (sowie allen anderen in der Berechnung), stehen die Klammern sortiert untereinander - ich weiß nicht mal, warum das eine Rolle spielen sollte, wenn die Elemente alle sauber per Index aufrufbar sind :?:

Habt ihr einen Hinweis, oder eine Idee?


Viele Grüße,
Arne
einfachTobi
User
Beiträge: 512
Registriert: Mittwoch 13. November 2019, 08:38

Ich hab mich noch nicht intensiv mit deinen Testansätzen beschäftigt, aber mir fallen vorab schon einige Dinge auf. Du arbeitest im wesentlichen nicht mit Arrays, sondern mit Listen. Verwende stattdessen von Beginn an Numpy-Arrays und verzichte auf das Iterieren über eben diese. In der Regel gibt es Funktionen, welche die gewünschten Schritte für das ganze Array ausführen. Was mich zum entscheidenden Punkt bringt: Warum verwendest du nicht die vorhandenen Funktionen wie numpy.cov, scipy.spatial.distance.mahalanobis etc.?
StudArne
User
Beiträge: 4
Registriert: Montag 20. April 2020, 15:39

Danke schon einmal für die schnelle Rückmeldung!

Ja da ist durchaus einiges entstanden, weil ich mich eingangs nicht sehr mit den Unterschieden von Listen und Arrays auseinandergesetzt habe :?.

Zur Frage:
Scipy.spatial.distance.mahalanobis gibt die Berechnung von zwei 1-D-Arrays vor - Ich muss hier Summen über Zeitreihen einberechnen.
Dafür hatte ich auch einige Scripts aus gitHub probiert, habe aber leider keins gefunden, dass mehrdimensionale Matritzen in der Art und Weise berechnet, wie es für diesen Fall sein soll.

Die Covariance betreffend:
Ich dachte mir, um Einen hat das Ganze den Zweck, sich mit Python und Schleifenaufbau nochmal eingehend zu beschäftigen, zum Anderen lassen sich die Funktionen nicht anpassen (oder ich wüsste nicht wie) - z.B.: Ob die Verrechnung mit den Spalten- oder Zeilendurchschnitten, als Gesamtstichproben-. oder Teilstichprobenberechnung betrachtet wird (also Summe der Standardabweichungen durch Spaltenanzahl, oder Spaltenanzahl - 1).
Vor allem aber, hatte ich das erst probiert, aber nicht die Ergebnisse erhalten, die ich händisch berechnet habe (wahrscheinlich aus dem gleichen Fehler, der mich jetzt aufhält) - gerade habe ich die np.cov getestet und sie liefert ein Ergebnis (das mit Zeilendurchschnitt und Spaltenanzahl -1).

Das führt mich aber zu dem Problem zurück:

Ich habe mit isinstance sämtliche Listen/Arrays geprüft und verwende bei den Berechnungen tatsächlich nur arrays (deswegen gibt es so viele Zwischenkonvertierungen, da hatte ich schon einige Fehler ausgeworfen bekommen).
Leider stimmt die weitere Berechnung (auch mit der Covariance durch np.cov) dennoch nicht.

Hast du/ habt ihr eventuell eine weitere Idee?



PS: Das mit den Listen und Arrays im Allgemeinen würde ich ganz gerne etwas sauberer machen - bisher fülle ich zeilenweise eine Liste mit allen Spalten, hänge sie mit .append dann zeilenweise an und konvertiere anschließend - Da bin ich beim Recherchieren fast kirre geworden, weil ich nichts gefunden (oder vielleicht auch nicht verstanden) habe, das den Vorgang gleich mit Arrays ermöglicht.

PSS: Zu den Testansätzen: Die Ergebnisse prüfe ich immer durch Matrix*Inverse - was die Einheitsmatrix ergeben würde - und durch das Invertieren der Inverse - wodurch die Originalmatrix entstehen sollte.
Für die Determinante und Inverse verwende ich einfach die linalg-Bibliothek.
Wirft für die händisch eingetragene Kovarianzmatrix auch das richtige aus.
einfachTobi
User
Beiträge: 512
Registriert: Mittwoch 13. November 2019, 08:38

Ist ja vollkommen okay nicht die fertigen Funktionen zu verwenden, wenn diese nicht machen, was man will. :)
Nichtsdestotrotz solltest du zunächst den Code aufräumen: Variablen werden klein_mit_Unterstrich geschrieben. Konstanten KOMPLETT_GROSS. MixedCase wird für Klassen verwendet. Bitte verwende keine Abkürzungen wie `mtx`, wenn du stattdessen einfach `matrix` schreiben kannst. Dein Editor schlägt dir eh den Namen vor und du drückst nur TAB. Es macht also keine Mehrarbeit erklärende Namen zu verwenden und steigert die Lesbarkeit ungemein.
Schauen wir uns mal schrittweise im Einzelnen an, was du vor hast:
  • Zeilendurchschnitt berechnen
    Du füllst eine Liste mit Nullen, addierst die Werte aus einer Matrix und berechnest dann den Zeilendurchschnitt. Das kann `numpy.mean(arr, axis=1)` erledigen.

    Code: Alles auswählen

    import numpy as np
    MATRIX = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
    zeilendurchschnitt = np.mean(MATRIX, axis=1)
    
  • Covarianz Matrix berechnen
    Hier folgen wieder Iterationen über die Anzahl der Elemente der Matrix. Dabei werden Listen befüllt.
    Wie vorgeschlagen sollte hier die Funktion `cov()` das gleiche Ergebnis liefern. Zumindest liefert sie das gleiche Ergebnis wie dein gezeigt Code. Die Dokumentation gibt an, wie die Berechnung beeinflusst werden kann (z. B. Divisior = N oder N-1).

    Code: Alles auswählen

    covariance = np.cov(MATRIX, bias=True)
    
  • Umformung in ein DataFrame, direkt Umformung in ein Array. Warum das Ganze? Kann ersatzlos gestrichen werden.
Wie berechnest du bisher den Abstand (Code)? Kannst du ein Beispiel geben, wie eine Eingangsdaten aussehen, welches Ergebnis du erhältst und welches Ergebnis du erwartest? Im bisher gezeigten Code werden ständig Listen für die Berechnung verwendet, welche zum Schluss in ein Array umgewandelt werden. Dieses wird dann nicht weiter verwendet (`TimeArr` ist kein Array, sondern eine Liste, `CovVarMtx`ebenfalls, `D` ist ein schlechter Name und ein Numpy-Array - wird aber nicht verwendet).
StudArne
User
Beiträge: 4
Registriert: Montag 20. April 2020, 15:39

Danke für die ausführliche Antwort und die ganzen Hinweise!

Sind die Schreibweisen allgemeine Konvention, oder pythonspezifisch? Bisher habe ich nur von den MixedCase als Empfehlung gehört, aber nur privat - geschweige denn, ich hätte in der Uni jemals derartige Hinweise erhalten ^^.

Den Code habe ich hinsichtlich deiner Empfehlungen überarbeitet und sämtliche unnötigen Umformungen rausgenommen (dataframe über panda ist noch drin, für die Zählung der Spaltenanzahl).

Code: Alles auswählen


#___Mahalanobis_Ver_5___
# col = column; com = compare; det = determinante; inv = inverse
import numpy as np
import pandas as pd
import math 

'''------------------------------------------------------------
File Auslesen und in Liste einschreiben
------------------------------------------------------------'''

file = open( "TestDatenKonstrukt_3x3.csv")
row_list = []
start = 0
for line in file.readlines():
    if start > 0:
        full_list = [value for value in line.split(',')]
        filter_list = []
        for i in range(len(full_list)):
            if i > 0:
                filter_list.append(full_list[i])
        row_list.append(filter_list)
    start = start + 1
file.close()
row_array = np.array(row_list)
row_number = len(row_list)

#Umformatierung der Liste
#------------------------------------------------------------

dataframe = pd.DataFrame(row_list, dtype=float)
col_number = 0
col_number = len(dataframe.columns)
print ('Rows/Cols :', row_number, col_number)

matrix = 0
matrix = np.array(dataframe)
print ('matrix: ', matrix)

'''------------------------------------------------------------
Berechnung Zeilendurchschnitt [Zeitreihendurchschnitt]
------------------------------------------------------------'''
'''
time_list = []
for calc_row in range(len(matrix)):
    time_list.append(0)
for column in range(col_number):
    for calc_row in range(len(matrix)):
        time_list[calc_row] += matrix[calc_row][column]    
for calc_row in range(len(matrix)):
    time_list[calc_row] = time_list[calc_row] / col_number
    #print ('Zeilendurchschnitt :', [calc_row], '=', time_list[calc_row])
'''

time_arr = np.mean(matrix, axis=1)
print ('Zeilendurchschnittsarray :', time_arr)

'''------------------------------------------------------------
	CovarianceVarianceMatrix
------------------------------------------------------------'''
'''
cov_var_list =[]
StdDev =[]
CovRow =[]
for calc_row in range(len(matrix)):
    for com_row in range(len(matrix)):
        StdDev = ((matrix[calc_row] - time_arr[calc_row]) * (matrix[com_row]-time_arr[com_row]))
        CovVarEle = sum(StdDev[0:len(StdDev)])/(col_number-1)
        CovRow.append(CovVarEle)    
    cov_var_list.append(CovRow)    
    CovRow = []
cov_var_array = np.array(cov_var_list)
print (cov_var_array)

'''

cov_var_matrix = np.cov(matrix, bias=True)
print ('CovVarMatrix :', '\n', cov_var_matrix)

#Zeilen/Spaltenberechnung
#------------------------------------------------------------
dataframe = pd.DataFrame(cov_var_matrix, dtype=float)
col_number_cov_var_matrix = 0
col_number_cov_var_matrix = len(dataframe.columns)

row_number_cov_var_matrix = 0
row_number_cov_var_matrix = len(cov_var_matrix)

print ('Rows/Cols :', row_number_cov_var_matrix, col_number_cov_var_matrix)


'''------------------------------------------------------------
	Teilberechnungen Mahalanobis
------------------------------------------------------------'''

#Inverse und Determinante, Zwischenchecks
#------------------------------------------------------------

det = np.linalg.det(cov_var_matrix)
print ('det:','\n', det)
inv = np.linalg.inv(cov_var_matrix)
print ('inv:','\n', inv)
print ('_______Check________')
print ('Rückrechnung:', '\n', np.linalg.inv(inv))
print ('Check Einheit','\n', cov_var_matrix.dot(np.linalg.inv(cov_var_matrix))) 

np.savetxt("Inverse.csv", inv, delimiter= ',')




#Alternative - Inverse und Determinante, Zwischenchecks
#------------------------------------------------------------
#Wird hinfällig sobald obere funktioniert - daher Variablen nicht überarbeitet

A = np.array([[4173.25415838,4168.991966,4153.1742671],[4168.991966,4164.73419886,4148.93308044],[4153.1742671,4148.93308044,4133.19442491]])
a = np.linalg.det(A)
print ('DET:', '\n', a)
print ('INV:', '\n', np.linalg.inv(A))
print ('EIN:', '\n', A.dot(np.linalg.inv(A))) 
Z = np.linalg.inv(A)
print ('RÜCK:', '\n', np.linalg.inv(Z))


Hier die konkreten Berechnungen der Mahalanobis-Distanz:
Ich berechne diese über die Wurzel der Doppelsummen der Zeitreihen anstatt über die konventionelle Formel (gibt aber erwartbare Ergebnisse aus).

Code: Alles auswählen

'''------------------------------------------------------------
	Finalberechnung
------------------------------------------------------------'''

#Doppelsummenarray
#------------------------------------------------------------

#'''
zw_erg_3 = 0
doppelsumme = []
for column in range(col_number):
    for calc_row in range(len(matrix)):
        for com_row in range(len(matrix)):
            zw_erg_1 = (matrix[com_row][column] - time_arr[com_row])*inv[calc_row][com_row]
            zw_erg_2 = (matrix[calc_row][column] - time_arr[calc_row]) * zw_erg_1
            #print ('Check Durchlaufindizes :', column, calc_row, com_row)
        zw_erg_3 += zw_erg_2
    doppelsumme.append(zw_erg_3)
#'''

#Wurzel der Arrayelemente --> Mahalanobisarray
#------------------------------------------------------------

#'''
mahalanobis = []
for di in range (len(doppelsumme)):
    end_erg = math.sqrt(abs(doppelsumme[di]))
    mahalanobis.append(end_erg)
    print ('Mahalanobis', di, ' :', mahalanobis[di])
print ('Mahalanobis:', mahalanobis)
#'''



Die np.mean und np.cov Funktionen funktionieren, da danke für die Hinweise, da frag ich mich, warum ich das bei der Recherche übersehen habe, oder ob ich es irgendwann aus Frust einfach selber schreiben wollte ^^.

Allerdings stimmen die Ausgaben immer noch nicht - es ergibt sich keine Einheitsmatrix und auch die Rückrechnung ergibt eine vollkommen andere Matrix als das Original.
Ich mache mich nachher nochmal daran auch die Inverse und die Mahalanobis händisch zu berechnen, darauf habe ich bisher verzichtet, da sich die Inverse ja ganz einfach prüfen lässt (funktioniert bis auf Kommafehler ja auch in der Prüfung der Alternative).

Jetzt bin ich wirklich überfragt - entweder ich übersehe immer noch etwas (deshalb habe ich mal den ganzen Code reingestellt) oder irgendwo geht etwas schief, dass ich bei meinem jetzigen Kenntnisstand schlichtweg nicht verstehe.



Die Eingangsdaten sehen wie folgt aus:
  • DateTime [UTC+1],S1,S2,S3,S4,S5,S6,S7
    2020-01-01 01:05:00,274.7173,399.1,252.1953,822.0775,820.6552,955.2102,889.3412
    2020-01-01 01:10:00,274.6193,398.8621,252.0997,821.8438,819.898,953.3099,888.8602
    2020-01-01 01:15:00,274.5122,398.2077,251.9565,821.8438,819.8048,953.4874,887.6563
    2020-01-01 01:20:00,275.0155,398.973,251.8281,822.0441,820.0313,958.5718,887.2789
    2020-01-01 01:25:00,273.8484,396.1359,251.7402,821.1375,818.6215,953.4493,887.3755
    2020-01-01 01:30:00,273.8858,396.4025,251.3882,821.9096,819.4911,953.4861,889.9638
    2020-01-01 01:35:00,273.6153,396.4895,251.0174,822.7977,820.8263,953.5137,892.1878
    2020-01-01 01:40:00,274.0667,397.0466,250.6688,825.8109,823.6235,957.9278,891.3961
    2020-01-01 01:45:00,272.8335,394.1308,250.3501,823.051,819.9756,954.4159,884.1678
    2020-01-01 01:50:00,272.5716,393.7445,249.9282,819.3125,817.5,953.125,883.3066
Das ist eine auf 10 Zeilen verkürzte Menge - das gleiche habe ich nochmals für 3 Zeilen und nur 3 Spalten.
Beim Einlesen trenne ich die Daten per Komma und schmeiße die Datumsspalte und die Sensorzeile raus, so dass ich die Rohdaten erhalte.


Für die 3x3 Variante habe ich für die Kovarianz folgendes berechnet:
  • Covarianz mit Spaltenanzahl-1
    6259,881237 6253,487949 6229,761401
    6253,487949 6247,101299 6223,39962
    6229,761401 6223,39962 6199,791638

    Covarianz mit Spaltenanzahl
    4173,254158 4168,991966 4153,174267
    4168,991966 4164,734199 4148,93308
    4153,174267 4148,93308 4133,194425
einfachTobi
User
Beiträge: 512
Registriert: Mittwoch 13. November 2019, 08:38

Das sind pythonspezifische Konventionen; hier nachzulesen. Es lohnt sich das einmal durchzulesen, weil es den Code einfach besser lesbar macht.
Dass du verschiedene (Numpy-) Funktionen bzw. deren Möglichkeiten nicht gleich bei der ersten Recherche erkannt hast, wundert mich nicht. Die Denkweise ist etwas speziell und auch herauszufinden, was geht und was nicht geht, ist nicht ganz einfach. Das kommt immer mehr, je länger man sich damit beschäftigt und man kann sicher immer wieder was dazulernen. Zudem ist die Idee über Arrayelemente zu iterieren ja auch erstmal nahe liegend. Das sollte man allerdings tunlichst vermeiden. In der Regel macht man etwas verkehrt, wenn man über Numpy-Arrays oder Pandas-DataFrames iteriert.
Schauen wir uns mal deinen Code weiter an :)
  • Einlesen der Datei. Numpy bietet auch hier eine fertige Funktion: np.loadtext(). Da wir hier nur 3 Zeilen und Spalten prüfen wollen, nehme ich hier den entsprechenden Ausschnitt - kann natürlich final entfernt werden. Dein Codeteil zum auslesen liefert übrigens eine Liste in der Strings stehen inkl. `\n` am Zeilenende. Das gehört da nicht hin, spielt aber keine Rolle mehr, wenn `loadtext()` verwendet wird.

    Code: Alles auswählen

    FILEPATH = "TestDatenKonstrukt_3x3.csv"
    MATRIX = np.loadtxt(FILEPATH, delimiter=',', skiprows=1, usecols=(1, 2, 3, 4, 5, 6, 7))
    MATRIX = MATRIX[:3, :3]
    
  • Die Überführung in ein DataFrame, um die Spalten und Zeilen zu bestimmen ist überflüssig und unnötig kompliziert. Numpy-Arrays haben das `shape`-Attribut. Das scheint mir aber auch wegzufallen, sobald man nicht mehr über die Zeilen iteriert.

    Code: Alles auswählen

    rows = MATRIX.shape[0]
    cols = MATRIX.shape[1]  # cols ist eine geläufige Abkürzung und damit gerade noch in Ordnung mMn
    
Beim Aufräumen und Durchgehen des Codes ist mir folgendes aufgefallen und genau das dürfte dein Problem sein: Die Berechnung der Inversen ist nicht korrekt. Warum weiß ich auch nicht genau. Ich vermute Rundungsprobleme in der Kommazahlrepräsentation oder überlaufende Datentypen. Wenn du die Matrix vorher auf bsp. 4 Stellen rundest, sieht das Ganze schon anders aus:

Code: Alles auswählen

FILEPATH = "TestDatenKonstrukt_3x3.csv"
matrix = np.loadtxt(FILEPATH, delimiter=",", skiprows=1, usecols=(1, 2, 3, 4, 5, 6, 7), dtype=np.float64)
matrix = matrix[:3, :3]

cov_var_matrix = np.round(np.cov(matrix), 4)
cov_var_inverse = np.linalg.inv(cov_var_matrix)
cov_var_det = np.linalg.det(cov_var_matrix)

print("Matrix:\n", matrix)
print("Kovarianzmatrix:\n", cov_var_matrix)
print("Inverse\n", cov_var_inverse)
print("Check Rückführung:\n", np.round(np.linalg.inv(cov_var_inverse), 4))
print("Check Einheit:\n", np.round(cov_var_matrix @ cov_var_inverse, 4))
Wenn dir die Genauigkeit genügt, ist das ein durchaus gangbarer Weg.
Sobald ich etwas mehr Zeit habe würde ich mir auch noch mal den Ansatz zur Berechnung der Mahalonobis-Distanz ansehen. Bei schnellem drauf schauen: Die for-Schleife über die `doppelsumme` kann ebenfalls vereinfacht werden:

Code: Alles auswählen

mahalanobis = np.sqrt(np.abs(doppelsumme))
StudArne
User
Beiträge: 4
Registriert: Montag 20. April 2020, 15:39

Krass, es funktioniert, es funktioniert tatsächlich!!
Genial, danke sehr!! (Es funktioniert sogar mit dem Programmentwurf vor den ganzen Änderungen, interessant, was die Auflösung der Daten für eine heftige Rolle spielt.)

Das macht das Programm auch um einiges übersichtlicher, das merke ich mir für meine nächste Recherche in jedem Fall.

Es läuft auch erstmal mit dem Originaldatensatz - bis es aufgrund der array-Größen abbricht ^^.
Traceback (most recent call last):
File "c:/UserData/Z003N69E/Documents/Dateien/PP_BA/Mahalanobis_Py0.2/Mahalanobis_Py_02/Main Test.py", line 75, in <module>
cov_var_matrix = np.round(np.cov(matrix, bias=True), 4)
File "<__array_function__ internals>", line 5, in cov
File "C:\Users\Z003N69E\AppData\Local\Programs\Python\Python38-32\lib\site-packages\numpy\lib\function_base.py", line 2454, in cov
c = dot(X, X_T.conj())
File "<__array_function__ internals>", line 5, in dot
ValueError: array is too big; `arr.size * arr.dtype.itemsize` is larger than the maximum possible size.
Wo bei ich mir vorstellen kann, dass sich das auf die beschränkte Kapazität meines Rechners zurückführen lässt.

Ich habe in der Dokumentation für np.cov und np.inv leider keinen Hinweis gefunden, wie sich die Berechnung auf float32 beschränken lässt - ich habe auch die eingelesenen Daten testweise mal auf float 32 gesetzt, da bricht er aber auch leider ab.

Gibt es die Möglichkeit die Berechnungen innerhalb eines Programmes allgemein auf einen Datentypen zu beschränken?
Natürlich stellt sich da die Frage, inwieweit die Daten der Berechnungen dann noch gebrauchbar sind, aber erstmal würde ich gerne sehen, dass es für den Testdatensatz dann überhaupt läuft ^^.



Ich danke dir auf jeden Fall vielmals! Nicht nur, weil das Programm jetzt endlich macht was es soll, sondern weil deine Hilfestellungen mir auch nochmal viel gezeigt haben, vielen, vielen Dank!
Benutzeravatar
__blackjack__
User
Beiträge: 14047
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@StudArne: Falls genug Arbeitsspeicher vorhanden ist, ist vielleicht auch einfach das 32-Bit-Python der beschränkende Faktor‽
“Vir, intelligence has nothing to do with politics!” — Londo Mollari
einfachTobi
User
Beiträge: 512
Registriert: Mittwoch 13. November 2019, 08:38

Schön, dass es klappt.
Verwendest du ein 32-bit Python? Bei einem Array, das den RAM übersteigt hätte ich eher einen MemoryError erwartet. 70.000 Daten in einem Array sind eigentlich überschaubar. Obwohl ja durch die Rechenoperationen noch mehr Platz benötigt wird, aber auch da sehe ich jetzt nicht das große Problem. Versuchs mal mit einem 64-bit Python, falls das nicht schon der Fall ist.
Ich muss ehrlich sagen, dass mir die Berechnung der Distanz gerade etwas unklar ist, weil ich nicht weiß welches deine Variablen sind (eine Reihe = eine Variable in der Matrix?) und wie deine Zusammenfassung erfolgen soll (Summenbildung). Ebenso ehrlich muss ich gestehen, dass ich wenig Lust habe die Schleife zu zerpflücken. Ich gehe aber mal davon aus, dass das ähnlich zusammenfassbar ist. Das könnte ein Anhalt sein:

Code: Alles auswählen

import numpy as np
FILEPATH = "TestDatenKonstrukt_3x3.csv"
matrix = np.loadtxt(FILEPATH, delimiter=",", skiprows=1, usecols=(1, 2, 3, 4, 5, 6, 7))
cov_var_matrix = np.round(np.cov(matrix), 4)
cov_var_inverse = np.round(np.linalg.inv(cov_var_matrix), 4)
time_mean = np.round(np.mean(matrix, axis=1), 4)
matrix_minus_mean = (matrix.T - time_mean).T
mahalanobis = np.sqrt(np.abs(np.sum(matrix_minus_mean.T @ cov_var_inverse @ matrix_minus_mean, axis=1)))
print(mahalanobis)
Wie du siehst und wahrscheinlich auch an der Performance merkst, lohnt es sich bei Numpy darüber zu grübeln, welche Berechnungen mit einer Funktion für alle Elemente/Spalten/Reihe vorgenommen werden können.
Antworten