2013-08-02 5 views
7

Я пытаюсь выполнить некоторый линейный регрессионный анализ, у меня есть некоторые категориальные функции, которые я конвертирую в фиктивные переменные, используя супер удивительные get_dummies.Получить подмножество наиболее часто встречающихся фиктивных переменных в pandas

Проблема, с которой я сталкиваюсь, - это то, что dataframe становится слишком большим, когда я добавляю все элементы категорий.

Есть ли способ (используя get_dummies или более сложный метод), чтобы просто создавать фиктивные переменные наиболее часто встречающихся терминов, а не все из них?

ответ

0

Вы можете первым использовать value_counts, чтобы увидеть, какие наиболее частые:

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 

Значения, которые являются наименее часто (например, все, кроме первых двух):

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

Вы можете просто replace все эти вхождения с 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 

и выполнить get_dummiesдумать должен игнорировать NaN, но есть ошибка, поэтому notnull хак):

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 

Если вы хотите, чтобы включить эти результаты можно использовать другой заполнитель (например '_').

+0

О, проклятие, похоже, что в 'get_dummies есть ошибка, это не игнорирует NaN, а делает что-то странное ... –

5

использование value_counts() сделать подсчет частоты, а затем создать маску для строк, которые вы хотите остаться:

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]) 

выход:

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

, если вы хотите, чтобы все данные:

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

мощность:

- 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

Я использовал ответ, который дал @HYRY написать функцию, которая будет иметь параметр (порог), который может быть использована для разделения популярных ценности и непопулярных (объединенный в колонке «другой»).

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) 
# 

Давайте создадим некоторые данные:

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') 

Примеры использования:

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 

Любые предложения, как обращаться с пренебрежимо малых? Я считаю, что нанов нельзя рассматривать как «других».

UPD: Я проверил его на довольно большом наборе данных (5 mil obs) с 183 различными строками в столбце, которые я хотел продублировать. Реализация занимает 10 секунд на моем ноутбуке.

Смежные вопросы