Fragmentierten pandas DataFrame neu strukturieren

mit matplotlib, NumPy, pandas, SciPy, SymPy und weiteren mathematischen Programmbibliotheken.
Antworten
ytroksit
User
Beiträge: 6
Registriert: Dienstag 6. Juni 2023, 07:42

Hi,

ich habe einen Datensatz, der durch einen Fehler falsch strukturiert ist und nun in Form gebracht werden soll.

Der falsch strukturiere Datensatz besteht aus mehreren Datenblöcken wovon jeder 8 Zeilen und 12 Spalten hat. Die einzelnen Datenblöcke wurden zu fortlaufenden Zeitpunkten aufgezeichnet:

Code: Alles auswählen

	Temperature(¡C)	1	2	3	4	5	6	7	8	9	10	11	12
00:00:00	36.8	0.329626972	0.166650871	0.561289099	0.994167021	0.56819283	0.427220331	0.338158063	0.108898469	0.747300526	0.152895491	0.349025426	0.623191546
		0.820297818	0.693138112	0.250049932	0.449135986	0.40266938	0.438780538	0.775284611	0.62102487	0.916580273	0.053514642	0.303613922	0.423623227
		0.388769891	0.835573632	0.043319931	0.209712452	0.141152595	0.568358985	0.534899386	0.431245891	0.628061268	0.550915045	0.870781791	0.393417482
		0.156394628	0.58742931	0.123775143	0.421432949	0.037761012	0.597365166	0.185773111	0.439944639	0.51907977	0.048352044	0.58683484	0.564276435
		0.296206647	0.703224293	0.053833327	0.007740982	0.491391998	0.339186416	0.366115874	0.230498755	0.736740045	0.070965299	0.049564823	0.109908292
		0.050318585	0.778930796	0.392869023	0.322292343	0.616463037	0.403811692	0.816787847	0.169035223	0.383024492	0.06515802	0.727704186	0.922490416
		0.534573942	0.264565702	0.077201483	0.837257537	0.001285578	0.750625786	0.176934907	0.751408245	0.841819117	0.581603177	0.336969975	0.704961892
		0.110192449	0.571907434	0.12432668	0.063021237	0.489477134	0.43074326	0.178482753	0.673657389	0.426610641	0.693233184	0.431220454	0.291261887
													
00:00:15	36.6	0.12600709	0.787025859	0.949541502	0.1545106	0.11443873	0.318470331	0.452300411	0.230617766	0.298019479	0.526522832	0.302658607	0.731114341
		0.816397602	0.084458485	0.009626854	0.865405753	0.224999401	0.226861594	0.394482552	0.621324423	0.666649319	0.660006708	0.682849466	0.469305098
		0.729385863	0.233649805	0.175145041	0.265569169	0.237573135	0.608715323	0.258729076	0.185915391	0.355038761	0.156297122	0.579782381	0.011803054
		0.410274882	0.961303112	0.243093733	0.383210984	0.239873516	0.993480871	0.143625091	0.854451008	0.564974224	0.503088874	0.193255537	0.450472701
		0.312160265	0.170105195	0.221418842	0.501146449	0.083156615	0.10913748	0.020803817	0.003275421	0.278928838	0.213011642	0.157723202	0.798753321
		0.10847298	0.993194937	0.572161717	0.562005131	0.461269059	0.551239675	0.66013571	0.815974983	0.432604616	0.301805693	0.101051672	0.455395232
		0.043164089	0.998600816	0.069393515	0.37659051	0.815489587	0.44525346	0.006030599	0.711396133	0.850724017	0.238697088	0.22818586	0.617209076
		0.640562878	0.369595835	0.480452624	0.606627048	0.789491004	0.88966775	0.116692365	0.647903931	0.158383335	0.655933907	0.0992814	0.875067617
													
00:00:30	37.1	0.586448301	0.20578325	0.748251807	0.173480353	0.800822728	0.232700269	0.110812624	0.036765183	0.474364087	0.555092856	0.689746594	0.868936498
		0.964190379	0.95075048	0.125784067	0.596669936	0.698159598	0.638729024	0.26028743	0.752683804	0.957901691	0.531032818	0.187437307	0.14204391
		0.018110853	0.97797046	0.325855917	0.005200198	0.178591695	0.314882681	0.719373308	0.591235036	0.705273939	0.632968948	0.399202461	0.219586377
		0.35240313	0.747898809	0.05590492	0.480249142	0.99023303	0.487922421	0.398712082	0.413247989	0.758971427	0.836988555	0.187203337	0.185643573
		0.624751903	0.107251944	0.830980176	0.187787471	0.019290193	0.832865941	0.136958714	0.940441201	0.098368839	0.524885624	0.620479876	0.651046453
		0.064812657	0.333107314	0.556134932	0.295475477	0.855492742	0.45362721	0.43451413	0.24368815	0.418933686	0.307498185	0.309693857	0.089442894
		0.980913736	0.560737072	0.029163956	0.347355799	0.523735544	0.90507383	0.422374469	0.82877731	0.279454743	0.54747391	0.770331051	0.49917395
		0.791488402	0.968132681	0.833609611	0.752368955	0.968199273	0.064920017	0.379649844	0.665575891	0.163898453	0.269428968	0.742775388	0.927736445
