# import package
import pandas as pd

Problem

Mam ramkę danych:

data = {'row1': ['a', 'A', 'B', 'b'],
        'row2': ['a', 'b', 'c', 'd'],
        'row3': ['a', 'b', 'd', 'D']}
df = pd.DataFrame.from_dict(data, orient='index', columns=['col'+str(x) for x in range(4)])

Który wygląda następująco:

enter image description here

Mam również listę zajęć równoważnych. Każda klasa równoważności składa się z przedmiotów, które są traktowane jako równoważne.

equivalenceClasses={'classA':['a','A'],
                    'classB':['b','B'],
                    'classC':['c','C'],
                    'classD':['d','D']}

Chciałbym utworzyć dataframe, w którym wiersze w powyższym dataframe zostaną zastąpione nazwami klasy równoważności, litery w rzędzie należą do . (Każda klasa równoważności powinna pojawić się nie więcej niż raz z rzędu, a my powinniśmy używać NaN s do wierszy po podkładkach, w których nie wszystkie kolumny są fille według nazwy klasy równoważnej). Tj. Chcę tego wyjścia:

enter image description here


Moja metoda

Osiągam cel przez:

def differentClasses(colvalues):
    return list(set([equivalenceClassName for colvalue in colvalues
                                          for equivalenceClassName, equivalenceClass in zip(equivalenceClasses.keys(),
                                                                                   equivalenceClasses.values())
                                          if colvalue in equivalenceClass]))

(na zagnieżdżonej liście Rozumienie.)

df['classes'] = df.apply(lambda row : differentClasses(row['col'+str(x)] for x in range(4)), axis = 1) 

(Pod wpływem . )

Wygląda na to df:

enter image description here

Zakończ:

result_df = pd.DataFrame(df['classes'].tolist(),index=df.index,columns=['classcol'+str(x) for x in range(4)])

result_df jest żądaną wyjściem powyżej.


Pytanie

Czy istnieje bardziej standardowy sposób na to? Coś jak:

df.equivalenceClassify(equivalenceClassList)

I dostaję moją produkcję?

2
zabop 4 sierpień 2020, 00:14

1 odpowiedź

Najlepsza odpowiedź

Potrzebujemy stworzenia nowego dyktatu na podstawie oryginalnego {x0}}, a następnie po prostu zrobić replace

from collections import ChainMap
d = dict(ChainMap(*[dict.fromkeys(y,x) for x , y in equivalenceClasses.items()]))
df = df.replace(d)
Out[299]: 
        col0    col1    col2    col3
row1  classA  classA  classB  classB
row2  classA  classB  classC  classD
row3  classA  classB  classD  classD

Następnie

df = df.mask(df.apply(pd.Series.duplicated,1))
Out[307]: 
        col0    col1    col2    col3
row1  classA     NaN  classB     NaN
row2  classA  classB  classC  classD
row3  classA  classB  classD     NaN
2
BENY 3 sierpień 2020, 21:20