我正在尝试执行一些线性回归分析,我有一些明确的功能,我使用超级棒的get_dummies转换为虚拟变量.
我面临的问题是,当我添加类别的所有元素时,数据框太大了.
有没有办法(使用get_dummies或更复杂的方法)来创建最常用术语的虚拟变量而不是所有这些变量?
用于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])
Run Code Online (Sandbox Code Playgroud)
输出:
a b
0 1 0
1 0 1
2 1 0
3 0 1
7 1 0
Run Code Online (Sandbox Code Playgroud)
如果你想要所有的数据:
values[~mask] = "-"
print pd.get_dummies(values)
Run Code Online (Sandbox Code Playgroud)
输出:
- 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
Run Code Online (Sandbox Code Playgroud)
我使用@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)
#
Run Code Online (Sandbox Code Playgroud)
让我们创建一些数据:
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')
Run Code Online (Sandbox Code Playgroud)
使用示例:
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
Run Code Online (Sandbox Code Playgroud)
任何建议如何处理nans?我认为 nans 不应该被视为“其他人”。
UPD:我已经在一个非常大的数据集(500 万个 obs)上对其进行了测试,该数据集在我想要虚拟化的列中有 183 个不同的字符串。在我的笔记本电脑上实现最多需要 10 秒。
您可以首先使用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
Run Code Online (Sandbox Code Playgroud)
最不常见的值(例如,除了前两个之外的所有值):
In [14]: s.value_counts().index[2:]
Out[14]: Index([u'b'], dtype=object)
Run Code Online (Sandbox Code Playgroud)
您可以简单地将所有这些出现的情况替换为 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
Run Code Online (Sandbox Code Playgroud)
并执行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
Run Code Online (Sandbox Code Playgroud)
如果您想包含这些结果,您可以使用不同的占位符(例如'_')。
| 归档时间: |
|
| 查看次数: |
3491 次 |
| 最近记录: |