我正在尝试根据该数据框中的少数其他列名及其值创建新列。
数据看起来像这样
user_id Gender Age Cate_Ch_Bot Cate_Ch_Phy Cate_Ch_Chem Cate_Ch_Comp Cate_Ch_Zoo
0001 F 13 0 1 0 1 0
0002 M 17 1 1 0 0 0
0003 F 13 0 0 0 0 0
0004 F 12 0 0 1 0 0
0005 F 14 0 1 0 0 1
0006 M 16 0 0 0 0 0
我需要创建一个类别列,其中包含值为1的所有类别。如果用户没有类别,则为空白或NA。
所以期望的输出将是:
user_id Gender Age Cate_Ch_Bot Cate_Ch_Phy Cate_Ch_Chem Cate_Ch_Comp Cate_Ch_Zoo Ch_Category
0001 F 13 0 1 0 1 0 Phy:Comp
0002 M 17 1 1 0 0 0 Bot:Phy
0003 F 13 0 0 0 0 0 NA
0004 F 12 0 0 1 0 0 Chem
0005 F 14 0 1 0 0 1 Phy:Zoo
0006 M 16 0 0 0 0 0 NA
我正在尝试遍历列名,但不确定如何正确执行。
test$category = ""
for (j in 1:dim(test)[1]){
for (i in colnames(test[4:14])){
name = colnames(test[i])
if (test[j,name] == 1){
test$category[j] = paste(test$category[j], colnames(test[i]),sep=":")
}
}
}
我非常感谢这方面的任何帮助。
答案 0 :(得分:3)
这样的事情怎么样:
Df <- data.frame(
user_id=1:6,
Gender=rep(c("M","F"),3),
Age=sample(13:17,6,replace=TRUE),
Cate_Ch_Bot=c(0,1,rep(0,4)),
Cate_Ch_Phy=c(1,1,0,0,1,0),
Cate_Ch_Chem=c(0,0,0,1,0,0),
Cate_Ch_Comp=c(1,0,0,0,0,0),
Cate_Ch_Zoo=c(0,0,0,0,1,0),
stringsAsFactors=FALSE)
##
Labs <- gsub("Cate_Ch_","",names(Df)[-c(1:3)])
##
getCols <- function(x)
{
Reduce(function(x,y){paste0(x,":",y)},Labs[which(x==1)])
}
##
Df$new <- apply(Df[,-c(1:3)],1,function(X){
if( is.null(getCols(X)) ){
""
} else {
getCols(X)
}
})
##
> Df2
user_id Gender Age Cate_Ch_Bot Cate_Ch_Phy Cate_Ch_Chem Cate_Ch_Comp Cate_Ch_Zoo new
1 1 M 13 0 1 0 1 0 Phy:Comp
2 2 F 14 1 1 0 0 0 Bot:Phy
3 3 M 16 0 0 0 0 0
4 4 F 14 0 0 1 0 0 Chem
5 5 M 14 0 1 0 0 1 Phy:Zoo
6 6 F 16 0 0 0 0 0
<强>编辑:强>
我必须在getCols
函数中包含if..else
apply
语句,因为它实际上返回list
而不是vector
,NULL
1}} Df
行的元素,其中没有列的值为1
。以前,它看起来像表面上的data.frame
,但仔细观察就会发现:
> class(Df)
[1] "data.frame"
> str(Df)
'data.frame': 6 obs. of 9 variables:
$ user_id : int 1 2 3 4 5 6
$ Gender : chr "M" "F" "M" "F" ...
$ Age : int 13 14 16 14 14 16
$ Cate_Ch_Bot : num 0 1 0 0 0 0
$ Cate_Ch_Phy : num 1 1 0 0 1 0
$ Cate_Ch_Chem: num 0 0 0 1 0 0
$ Cate_Ch_Comp: num 1 0 0 0 0 0
$ Cate_Ch_Zoo : num 0 0 0 0 1 0
$ new :List of 6
..$ : chr "Phy:Comp"
..$ : chr "Bot:Phy"
..$ : NULL
..$ : chr "Chem"
..$ : chr "Phy:Zoo"
..$ : NULL
这是不受欢迎的。至于对解决方案中发生的事情的解释,
Labs <- gsub("Cate_Ch_","",names(Df)[-c(1:3)])
只是一个方便的步骤,因此有一个现成标签的向量可供参考。 gsub
正在获取目标列的名称,并将"Cate_Ch_"
替换为空字符串""
,以便剩余的文本可用作标签。 getCols
函数的结构是对单个向量x
进行操作 - 在本例中为Df
的单行。它使用Reduce
以累积方式应用子操作(粘贴两个字符串,由:
分隔),其中此子操作是根据匿名函数function(x,y){ ... }
给出的。我们提供给function(x,y)
的输入是我们整个Labs
向量的子集 - 该子集仅开始x==1
行中的那些元素。使用which(x==1)
只是给我们行的索引等于1。因此,对于Df
的第2行,which(x==1)
给出了向量c(1,2)
(因为Cate_Ch_Bot
和Cate_Ch_Phy
在第2行中的值为1
) 。评估Labs
内的这个索引向量,可以得到1
- 2
的元素Labs
和c("Bot","Phy")
。将此传递给我们的Reduce(function(x,y) ...
调用后,它会将所有元素粘贴在一起,以:
分隔,并返回单个字符值"Bot:Phy"
。如果Reduce
的输入为c("A","B","C","D")
,则会返回"A:B:C:D"
,依此类推。 apply
用于执行多行操作。如上所述,我必须对原来的apply
来电稍作修改,以确保它返回vector
而不是list
。 然后打字...... @Richard Scriven指出了一个更好的答案:
> apply(Df[-(1:3)] == 1, 1, function(x) {
paste(gsub(".*_", "", names(which(x))), collapse = ":")
})
[1] "Phy:Comp" "Bot:Phy" "" "Chem" "Phy:Zoo" ""