Mam dataframe zorganizowany tak:Dodaj kolumnę z GroupBy na hierarchicznej dataframe
First A B
Second bar baz foo bar baz foo
Third cat dog cat dog cat dog cat dog cat dog cat dog
0 3 8 7 7 4 7 5 3 2 2 6 2
1 8 6 5 7 8 7 1 8 6 0 3 9
2 9 2 2 9 7 3 1 8 4 1 0 8
3 3 6 0 6 3 2 2 6 2 4 6 9
4 7 6 4 3 1 5 0 4 8 4 8 1
więc są trzy poziomy kolumny. Chcę dodać nową kolumnę na drugim poziomie, gdzie dla każdego z trzecich poziomów wykonywane jest obliczenie, na przykład "nowy" = "foo" + "słupek". Tak otrzymaną dataframe wyglądałby następująco:
First A B
Second bar baz foo new bar baz foo new
Third cat dog cat dog cat dog cat dog cat dog cat dog cat dog cat dog
0 3 8 7 7 4 7 7 15 5 3 2 2 6 2 11 5
1 8 6 5 7 8 7 16 13 1 8 6 0 3 9 4 17
2 9 2 2 9 7 3 16 5 1 8 4 1 0 8 1 16
3 3 6 0 6 3 2 6 8 2 6 2 4 6 9 8 15
4 7 6 4 3 1 5 8 11 0 4 8 4 8 1 8 5
Znalazłem obejście który jest wymieniony na końcu tego postu, ale nie jest w ogóle „panda w stylu” i podatne na błędy. Funkcja zastosowania lub przekształcenia w grupie wydaje się być właściwą drogą, ale po wielu próbach nadal nie udaje mi się. Pomyślałem poprawny sposób powinno być coś takiego:
def func(data):
fi = data.columns[0][0]
th = data.columns[0][2]
data[(fi,'new',th)] = data[(fi,'foo',th)] + data[(fi,'bar',th)]
print data
return data
print grouped.apply(func)
Nowa kolumna jest prawidłowo dodanej wewnątrz funkcji, ale nie jest zwracana. Używanie tej samej funkcji z transformacją działałoby, gdyby kolumna "nowa" już istniała w pliku df, ale jak dodać nową kolumnę na określonym poziomie "w locie" lub przed grupowaniem?
Kod do generowania DF próbka jest:
import pandas, itertools
first = ['A','B']
second = ['foo','bar','baz']
third = ['dog', 'cat']
tuples = []
for tup in itertools.product(first, second, third):
tuples.append(tup)
columns = pandas.MultiIndex.from_tuples(tuples, names=['First','Second','Third'])
data = np.random.randint(0,10,(5, 12))
df = pandas.DataFrame(data, columns=columns)
A mój obejście:
dfnew = None
grouped = df.groupby(by=None, level=[0,2], axis=1)
for name, group in grouped:
newparam = group.xs('foo', axis=1, level=1) + group.xs('bar', axis=1, level=1)
dftmp = group.join(pandas.DataFrame(np.array(newparam), columns=pandas.MultiIndex.from_tuples([(group.columns[0][0], 'new', group.columns[0][2])], names=['First','Second', 'Third'])))
if dfnew is None:
dfnew = dftmp
else:
dfnew = pandas.concat([dfnew, dftmp], axis=1)
print dfnew.sort_index(axis=1)
Wich działa, ale stworzenie nowego dataframe dla każdej grupy i 'ręcznie' przypisanie poziomów jest naprawdę zła praktyka.
Jaki jest właściwy sposób, aby to zrobić? Znalazłem kilka postów poświęconych podobnym pytaniom, ale wszystkie miały tylko jeden poziom kolumn i właśnie to im usiłowało.
Tworzenie nowej kolumny w oparciu o zgrupowane wartości to zadanie przekształcić , ale nie wiem, czy tranform może generować wiele kolumn. Postąpiłbym tak samo, jak ty. BTW pod maską transformuje także tworzy nową ramkę dla każdej grupy i konkluduje je wszystkie na końcu. –
Mając mechanizm zastosowania/transformowania, można wyprowadzać wartości strukturalne i rozgłaszane na kolumny (tj. Jeśli krotka jest tworzona przez zastosowaną funkcję, komponenty przechodzą w oddzielnych kolumnach zamiast krotki stającej się elementem atomowym w jednej kolumnie) być fantastyczną cechą, nawet jeśli jest to tylko cukier syntaktyczny. Prawdopodobnie z inną nazwą metody, aby było jasne (zastosowanie lub coś podobnego lub słowo kluczowe splitseq = Prawda w zastosowaniu). – meteore