我有多个响应数据已被拆分为单独的列,cSplit_e为这样的格式......
ID Response IM2 IM4 ... IM10 IM16
1 1 4,7,10 NA 1 1 NA
2 2 7,5,16,8 NA NA NA 1
3 3 2,10 1 NA 1 NA
我正在尝试设置一个函数,检查每一行,看一下列的子集是否包含至少一个“1”。然后它会创建一个新列,如果一行在指定的列中至少有一个“1”,则将其设置为“1”。
以前我通过为我想要创建的每个列写出for循环来完成此操作,就像这样......
parade$q9PaperAggregate <- NA
parade$q9MagazineAggregate <- NA
#Newspaper Aggregate Loop
for (i in 1:nrow(parade)) { #Starts loop setting i to each row number
if (is.na(parade$q9PaperAds[i]) == FALSE | ##These three lines check each row is not all NA
is.na(parade$q9PaperCircs[i]) == FALSE |
is.na(parade$q9PaperWebAds[i]) == FALSE) {
parade$q9PaperAggregate[i] <- 1 #Sets agg cell value to 1 if not all NA for each i
}
}
#Magazine Aggregate Loop
for (i in 1:nrow(parade)) {
if (is.na(parade$q9MagazineAds[i]) == FALSE |
is.na(parade$q9MagazineWebAds[i]) == FALSE) {
parade$q9MagazineAggregate[i] <- 1
}
}
这有效,但显然效率低下。我想创建一个为输入执行此操作的常规函数。以下是我到目前为止的情况:
#df = object; n = new column name; col = vector of columns I want to check
atleastone <- function(df, n, col) {
#n = new column name (will run over list of vector - new col names with the old columns you want to agg)
df[n] <- NA
for (i in 1:nrow(df)) { #Starts loop setting i to each row number
if (df[i, col] == 1) {
(df[n])[i] <- 1 #Sets new column cell value to 1 if not all NA for each i
}
}
}
我的主要两个问题是:1)如果要检查的列数可以变化,如何运行for循环以检查值的多个列,以及2)如何将行和列传递给子集。目前“col”使用列的实际名称,而“i”只使用数字行值。这在我之前使用的格式中很好......
df$column[i]
...但$运算符似乎不适用于从函数传递给它的值。
知道我在这里做错了吗?有更好的方法吗?
感谢您的时间。
编辑:
我将@ SymbolixAU的回复转换为函数,如下所示:
#Aggregate Function
#takes input df = object; n = name of new column in double quotes; l = columns you want to agg
agger <- function(df, l, n) {
#checks if the sum of the rows in the specified columns is greater than 1
#this produces a logical value which is multiplied by 1 to change it to numeric
df[n] <- ((rowSums(df[, l] == 1) > 0) * 1)
}
后续问题 - 我试图使用mapply将两个不同向量列的列表“x”传递给参数“l”,并将两个新列的两个名称的向量“y”传递给创建并且目标对象df = BR。该命令如下所示:
mapply(agger, l = x, n = y, MoreArgs = list(BR))
这是将我发送到调试窗口,没有关于出错的消息或信息。我的mapply是否设置错误和/或是否有更好的方法在同一数据框中的多组列上运行此函数?
谢谢。
答案 0 :(得分:3)
这可以在一行中完成,没有任何循环或*apply
s:
df$new_col <- ((rowSums(df[, col] == 1, na.rm=T) > 0) * 1)
您可以使用以下内容检查列子集中的值是否等于1
df[, col] == 1
然后,您可以检查每行中有多少个值
使用rowSums()
然后,如果有任何rowSums
结果的值大于0,您就知道了
该行中的一列中至少有一个
> 0
检查返回逻辑,因此将其乘以1以将其转换
到数字
## taking the data you've provide
df <- read.table(text = "ID Response IM2 IM4 IM10 IM16
1 4,7,10 NA 1 1 NA
2 7,5,16,8 NA NA NA 1
3 2,10 1 NA 1 NA", header = T)
df
# ID Response IM2 IM4 IM10 IM16
# 1 1 4,7,10 NA 1 1 NA
# 2 2 7,5,16,8 NA NA NA 1
# 3 3 2,10 1 NA 1 NA
## specify the columns of interest
col <- c("IM4", "IM10")
## assign the new column
df$new_col <- ((rowSums(df[, col] == 1, na.rm=T) > 0) * 1)
df
# ID Response IM2 IM4 IM10 IM16 new_col
# 1 1 4,7,10 NA 1 1 NA 1
# 2 2 7,5,16,8 NA NA NA 1 0
# 3 3 2,10 1 NA 1 NA 1
这也适用于@Barker提供的数据
set.seed(100)
df <- data.frame(ID = 1:20)
df[paste0("IM", 1:7)] <- replicate(7,sample(c(rep(NA,5),1,1),20, replace = TRUE))
col <- paste0("IM", 1:7)
df$new_col <- ((rowSums(df[, col] == 1, na.rm=T) > 0) * 1)
我不完全确定你在评论中提出的问题,但你可以做点什么
## using @Barker 's data gain, create a list of groups of columns
col_groups <- list(grp1 = c("IM1","IM2"),
grp2 = c("IM2","IM7"),
grp3 = c("IM5","IM7"))
## use lapply to do the calculation for each group of columns
df2 <- lapply(col_groups, function(x){
df['new_col'] <- ((rowSums(df[, x] == 1, na.rm=T) > 0) * 1)
return(df)
})
这显然会返回data.frame
个列表,每个列表都根据grp
值命名,每个都附加了不同的new_col
。
答案 1 :(得分:1)
使用apply函数实际上可以很简单地完成。
让我们首先制作一个示例数据集来使用:
set.seed(100)
df <- data.frame(ID = 1:20)
df[paste0("IM", 1:7)] <- replicate(7,sample(c(rep(NA,5),1,1),20, replace = TRUE))
现在我们有了数据,我们实际上可以在一行中完成任务:
df[["newName"]] <- apply(df[grep("^IM", names(df))] == 1, 1, any, na.rm = TRUE)
让我们回顾一下这里发生的事情。首先,我们使用df[grep("^IM", names(df))]
对df
中以IM
开头的列进行子集化。接下来,我们使用==
来确定哪些值等于1
。 apply
函数接受新的逻辑数据帧,并且对于每一行(因为第二个参数等于1
,columnes将为2
,每个元素将为c(1, 2)
) any
函数。如果至少有一个输入为TRUE
,则返回TRUE
,但是,如果没有为TRUE且其中一个值为NA
,则它将返回NA
,因为它不会我知道NA
是TRUE
还是FALSE
。通过在末尾添加na.rm = TRUE
,我们告诉any
函数忽略NA
值。如果您希望这些值包含NA
而不是FALSE
,只需删除na.rm = TRUE
语句。
答案 2 :(得分:1)
此代码
parade$q9PaperAggregate <- NA
#Newspaper Aggregate Loop
for (i in 1:nrow(parade)) { #Starts loop setting i to each row number
if (is.na(parade$q9PaperAds[i]) == FALSE | ##These three lines check each row is not all NA
is.na(parade$q9PaperCircs[i]) == FALSE |
is.na(parade$q9PaperWebAds[i]) == FALSE) {
parade$q9PaperAggregate[i] <- 1 #Sets agg cell value to 1 if not all NA for each i
}
}
可以矢量化(运行得更快):
parade$q9PaperAggregate <- ifelse(is.na(parade$q9PaperAds) &
is.na(parade$q9PaperCircs) &
is.na(parade$q9PaperWebAds), NA, 1)