2013-08-02 11 views
7

Próbuję przeprowadzić analizę liniowej regresji, mam kilka cech jakościowych, które zamieniam na zmienne atrapowe przy użyciu super niesamowitych get_dummies.Pobierz podzbiór najczęściej występujących zmiennych dummy w pandzie

Problemem, który napotykam, jest to, że ramka danych staje się zbyt duża, gdy dodaję wszystkie elementy kategorii.

Czy istnieje sposób (za pomocą get_dummies lub bardziej rozbudowanej metody) do tworzenia fałszywych zmiennych najczęściej używanych terminów zamiast wszystkich?

Odpowiedz

0

Można najpierw użyć value_counts aby zobaczyć, które są najczęstszą:

In [11]: s = pd.Series(list('aabccc')) 

In [12]: s 
Out[12]: 
0 a 
1 a 
2 b 
3 c 
4 c 
5 c 
dtype: object 

In [13]: s.value_counts() 
Out[13]: 
c 3 
a 2 
b 1 
dtype: int64 

Wartości, które są najrzadziej (np wszystkie z wyjątkiem dwóch pierwszych):

In [14]: s.value_counts().index[2:] 
Out[14]: Index([u'b'], dtype=object) 

Można po prostu replace wszystkie te wystąpienia z NaN:

In [15]: s1 = s.replace(s.value_counts().index[2:], np.nan) 

In [16]: s1 
Out[16]: 
0  a 
1  a 
2 NaN 
3  c 
4  c 
5  c 
dtype: object 

i wykonać get_dummies (który myślę powinniśmy ignorować NaN, ale nie jest to błąd, stąd notnull Hack):

In [16]: pd.get_dummies(s1[s1.notnull()]) 
Out[16]: 
    a c 
0 1 0 
1 1 0 
3 0 1 
4 0 1 
5 0 1 

Jeśli chciał to te wyniki można użyć innego zastępczy (na przykład '_').

+0

Och, wygląda na to, że w 'get_dummies' jest błąd, nie ignorujemy NaN, ale robimy coś dziwnego ... –

5

użycie value_counts() zrobić liczenia częstotliwości, a następnie utworzyć maskę dla wierszy, które mają pozostać:

import pandas as pd 
values = pd.Series(["a","b","a","b","c","d","e","a"]) 
counts = pd.value_counts(values) 
mask = values.isin(counts[counts > 1].index) 
print pd.get_dummies(values[mask]) 

wyjściowa:

a b 
0 1 0 
1 0 1 
2 1 0 
3 0 1 
7 1 0 

jeśli chcesz wszystkie dane:

values[~mask] = "-" 
print pd.get_dummies(values) 

moc wyjściowa:

- a b 
0 0 1 0 
1 0 0 1 
2 0 1 0 
3 0 0 1 
4 1 0 0 
5 1 0 0 
6 1 0 0 
7 0 1 0 
0

Kiedyś odpowiedź, że @HYRY dał napisać funkcję, która będzie mieć parametr (próg), które mogą być stosowane do oddzielenia popularne wartości i te niepopularne (połączone w kolumnie „Inne”).

import pandas as pd 
import numpy as np 

# func that returns a dummified DataFrame of significant dummies in a given column 
def dum_sign(dummy_col, threshold=0.1): 

    # removes the bind 
    dummy_col = dummy_col.copy() 

    # what is the ratio of a dummy in whole column 
    count = pd.value_counts(dummy_col)/len(dummy_col) 

    # cond whether the ratios is higher than the threshold 
    mask = dummy_col.isin(count[count > threshold].index) 

    # replace the ones which ratio is lower than the threshold by a special name 
    dummy_col[~mask] = "others" 

    return pd.get_dummies(dummy_col, prefix=dummy_col.name) 
# 

Stwórzmy jakieś dane:

df = ['a', 'a', np.nan, np.nan, 'a', np.nan, 'a', 'b', 'b', 'b', 'b', 'b', 
      'c', 'c', 'd', 'e', 'g', 'g', 'g', 'g'] 

data = pd.Series(df, name='dums') 

Przykłady zastosowań:

In: dum_sign(data) 
Out: 
    dums_a dums_b dums_g dums_others 
0  1  0  0   0 
1  1  0  0   0 
2  0  0  0   1 
3  0  0  0   1 
4  1  0  0   0 
5  0  0  0   1 
6  1  0  0   0 
7  0  1  0   0 
8  0  1  0   0 
9  0  1  0   0 
10  0  1  0   0 
11  0  1  0   0 
12  0  0  0   1 
13  0  0  0   1 
14  0  0  0   1 
15  0  0  0   1 
16  0  0  1   0 
17  0  0  1   0 
18  0  0  1   0 
19  0  0  1   0 

In: dum_sign(data, threshold=0.2) 
Out: 
    dums_b dums_others 
0  0   1 
1  0   1 
2  0   1 
3  0   1 
4  0   1 
5  0   1 
6  0   1 
7  1   0 
8  1   0 
9  1   0 
10  1   0 
11  1   0 
12  0   1 
13  0   1 
14  0   1 
15  0   1 
16  0   1 
17  0   1 
18  0   1 
19  0   1 

In: dum_sign(data, threshold=0) 
Out: 
    dums_a dums_b dums_c dums_d dums_e dums_g dums_others 
0  1  0  0  0  0  0   0 
1  1  0  0  0  0  0   0 
2  0  0  0  0  0  0   1 
3  0  0  0  0  0  0   1 
4  1  0  0  0  0  0   0 
5  0  0  0  0  0  0   1 
6  1  0  0  0  0  0   0 
7  0  1  0  0  0  0   0 
8  0  1  0  0  0  0   0 
9  0  1  0  0  0  0   0 
10  0  1  0  0  0  0   0 
11  0  1  0  0  0  0   0 
12  0  0  1  0  0  0   0 
13  0  0  1  0  0  0   0 
14  0  0  0  1  0  0   0 
15  0  0  0  0  1  0   0 
16  0  0  0  0  0  1   0 
17  0  0  0  0  0  1   0 
18  0  0  0  0  0  1   0 
19  0  0  0  0  0  1   0 

Wszelkie sugestie, jak radzić Nans? Uważam, że nans nie powinien być traktowany jako "inni".

UPD: Przetestowałem go na dość dużym zbiorze danych (5 mil obsł.) Z 183 różnymi ciągami w kolumnie, którą chciałem zmumifikować. Implementacja zajmuje maksymalnie 10 s na moim laptopie.