如果值=1(二进制值),则提取列名并将它们与分隔符组合并将其放入新列中
Posted
技术标签:
【中文标题】如果值=1(二进制值),则提取列名并将它们与分隔符组合并将其放入新列中【英文标题】:Extract column names & combine them with delimiter if value =1 (binary values) and put it in new column 【发布时间】:2021-08-03 12:56:00 【问题描述】:在使用 pandas 执行 get_dummies 后,我有一个带有二进制值的数据框
df=
Values A1 A2 B1 B2 B3 B4 C1 C2 C3
10 1 0 1 0 0 0 1 0 0
12 0 1 0 0 1 0 0 1 0
3 0 1 0 1 0 0 0 0 1
5 1 0 0 0 0 1 1 0 0
我想要一个新列,其中包含所有包含 1 的列的组合
Expected output:
Values A1 A2 B1 B2 B3 B4 C1 C2 C3 Combination
10 1 0 1 0 0 0 1 0 0 A1~~B1~~C1
12 0 1 0 0 1 0 0 1 0 A2~~B3~~C2
3 0 1 0 1 0 0 0 0 1 A2~~B2~~C3
5 1 0 0 0 0 1 1 0 0 A1~~B4~~C3
实际矩阵可以是25000+行*1000+列
在 R 中找到了类似的解决方案,但我在 Python 中需要它,因为所有其他依赖项都在 python 中,而 R 对我来说是新的。
Extract column names with value 1 in binary matrix
Codes in R below, & need similar one or any other code in python which can help me to arrive at my expected output
Solution 1 :
as.matrix(apply(m==1,1,function(a) paste0(colnames(m)[a], collapse = "")))
Solution 2:
t <- which(m==1, arr.ind = TRUE)
as.matrix(aggregate(col~row, cbind(row=rownames(t), col=t[,2]), function(x)
paste0(colnames(m)[x], collapse = "")))
如何在 Python 中实现类似或达到我预期的输出?
【问题讨论】:
【参考方案1】:df["Combination"] = df.iloc[:, 1:].dot(df.add_suffix("~~").columns[1:]).str[:-2]
我们选择除Values
和iloc
之外的列,然后形成一个点积,其中第二个操作数是df
的各个列,并在末尾添加~~
。结果最后也给出了~~
,所以我们用.str[:-2]
砍掉它
得到
Values A1 A2 B1 B2 B3 B4 C1 C2 C3 Combination
0 10 1 0 1 0 0 0 1 0 0 A1~~B1~~C1
1 12 0 1 0 0 1 0 0 1 0 A2~~B3~~C2
2 3 0 1 0 1 0 0 0 0 1 A2~~B2~~C3
3 5 1 0 0 0 0 1 1 0 0 A1~~B4~~C1
【讨论】:
恕我直言,这是一个理想的解决方案,因为它避免使用apply
。但是,由于它需要第二个字符串剥离步骤,因此必须针对apply solution
进行计时。这可能会更快。
顺便说一句,您可以跳过.dot
之前的.values
部分,以便它生成熊猫系列。然后你可以在同一步骤中进行字符串修剪:df.iloc[:, 1:].dot(df.add_suffix("~~").columns[1:]).str[:-2]
【参考方案2】:
你可以试试apply
和str.join
:
df["Combination"] = df.drop("Values", axis=1).apply(lambda x: "~~".join(x[x != 0].index), axis=1)
print(df)
# Values A1 A2 B1 B2 B3 B4 C1 C2 C3 Combination
# 0 10 1 0 1 0 0 0 1 0 0 A1~~B1~~C1
# 1 12 0 1 0 0 1 0 0 1 0 A2~~B3~~C2
# 2 3 0 1 0 1 0 0 0 0 1 A2~~B2~~C3
# 3 5 1 0 0 0 0 1 1 0 0 A1~~B4~~C1
解释:
-
要计算
Combination
,请忽略Values
列。有几种方法是可能的(见topic)。这里我使用drop
:df.drop("Values", axis=1)
。
使用apply
和axis=1
在每一行上应用自定义函数
在函数中,使用x[x != 0]
过滤不同于0
的值
使用.index
选择列名(这里有Serie的索引)
使用str.join
匹配所需的输出:"~~".join(x[x != 0].index)
完整插图:
# Step 1
print(df.drop("Values", axis=1))
# A1 A2 B1 B2 B3 B4 C1 C2 C3
# 0 1 0 1 0 0 0 1 0 0
# 1 0 1 0 0 1 0 0 1 0
# 2 0 1 0 1 0 0 0 0 1
# 3 1 0 0 0 0 1 1 0 0
# Step 3
print(df.drop("Values", axis=1).apply(lambda x: x[x != 0], axis=1))
# A1 A2 B1 B2 B3 B4 C1 C2 C3
# 0 1.0 NaN 1.0 NaN NaN NaN 1.0 NaN NaN
# 1 NaN 1.0 NaN NaN 1.0 NaN NaN 1.0 NaN
# 2 NaN 1.0 NaN 1.0 NaN NaN NaN NaN 1.0
# 3 1.0 NaN NaN NaN NaN 1.0 1.0 NaN NaN
# Step 4
print(df.drop("Values", axis=1).apply(lambda x: x[x != 0].index, axis=1))
# 0 Index(['A1', 'B1', 'C1'], dtype='object')
# 1 Index(['A2', 'B3', 'C2'], dtype='object')
# 2 Index(['A2', 'B2', 'C3'], dtype='object')
# 3 Index(['A1', 'B4', 'C1'], dtype='object')
# Step 5
df["Combination"] = df.drop("Values", axis=1).apply(lambda x: "~~".join(x[x != 0].index), axis=1)
print(df)
# Values A1 A2 B1 B2 B3 B4 C1 C2 C3 Combination
# 0 10 1 0 1 0 0 0 1 0 0 A1~~B1~~C1
# 1 12 0 1 0 0 1 0 0 1 0 A2~~B3~~C2
# 2 3 0 1 0 1 0 0 0 0 1 A2~~B2~~C3
# 3 5 1 0 0 0 0 1 1 0 0 A1~~B4~~C1
【讨论】:
我忍不住为这么详细的解释点赞,我希望这里有更多的答案是这样的...... 希望这会有所帮助,谢谢@MustafaAydın :-)【参考方案3】:您可以在删除values
列后使用pandas 的.dot
函数来获取您想要的列名,然后使用列表推导处理输出以获得正确的A1~~B1~~C1
格式。
它的外观如下:
tmp = [list(i) for i in list(df.dot(df.columns))]
df['combination'] = ['~~'.join(i) for i in tmp]
print(df)
A B C D combination
0 1 1 0 0 A~~B
1 0 1 1 0 B~~C
2 0 0 1 0 C
【讨论】:
说得太早了。如果列的名称中有多个字符,则此解决方案会出现问题。提供类似A~~1~~B~~1~~C~~1
的输出,而不是A1~~B1~~C1
。以上是关于如果值=1(二进制值),则提取列名并将它们与分隔符组合并将其放入新列中的主要内容,如果未能解决你的问题,请参考以下文章