Вземете уникални стойности и тяхното появяване от един кадър с данни в нов кадър с данни с помощта на Pandas DataFrame

Искам да превърна моята рамка от данни с неотличими стойности под всяка заглавка на колона в рамка от данни с различни стойности под всяка заглавка на колона с тяхното появяване в тяхната конкретна колона до нея. Пример:

Първоначалната ми рамка с данни се вижда отдолу:

A       B       C       D
0       CEN     T2      56
2       DECEN   T2      45
3       ONBEK   T2      84
NaN     CEN     T1      59
3       NaN     T1      87
NaN     NaN     T2      NaN
0       NaN     NaN     98
NaN     CEN     NaN     23
NaN     CEN     T1      65

където A, B, C и D са заглавките на колоните с всеки 9 стойности под тях (включени празни места).

Моят предпочитан изходен кадър с данни трябва да изглежда така: (първо колона с уникални стойности за всяка колона в оригиналния кадър с данни и до него тяхното появяване в тази конкретна колона)

A       B       C       D       A       B       C       D
0       CEN     T2      56      2       4       4       1
2       DECEN   T1      45      1       1       3       1
3       ONBEK   NaN     84      2       1       NaN     1
Nan     NaN     NaN     59      NaN     NaN     NaN     1
NaN     NaN     NaN     87      NaN     NaN     NaN     1
NaN     NaN     NaN     98      NaN     NaN     NaN     1
NaN     NaN     NaN     23      NaN     NaN     NaN     1
NaN     NaN     NaN     65      NaN     NaN     NaN     1

където A, B, C и D са заглавките на колоните с под тях първо отделните стойности за всяка колона от оригиналния .csv-файл и до него появата на всеки елемент в тяхната конкретна колона.

Някой идеи?

Кодът по-долу се използва за извеждане на уникалните стойности от всяка колона в нова рамка с данни. Опитах се да направя нещо с .value_counts, за да получа събитието във всяка колона, но там не успях да го вкарам отново в една рамка с данни с уникалните стойности..

df
new_df=pd.concat([pd.Series(df[i].unique()) for i in df.columns], axis=1)
new_df.columns=df.columns
new_df

person Matthi9000    schedule 14.02.2020    source източник
comment
колона D има NaN на входа, но не и на изхода?   -  person anky    schedule 14.02.2020
comment
Ами моят DataFrame се чете от .csv-файл. и Python чете празни клетки като NaN в DataFrame.. така че наистина не трябва да се появява в изхода ;-) (ако не съм прав)   -  person Matthi9000    schedule 14.02.2020


Отговори (1)


Трудната част е да поддържате стойностите на колоните във всеки ред подравнени. За да направите това, трябва да конструирате нов кадър с данни от unique и pd.concat с value_counts карта към всяка колона на този нов кадър с данни.

new_df = (pd.DataFrame([df[c].unique() for c in df], index=df.columns).T
            .dropna(how='all'))

df_final = pd.concat([new_df, *[new_df[c].map(df[c].value_counts()).rename(f'{c}_Count') 
                                   for c in  df]], axis=1).reset_index(drop=True)

Out[1580]:
     A      B    C   D  A_Count  B_Count  C_Count  D_Count
0    0    CEN   T2  56      2.0      4.0      4.0        1
1    2  DECEN   T1  45      1.0      1.0      3.0        1
2    3  ONBEK  NaN  84      2.0      1.0      NaN        1
3  NaN    NaN  NaN  59      NaN      NaN      NaN        1
4  NaN    NaN  NaN  87      NaN      NaN      NaN        1
5  NaN    NaN  NaN  98      NaN      NaN      NaN        1
6  NaN    NaN  NaN  23      NaN      NaN      NaN        1
7  NaN    NaN  NaN  65      NaN      NaN      NaN        1

Ако трябва само да поддържате подравняване между всяка двойка колони и техния брой, като A - A_Count, B - B_Count..., просто използвайте value_counts с reset_index някои команди, за да промените имената на осите

cols = df.columns.tolist() + (df.columns + '_Count').tolist()
new_df = pd.concat([df[col].value_counts(sort=False).rename_axis(col).reset_index(name=f'{col}_Count') 
                        for col in df], axis=1).reindex(new_cols, axis=1)

Out[1501]:
     A      B    C     D  A_Count  B_Count  C_Count  D_Count
0  0.0  ONBEK   T2  56.0      2.0      1.0      4.0        1
1  2.0    CEN   T1  45.0      1.0      4.0      3.0        1
2  3.0  DECEN  NaN  84.0      2.0      1.0      NaN        1
3  NaN    NaN  NaN  59.0      NaN      NaN      NaN        1
4  NaN    NaN  NaN  87.0      NaN      NaN      NaN        1
5  NaN    NaN  NaN  98.0      NaN      NaN      NaN        1
6  NaN    NaN  NaN  23.0      NaN      NaN      NaN        1
7  NaN    NaN  NaN  65.0      NaN      NaN      NaN        1
person Andy L.    schedule 14.02.2020
comment
Това е, перфектно!! Няма ли начин да получите същия резултат като при първия вариант, освен чрез нулиране на индекса (сега ред номер 5 липсва)? Имате ли представа защо някои от стойностите се записват като цели числа (напр. „1“, но други като десетични знаци (напр. „1,0“)? - person Matthi9000; 14.02.2020
comment
@Matthi9000: О, просто е. Просто добавете допълнително reset_index(drop=True). Редактирах отговора. На 1 и 1.0, когато колоната има NaN стойност, нейният dtype е принуден да бъде float, така че 1 се преобразува в 1.0 - person Andy L.; 14.02.2020