scal dwie ramki danych i dodaj poziom kolumny z nazwami

9

Cześć. Przekopałem się przez metody konkatacji, łączenia i łączenia pand i nie mogę znaleźć tego, czego chcę.

Załóżmy, że mam dwie ramki danych

A = pd.DataFrame("A",index=[0,1,2,3,4],columns=['Col 1','Col 2','Col 3'])
B = pd.DataFrame("B",index=[0,1,2,3,4],columns=['Col 1','Col 2','Col 3'])
>>> A
  Col 1 Col 2 Col 3
0     A     A     A
1     A     A     A
2     A     A     A
3     A     A     A
4     A     A     A
>>> B
  Col 1 Col 2 Col 3
0     B     B     B
1     B     B     B
2     B     B     B
3     B     B     B
4     B     B     B

Teraz chcę utworzyć nową ramkę danych ze scalonymi kolumnami. Myślę, że najłatwiej jest to wytłumaczyć, jeśli utworzę indeks wielokrotny dla tego, jak chcę kolumn

index = pd.MultiIndex.from_product([A.columns.values,['A','B']])
>>> index
MultiIndex(levels=[['Col 1', 'Col 2', 'Col 3'], ['A', 'B']],
           labels=[[0, 0, 1, 1, 2, 2], [0, 1, 0, 1, 0, 1]])

Teraz, jeśli utworzę pustą ramkę danych z tym indeksem wielu kolumn

empty_df = pd.DataFrame('-',index=A.index,columns=index)
>>> empty_df
  Col 1    Col 2    Col 3
      A  B     A  B     A  B
0     -  -     -  -     -  -
1     -  -     -  -     -  -
2     -  -     -  -     -  -
3     -  -     -  -     -  -
4     -  -     -  -     -  -

Moje pytanie brzmi: jakiego rodzaju scalenia, konkatacji lub łączenia używam, aby to uzyskać? Próbowałem wielu rzeczy dla konkat ... wewnętrznej, zewnętrznej itp. Nie mogę znaleźć tego, czego chcę. Jedyne, co mogę wymyślić, to zrobić pustą ramkę danych, a następnie uzupełnić.

Edycja: Po wypróbowaniu odpowiedzi Jezraela jest blisko, ale nie do końca. To, czego chcę, to rodzaj zagnieżdżonych kolumn? Na przykład

empty_df['Col 1']
>>> empty_df['Col 1']
   A  B
0  -  -
1  -  -
2  -  -
3  -  -
4  -  -

Lub

>>> empty_df['Col 1']['A']
0    -
1    -
2    -
3    -
4    -
Name: A, dtype: object

Więc to jest rozwiązanie, które wymyśliłem, ale polega na iteracji po kolumnach.

row_idx = A.index.union(B.index)
col_idx = pd.MultiIndex.from_product([A.columns.values,['A','B']])
new_df = pd.DataFrame('-',index=row_idx,columns=col_idx)
for column in A.columns:
   new_df.loc[:,(column,'A')] = A[column]
   new_df.loc[:,(column,'B')] = B[column]
>>> new_df
  Col 1    Col 2    Col 3
      A  B     A  B     A  B
0     A  B     A  B     A  B
1     A  B     A  B     A  B
2     A  B     A  B     A  B
3     A  B     A  B     A  B
4     A  B     A  B     A  B
>>> new_df['Col 1']
   A  B
0  A  B
1  A  B
2  A  B
3  A  B
4  A  B
>>> new_df['Col 1']['A']
0    A
1    A
2    A
3    A
4    A
Name: A, dtype: object
Melendowskiego
źródło

Odpowiedzi:

8

Myślę, że trzeba concatz keysparametrem a axis=1, ostatnia zmiana kolejności poziomów przez DataFrame.swapleveli sortowania według pierwszego poziomu przez DataFrame.sort_index:

df1 = (pd.concat([A, B], axis=1, keys=('A','B'))
         .swaplevel(0,1, axis=1)
         .sort_index(axis=1, level=0))
print (df1)
  Col 1    Col 2    Col 3   
      A  B     A  B     A  B
0     A  B     A  B     A  B
1     A  B     A  B     A  B
2     A  B     A  B     A  B
3     A  B     A  B     A  B
4     A  B     A  B     A  B

Do pracy MultiIndexjest możliwe użycie DataFrame.xs:

print (df1.xs('Col 1', axis=1, level=0))
   A  B
0  A  B
1  A  B
2  A  B
3  A  B
4  A  B

Jeśli chcesz wybierz MultiIndex columnużyj tuple:

print (df1[('Col 1', 'A')])
0    A
1    A
2    A
3    A
4    A
Name: (Col 1, A), dtype: object

Jeśli chcesz, wybierz według indeksu i według kolumny loc:

print (df1.loc[4, ('Col 1', 'A')])
A
jezrael
źródło
2
To zrobiło! Dziękuję Ci bardzo!
Melendowski