Die zusammenhängen Datenreihen ergeben sich aus Zeile und Spalte als Koordinate. D. h., der DataFrame soll eigentlich so ausschauen:

Code: Alles auswählen

Zeitpunkt	A1	A2	...	A12	...	B1	B2	...	B12
00:00:00	0.329626972	0.166650871	...	0.623191546	0.820297818	0.693138112	...	0.423623227
00:00:15	0.12600709	0.787025859	...	0.731114341	0.816397602	0.084458485	...	0.469305098
00:00:30	0.586448301	0.20578325	...	0.868936498	0.964190379	0.95075048	...	0.14204391
Ich habe hinbekommen, die jeweils erste Zeile entsprechend zu extrahieren mit diesem Code:

Code: Alles auswählen

for col in df.columns:
    df2[col] = [df.loc[i, col] for i in range(0, df.shape[0], 8)]
Mit pd.concat(), pd.join(), bin ich irgendwie nicht weiter gekommen. Daher bin ich für ein paar Vorschläge dankbar. :)
Sirius3
User
Beiträge: 17754
Registriert: Sonntag 21. Oktober 2012, 17:20

Wenn man über die Zeilen eines Dataframes iteriert, macht man in 99% der Fälle etwas falsch.
Erster Schritt wäre, die Blöcke und Zeilen zu identifizieren:

Code: Alles auswählen

df[['block','line']] = list(zip(*divmod(np.arange(len(df)), 9)))
Dann kann man die selben Zeilen gruppieren:

Code: Alles auswählen

groups = df.groupby('line')
Um dann die einzelnen Gruppen zu mergen:

Code: Alles auswählen

full_df = groups.get_group(0)
for index in range(1, 8):
    full_df = full_df.merge(groups.get_group(index), on='block')
ytroksit
User
Beiträge: 6
Registriert: Dienstag 6. Juni 2023, 07:42

Das Iterieren nicht die effizienteste Lösung ist, ist mir bewusst, aber es ist halt verständlicher.

Danke für deine Idee! Leider produziert einige Fehlermeldungen und bringt den Rechner ob der nötigen Menge Speichers ganz schön ins Schwitzen. Ich habe aber gesehen, dass der full_df die Daten in der falschen Reihenfolge enthält.

Ich habe die Zeilen und Blöcke nun so generiert:

Code: Alles auswählen

rows = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H']
lines = int(df.shape[0])
blocks = int(lines / len(rows))

df['line'] = (rows * (blocks + 1))[:lines]
df['block'] = [i for i in range(8) for block in range(blocks)]
Das benennt die 8 Zeilen je Block in A, B, C, etc. und weist jedem Block seine Nummer zu. Über den Rest muss ich noch weiter grübeln.

Vielleicht ist meine Idee auch nicht ganz klar. Vereinfacht möchte ich von

Code: Alles auswählen

Block 1	1	2	3	4
A	A1	A2	A3	A4
B	B1	B2	B3	B4
C	C1	C2	C3	C4


Block 2	1	2	3	4
A	A1	A2	A3	A4
B	B1	B2	B3	B4
C	C1	C2	C3	C4
zu

Code: Alles auswählen

A1	A2	A3	A4	B1	B2	B3	B4	C1	C2	C3	C4
Wert A1/Block 1	Wert A2/Block 1
Wert A1/Block 2	Wert A2/Block 2
ytroksit
User
Beiträge: 6
Registriert: Dienstag 6. Juni 2023, 07:42

Ich habe eine Lösung gefunden, die NumPy zur Umformung des DataFrames nutzt:

Code: Alles auswählen

# Anzahl der Messzeitpunkte (erste Spalte )entspricht den Datenblöcken bzw. Messungen
timepoints = df.iloc[:, 0].dropna()
number_timepoints = len(timepoints)

# DataFrame basierend auf Anzahl der Messungen umstrukturieren
df = pd.DataFrame(df.to_numpy().reshape(len(timepoints), -1))
Da durch die Konvertierung über NumPy die Spaltennamen verloren gehen, müssen diese neu aufgebaut werden. Die Messung erfolgt in einer Matrix aus 8 Reihen und 12 Spalten, wobei Reihen mit Buchstaben und Spalten mit Zahlen nummeriert sind. Daher:

Code: Alles auswählen

# Hilfsspalte für Zuordnung Messwert–Reihe
rows = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H']
df['row'] = (rows * number_timepoints)

# Umformen der Spaltennamen in 2D Array nach 12 Spalten + 1 Spalte für die Reihe
# (Spalten mit Zeit- und Temperaturwerten müssen ggf. entfernt werden)
cols = cols.reshape(-1, 13)

# Iterieren durch den 2D-Array um Reihe mit Spalte zu verbinden
mappings = {}
for cols_list in cols:
    for idx, col in enumerate(cols_list[:-1], start=1):
        mappings[col] = df[cols_list[-1]].iloc[0] + str(idx)

df.rename(columns=mappings, inplace=True)
Antworten