将分类数据转换为虚拟集
Convert categorical data into dummy set
我有这样的数据:-
|--------|---------|
| Col1 | Col2 |
|--------|---------|
| X | a,b,c |
|--------|---------|
| Y | a,b |
|--------|---------|
| X | b,d |
|--------|---------|
我想将这些分类数据转换为虚拟变量。由于我的数据很大,如果我使用 pandas 中的 get_dummies()
,则会出现内存错误。我想要这样的结果:-
|------|------|------|------|------|------|
|Col_X |Col_Y |Col2_a|Col2_b|Col2_c|Col2_d|
|------|------|------|------|------|------|
| 1 | 0 | 1 | 1 | 1 | 0 |
|------|------|------|------|------|------|
| 0 | 1 | 1 | 1 | 0 | 0 |
|------|------|------|------|------|------|
| 1 | 0 | 0 | 1 | 0 | 1 |
|------|------|------|------|------|------|
我尝试使用 转换 Col2,但由于数据很大而出现 MemoryError,并且 col2 也有很多可变性。
所以,
1) 如何将多个分类列转换为虚拟变量?
2) pandas get_dummy() 出现内存错误,我该如何处理?
我几乎可以肯定您遇到了内存问题,因为 str.get_dummies returns an array full of 1s and 0s, of datatype np.int64
. This is quite different from the behavior of pd.get_dummies,其中 returns 数据类型为 uint8
.
的值数组
这似乎是 str.get_dummies 的 known issue. However, there's been no update, nor fix, for the past year. Checking out the source code 确实会确认它正在返回 np.int64
。
一个8位的整数会占用1个字节的内存,而一个64位的整数会占用8个字节。我希望通过找到另一种单热编码方式 Col2
确保输出都是 8 位整数,从而避免内存问题。
这是我的方法,从您的示例开始:
df = pd.DataFrame({'Col1': ['X', 'Y', 'X'],
'Col2': ['a,b,c', 'a,b', 'b,d']})
df
Col1 Col2
0 X a,b,c
1 Y a,b
2 X b,d
- 由于
Col1
包含简单的非定界字符串,我们可以使用 pd.get_dummies: 轻松地对其进行一次性编码
df = pd.get_dummies(df, columns=['Col1'])
df
Col2 Col1_X Col1_Y
0 a,b,c 1 0
1 a,b 0 1
2 b,d 1 0
到目前为止一切顺利。
df['Col1_X'].values.dtype
dtype('uint8')
- 让我们获取
Col2
中逗号分隔字符串中包含的所有唯一子字符串的列表:
vals = list(df['Col2'].str.split(',').values)
vals = [i for l in vals for i in l]
vals = list(set(vals))
vals.sort()
vals
['a', 'b', 'c', 'd']
- 现在我们可以遍历上面的值列表并使用
str.contains
为每个值创建一个新列,例如 'a'
。如果新列中的每一行在 Col2
中的字符串中实际具有新列的值,例如 'a'
,则该行将包含 1。当我们创建每个新列时,我们确保将其数据类型转换为 uint8
:
col='Col2'
for v in vals:
n = col + '_' + v
df[n] = df[col].str.contains(v)
df[n] = df[n].astype('uint8')
df.drop(col, axis=1, inplace=True)
df
Col1_X Col1_Y Col2_a Col2_b Col2_c Col2_d
0 1 0 1 1 1 0
1 0 1 1 1 0 0
2 1 0 0 1 0 1
这会生成符合您所需格式的数据框。值得庆幸的是,从 Col2
一次性编码的四个新列中的整数每个只占用 1 个字节,而不是每个 8 个字节。
df['Col2_a'].dtype
dtype('uint8')
如果碰巧上述方法不起作用。我的建议是使用 str.get_dummies 对行块中的 Col2
进行单热编码。每次你做一个块,你会把它的数据类型从 np.int64
转换成 uint8
,然后是 transform the chunk to a sparse matrix。您最终可以将所有块连接在一起。
我也想给出我的解决方案。我要感谢@James-dellinger 的回答。所以这是我的方法
df = pd.DataFrame({'Col1': ['X', 'Y', 'X'],
'Col2': ['a,b,c', 'a,b', 'b,d']})
df
Col1 Col2
0 X a,b,c
1 Y a,b
2 X b,d
我先把col2值拆分出来,转换成列值。
df= pd.DataFrame(df['Col2'].str.split(',',3).tolist(),columns = ['Col1','Col2','Col3'])
df
Col1 Col2 Col3
0 a b c
1 a b None
2 b d None
然后我在这个数据框上应用了虚拟创建,没有给出任何前缀。
df=pd.get_dummies(df, prefix="")
df
_a _b _b _d _c
0 1 0 1 0 1
1 1 0 1 0 0
2 0 1 0 1 0
现在为了得到我们想要的结果,我们可以总结所有重复的列。
df.groupby(level=0, axis=1).sum()
df
_a _b _c _d
0 1 1 1 0
1 1 1 0 0
2 0 1 0 1
对于 Col1,我们可以使用 pd.get_dummies()
直接创建虚拟变量并将其存储到假设 col1_df
的不同数据帧中。我们可以使用 pd.concat([df,col1_df], axis=1, sort=False)
连接两列
我有这样的数据:-
|--------|---------|
| Col1 | Col2 |
|--------|---------|
| X | a,b,c |
|--------|---------|
| Y | a,b |
|--------|---------|
| X | b,d |
|--------|---------|
我想将这些分类数据转换为虚拟变量。由于我的数据很大,如果我使用 pandas 中的 get_dummies()
,则会出现内存错误。我想要这样的结果:-
|------|------|------|------|------|------|
|Col_X |Col_Y |Col2_a|Col2_b|Col2_c|Col2_d|
|------|------|------|------|------|------|
| 1 | 0 | 1 | 1 | 1 | 0 |
|------|------|------|------|------|------|
| 0 | 1 | 1 | 1 | 0 | 0 |
|------|------|------|------|------|------|
| 1 | 0 | 0 | 1 | 0 | 1 |
|------|------|------|------|------|------|
我尝试使用
所以,
1) 如何将多个分类列转换为虚拟变量?
2) pandas get_dummy() 出现内存错误,我该如何处理?
我几乎可以肯定您遇到了内存问题,因为 str.get_dummies returns an array full of 1s and 0s, of datatype np.int64
. This is quite different from the behavior of pd.get_dummies,其中 returns 数据类型为 uint8
.
这似乎是 str.get_dummies 的 known issue. However, there's been no update, nor fix, for the past year. Checking out the source code 确实会确认它正在返回 np.int64
。
一个8位的整数会占用1个字节的内存,而一个64位的整数会占用8个字节。我希望通过找到另一种单热编码方式 Col2
确保输出都是 8 位整数,从而避免内存问题。
这是我的方法,从您的示例开始:
df = pd.DataFrame({'Col1': ['X', 'Y', 'X'],
'Col2': ['a,b,c', 'a,b', 'b,d']})
df
Col1 Col2
0 X a,b,c
1 Y a,b
2 X b,d
- 由于
Col1
包含简单的非定界字符串,我们可以使用 pd.get_dummies: 轻松地对其进行一次性编码
df = pd.get_dummies(df, columns=['Col1'])
df
Col2 Col1_X Col1_Y
0 a,b,c 1 0
1 a,b 0 1
2 b,d 1 0
到目前为止一切顺利。
df['Col1_X'].values.dtype
dtype('uint8')
- 让我们获取
Col2
中逗号分隔字符串中包含的所有唯一子字符串的列表:
vals = list(df['Col2'].str.split(',').values)
vals = [i for l in vals for i in l]
vals = list(set(vals))
vals.sort()
vals
['a', 'b', 'c', 'd']
- 现在我们可以遍历上面的值列表并使用
str.contains
为每个值创建一个新列,例如'a'
。如果新列中的每一行在Col2
中的字符串中实际具有新列的值,例如'a'
,则该行将包含 1。当我们创建每个新列时,我们确保将其数据类型转换为uint8
:
col='Col2'
for v in vals:
n = col + '_' + v
df[n] = df[col].str.contains(v)
df[n] = df[n].astype('uint8')
df.drop(col, axis=1, inplace=True)
df
Col1_X Col1_Y Col2_a Col2_b Col2_c Col2_d
0 1 0 1 1 1 0
1 0 1 1 1 0 0
2 1 0 0 1 0 1
这会生成符合您所需格式的数据框。值得庆幸的是,从 Col2
一次性编码的四个新列中的整数每个只占用 1 个字节,而不是每个 8 个字节。
df['Col2_a'].dtype
dtype('uint8')
如果碰巧上述方法不起作用。我的建议是使用 str.get_dummies 对行块中的 Col2
进行单热编码。每次你做一个块,你会把它的数据类型从 np.int64
转换成 uint8
,然后是 transform the chunk to a sparse matrix。您最终可以将所有块连接在一起。
我也想给出我的解决方案。我要感谢@James-dellinger 的回答。所以这是我的方法
df = pd.DataFrame({'Col1': ['X', 'Y', 'X'],
'Col2': ['a,b,c', 'a,b', 'b,d']})
df
Col1 Col2
0 X a,b,c
1 Y a,b
2 X b,d
我先把col2值拆分出来,转换成列值。
df= pd.DataFrame(df['Col2'].str.split(',',3).tolist(),columns = ['Col1','Col2','Col3'])
df
Col1 Col2 Col3
0 a b c
1 a b None
2 b d None
然后我在这个数据框上应用了虚拟创建,没有给出任何前缀。
df=pd.get_dummies(df, prefix="")
df
_a _b _b _d _c
0 1 0 1 0 1
1 1 0 1 0 0
2 0 1 0 1 0
现在为了得到我们想要的结果,我们可以总结所有重复的列。
df.groupby(level=0, axis=1).sum()
df
_a _b _c _d
0 1 1 1 0
1 1 1 0 0
2 0 1 0 1
对于 Col1,我们可以使用 pd.get_dummies()
直接创建虚拟变量并将其存储到假设 col1_df
的不同数据帧中。我们可以使用 pd.concat([df,col1_df], axis=1, sort=False)