11

我正在尝试执行一些线性回归分析,我有一些分类特征,我使用超级棒的 get_dummies 将其转换为虚拟变量。

我面临的问题是,当我添加类别的所有元素时,数据框变得太大。

有没有办法(使用 get_dummies 或更精细的方法)来创建最常见术语的虚拟变量而不是所有这些?

4

3 回答 3

7

用于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
于 2013-08-02T12:48:54.330 回答
5

我使用@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

有什么建议如何处理 nans?我认为nans不应该被视为“其他人”。

UPD:我已经在一个相当大的数据集(5 百万 obs)上对其进行了测试,在我想要虚拟化的列中有 183 个不同的字符串。在我的笔记本电脑上实施最多需要 10 秒。

于 2016-10-27T08:40:38.023 回答
2

您可以首先使用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)

您可以简单地用 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,但有一个错误,因此是notnullhack):

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

如果您想包含这些结果,您可以使用不同的占位符(例如'_')。

于 2013-08-02T12:40:43.977 回答