当我搜索这个主题时,我得到的答案与我想要做的不匹配。假设我有一张这样的表格:
物品 | N1 | 氮气 | N3 | N4 |
---|---|---|---|---|
项目1 | 1 | 2 | 4 | 8 |
项目2 | 2 | 3 | 6 | 7 |
项目3 | 4 | 5 | 7 | 9 |
项目4 | 1 | 5 | 6 | 7 |
项目5 | 3 | 4 | 7 | 8 |
我想对其进行独热编码以获得:
物品 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
---|---|---|---|---|---|---|---|---|---|
项目1 | 1 | 1 | 0 | 1 | 0 | 0 | 0 | 1 | 0 |
项目2 | 0 | 1 | 1 | 0 | 0 | 1 | 1 | 0 | 0 |
项目3 | 0 | 0 | 0 | 1 | 1 | 0 | 1 | 0 | 1 |
项目4 | 1 | 0 | 0 | 0 | 1 | 1 | 1 | 0 | 0 |
项目5 | 0 | 0 | 1 | 1 | 0 | 0 | 1 | 1 | 0 |
这可行吗?我现在正在编写某种循环来遍历每一行,但我决定询问是否有人知道更有效的方法来做到这一点。
最佳答案
3
使用 melt 和 crosstab。
tmp = df.melt('Item')
result = pd.crosstab(tmp['Item'], tmp['value']).reset_index().rename_axis(None, axis=1)
Item 1 2 3 4 5 6 7 8 9
0 Item1 1 1 0 1 0 0 0 1 0
1 Item2 0 1 1 0 0 1 1 0 0
2 Item3 0 0 0 1 1 0 1 0 1
3 Item4 1 0 0 0 1 1 1 0 0
4 Item5 0 0 1 1 0 0 1 1 0
3
-
1使用,您可以使用
colnames
参数来避免链接df.rename_axis
。即pd.crosstab(tmp['Item'], tmp['value'], colnames=[None]).reset_index()
。
–
-
如果“item”列是 datetimeindex 而不是常规列,该怎么办?显然 datetimeindex 没有属性 melt。
– -
我无法重现错误… 列是否设置为索引?如果是这样,只需使用 tmp = df.unstack().reset_index(name=’N’) 而不是 melt,然后使用 crosstab
–
|
您可以尝试,例如,
pd.get_dummies(df.melt('Item'), columns=['value'], prefix='', prefix_sep='').drop('variable', axis=1).groupby('Item').sum().reset_index()
由此得出
Item 1 2 3 4 5 6 7 8 9
0 Item1 1 1 0 1 0 0 0 1 0
1 Item2 0 1 1 0 0 1 1 0 0
2 Item3 0 0 0 1 1 0 1 0 1
3 Item4 1 0 0 0 1 1 1 0 0
4 Item5 0 0 1 1 0 0 1 1 0
数据
df = pd.DataFrame(
{
"Item": ["Item1", "Item2", "Item3", "Item4", "Item5"],
"N1": [1, 2, 4, 1, 3],
"N2": [2, 3, 5, 5, 4],
"N3": [4, 6, 7, 6, 7],
"N4": [8, 7, 9, 7, 8],
}
)
2
-
嗨,我是原帖者。我选择了 Triky 的答案,因为它满足了我的要求(即标签是实际数字)。但您的解决方案也很好,我可以想到在某些情况下最好有一个命名标签。谢谢。
– -
@Eric 没问题。你可以查看我的更新
–
|
另一个可能的解决方案是使用sklearn
。此解决方案利用sklearn
对的特定列进行独热编码df
。其步骤如下:
-
首先,它初始化
MultiLabelBinarizer
并将其方法应用于到的fit_transform
列的值,将它们转换为二进制矩阵,其中每个唯一值表示为单独的列。N1
N4
-
然后从这个二进制矩阵创建一个新的数据框,其列以所标识的唯一值命名
binarize.classes_
。 -
最后,用于将原始
Item
列与新创建的独热编码数据框相结合。
from sklearn.preprocessing import MultiLabelBinarizer
binarize = MultiLabelBinarizer()
pd.concat(
[df[['Item']],
pd.DataFrame(
binarize.fit_transform(df[['N1', 'N2', 'N3', 'N4']].values),
columns=binarize.classes_)], axis=1)
注意:为了避免枚举以 开头的所有列N
,@ThomasIsCoding(我向他表示感谢)在下面的评论中建议使用:
df.loc[:,df.columns.str.startswith("N")]
或者
df.iloc[:,1:]
输出:
Item 1 2 3 4 5 6 7 8 9
0 Item1 1 1 0 1 0 0 0 1 0
1 Item2 0 1 1 0 0 1 1 0 0
2 Item3 0 0 0 1 1 0 1 0 1
3 Item4 1 0 0 0 1 1 1 0 0
4 Item5 0 0 1 1 0 0 1 1 0
5
-
1这也很好,因为简单的事实就是很容易理解到底发生了什么。
– -
1有趣的方法
MultiLabelBinarizer
,+1!
– -
1谢谢,@ThomasIsCoding!我现在从事机器学习工作,这启发了我提出这个解决方案。
– -
1哈哈,
sklearn
确实是个宝藏岛 :D。一个小评论:也许您可以使用df.iloc[:,1:]
来避免枚举以N
或开头的所有列df.loc[:,df.columns.str.startswith("N")]
,以防有大量这样的列
– -
谢谢@ThomasIsCoding的评论!与此同时,我也相应地更新了我的答案。
–
|
|