unikalne kombinacje wartości w wybranych kolumnach ramki danych pandy i liczby

109

Mam swoje dane w ramce danych pandy w następujący sposób:

df1 = pd.DataFrame({'A':['yes','yes','yes','yes','no','no','yes','yes','yes','no'],
                   'B':['yes','no','no','no','yes','yes','no','yes','yes','no']})

Więc moje dane wyglądają tak

----------------------------
index         A        B
0           yes      yes
1           yes       no
2           yes       no
3           yes       no
4            no      yes
5            no      yes
6           yes       no
7           yes      yes
8           yes      yes
9            no       no
-----------------------------

Chciałbym przekształcić go w inną ramkę danych. Oczekiwane dane wyjściowe można wyświetlić w następującym skrypcie w języku Python:

output = pd.DataFrame({'A':['no','no','yes','yes'],'B':['no','yes','no','yes'],'count':[1,2,4,3]})

Tak więc mój oczekiwany wynik wygląda tak

--------------------------------------------
index      A       B       count
--------------------------------------------
0         no       no        1
1         no      yes        2
2        yes       no        4
3        yes      yes        3
--------------------------------------------

Właściwie mogę znaleźć wszystkie kombinacje i policzyć je za pomocą następującego polecenia: mytable = df1.groupby(['A','B']).size()

Okazuje się jednak, że takie kombinacje są w jednej kolumnie. Chciałbym oddzielić każdą wartość w kombinacji do innej kolumny, a także dodać jeszcze jedną kolumnę dla wyniku zliczania. czy jest to możliwe do zrobienia? Czy mogę prosić o sugestie? Z góry dziękuję.

Ratchainant Thammasudjarit
źródło

Odpowiedzi:

176

Możesz groupbyna kolumnach „A” i „B” i wywołać sizea potem reset_indexi renamewygenerowaną kolumnę:

In [26]:

df1.groupby(['A','B']).size().reset_index().rename(columns={0:'count'})
Out[26]:
     A    B  count
0   no   no      1
1   no  yes      2
2  yes   no      4
3  yes  yes      3

aktualizacja

Małe wyjaśnienie, grupując w 2 kolumny, grupuje się wiersze, w których wartości A i B są takie same, nazywamy to, sizeco zwraca liczbę unikalnych grup:

In[202]:
df1.groupby(['A','B']).size()

Out[202]: 
A    B  
no   no     1
     yes    2
yes  no     4
     yes    3
dtype: int64

Więc teraz, aby przywrócić zgrupowane kolumny, wywołujemy reset_index:

In[203]:
df1.groupby(['A','B']).size().reset_index()

Out[203]: 
     A    B  0
0   no   no  1
1   no  yes  2
2  yes   no  4
3  yes  yes  3

To przywraca indeksy, ale agregacja rozmiaru jest przekształcana w wygenerowaną kolumnę 0, więc musimy zmienić nazwę tego:

In[204]:
df1.groupby(['A','B']).size().reset_index().rename(columns={0:'count'})

Out[204]: 
     A    B  count
0   no   no      1
1   no  yes      2
2  yes   no      4
3  yes  yes      3

groupbyakceptuje argument, as_indexktóry mogliśmy ustawić, Falsewięc nie powoduje, że zgrupowane kolumny są indeksem, ale to generuje a seriesi nadal będziesz musiał przywrócić indeksy i tak dalej ....:

In[205]:
df1.groupby(['A','B'], as_index=False).size()

Out[205]: 
A    B  
no   no     1
     yes    2
yes  no     4
     yes    3
dtype: int64
EdChum
źródło
2

Nieco powiązane, szukałem unikalnych kombinacji i wymyśliłem taką metodę:

def unique_columns(df,columns):

    result = pd.Series(index = df.index)

    groups = meta_data_csv.groupby(by = columns)
    for name,group in groups:
       is_unique = len(group) == 1
       result.loc[group.index] = is_unique

    assert not result.isnull().any()

    return result

A jeśli chcesz tylko zapewnić, że wszystkie kombinacje są niepowtarzalne:

df1.set_index(['A','B']).index.is_unique
Martin Alexandersson
źródło
Nie wiedziałem o set_index(). Utrzymano próbę użycia groupby()do grupowania wierszy z określoną wspólną parą kolumn. Niesamowite, dziękuję!
user3290553
0

Umieszczanie bardzo ładnej odpowiedzi @ EdChum w funkcji count_unique_index. Ta unikalna metoda działa tylko w przypadku serii pand, a nie ramek danych. Poniższa funkcja odtwarza zachowanie unikalnej funkcji w R:

unique zwraca wektor, ramkę danych lub tablicę, taką jak x, ale z usuniętymi zduplikowanymi elementami / wierszami.

I dodaje liczbę wystąpień zgodnie z żądaniem OP.

df1 = pd.DataFrame({'A':['yes','yes','yes','yes','no','no','yes','yes','yes','no'],                                                                                             
                    'B':['yes','no','no','no','yes','yes','no','yes','yes','no']})                                                                                               
def count_unique_index(df, by):                                                                                                                                                 
    return df.groupby(by).size().reset_index().rename(columns={0:'count'})                                                                                                      

count_unique_index(df1, ['A','B'])                                                                                                                                              
     A    B  count                                                                                                                                                                  
0   no   no      1                                                                                                                                                                  
1   no  yes      2                                                                                                                                                                  
2  yes   no      4                                                                                                                                                                  
3  yes  yes      3
Paul Rougieux
źródło
0

Nie zrobiłem z tym testu czasu, ale fajnie było spróbować. Zasadniczo przekonwertuj dwie kolumny na jedną kolumnę krotek. Teraz przekonwertuj to na ramkę danych, wykonaj 'value_counts ()', który znajduje unikalne elementy i je zlicza. Ponownie baw się suwakiem i ułóż kolumny w żądanej kolejności. Prawdopodobnie możesz uczynić kroki bardziej eleganckimi, ale praca z krotkami wydaje mi się bardziej naturalna w przypadku tego problemu

b = pd.DataFrame({'A':['yes','yes','yes','yes','no','no','yes','yes','yes','no'],'B':['yes','no','no','no','yes','yes','no','yes','yes','no']})

b['count'] = pd.Series(zip(*[b.A,b.B]))
df = pd.DataFrame(b['count'].value_counts().reset_index())
df['A'], df['B'] = zip(*df['index'])
df = df.drop(columns='index')[['A','B','count']]
MikeB2019x
źródło