如果值=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]

我们选择除Valuesiloc 之外的列,然后形成一个点积,其中第二个操作数是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】:

你可以试试applystr.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)。这里我使用dropdf.drop("Values", axis=1)。 使用applyaxis=1 在每一行上应用自定义函数 在函数中,使用x[x != 0]过滤不同于0的值 使用.index选择列名(这里有Seri​​e的索引) 使用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(二进制值),则提取列名并将它们与分隔符组合并将其放入新列中的主要内容,如果未能解决你的问题,请参考以下文章

Jmeter提取response返回值保存到本地csv文件

Jmeter提取response返回值保存到本地csv文件

如果没有列名,如何提取值?

从 SQL 中提取一列值并将它们放入数组 VBA [关闭]

创建一个新列提取值等于列名的值

入门Mysql命令总结!!!