Ich möchte eine Gruppe per Operation auf einen Pandas DataFrame anwenden, ohne eine Aggregation durchzuführen. Stattdessen möchte ich nur, dass die hierarchische Struktur im MultiIndex widergespiegelt wird.Pandas DataFrame-Gruppierung zum Generieren eines numerischen Multiindex
import pandas as pd
def multi_index_group_by(df, columns):
# TODO: How to write this? (Hard-coded to give the desired result for the example.)
if columns == ["b"]:
df.index = pd.MultiIndex(levels=[[0,1],[0,1,2]], labels=[[0,1,0,1,0],[0,0,1,1,2]])
return df
if columns == ["c"]:
df.index = pd.MultiIndex(levels=[[0,1],[0,1],[0,1]], labels=[[0,1,0,1,0],[0,0,0,1,1],[0,0,1,0,0]])
return df
if __name__ == '__main__':
df = pd.DataFrame({
"a": [0,1,2,3,4],
"b": ["b0","b1","b0","b1","b0"],
"c": ["c0","c0","c0","c1","c1"],
})
print(df.index.values) # [0,1,2,3,4]
# Add level of grouping
df = multi_index_group_by(df, ["b"])
print(df.index.values) # [(0, 0) (1, 0) (0, 1) (1, 1) (0, 2)]
# Examples
print(df.loc[0]) # Group 0
print(df.loc[1,1]) # Group 1, Item 1
# Add level of grouping
df = multi_index_group_by(df, ["c"])
print(df.index.values) # [(0, 0, 0) (1, 0, 0) (0, 0, 1) (1, 1, 0) (0, 1, 0)]
# Examples
print(df.loc[0]) # Group 0
print(df.loc[0,0]) # Group 0, Sub-Group 0
print(df.loc[0,0,1]) # Group 0, Sub-Group 0, Item 1
Was wäre der beste Weg multi_index_group_by
zu implementieren? Die folgenden fast funktioniert, aber der resultierende Index ist nicht numerisch:
index_columns = []
# Add level of grouping
index_columns += ["b"]
print(df.set_index(index_columns, drop=False))
# Add level of grouping
index_columns += ["c"]
print(df.set_index(index_columns, drop=False))
Edit: Um zu klären, in dem Beispiel, sollte die endgültige Indizierung äquivalent zu:
[
[ #b0
[ #c0
{"a": 0, "b": "b0", "c": "c0"},
{"a": 2, "b": "b0", "c": "c0"},
],
[ #c1
{"a": 4, "b": "b0", "c": "c1"},
]
],
[ #b1
[ #c0
{"a": 1, "b": "b1", "c": "c0"},
],
[ #c1
{"a": 3, "b": "b1", "c": "c1"},
]
]
]
Edit: Hier ist das beste, was ich bisher habe:
def autoincrement(value=0):
def _autoincrement(*args, **kwargs):
nonlocal value
result = value
value += 1
return result
return _autoincrement
def swap_levels(df, i, j):
order = list(range(len(df.index.levels)))
order[i], order[j] = order[j], order[i]
return df.reorder_levels(order)
def multi_index_group_by(df, columns):
new_index = df.groupby(columns)[columns[0]].aggregate(autoincrement())
result = df.join(new_index.rename("_new_index"), on=columns)
result.set_index('_new_index', append=True, drop=True, inplace=True)
result.index.name = None
result = swap_levels(result, -2, -1)
return result
Es gibt das korrekte Ergebnis, mit Ausnahme des letzten leve l, das ist unverändert. Ich habe immer noch das Gefühl, dass es noch einiges zu verbessern gibt.
Was die Bedeutung Ihrer fest einprogrammiert ist Multiindex? – desiato
@desiato Es ist ein stetig wachsender nd-Index (siehe Beispiele). Zum Beispiel (0, 1, 2, ...) bedeutet: Gruppe 0, Untergruppe 1, Untergruppe 2 usw. – kloffy
Im Wesentlichen möchte ich in der Lage sein, Zeilen auf dieselbe Weise zu adressieren, in die Sie indizieren würden eine verschachtelte Liste – kloffy