在列上迭代 for 循环时出错:"argument is of length zero"
Error when iterating for loop over columns: "argument is of length zero"
我有一个数据框"comp"。参考样本:
comp <- data.frame(A=c(1:5), B=c(1,0,1,0,0), C=c(5,2,0,0,NA), D=c(1,3,1,NA,0))
A B C D
1 1 1 5 1
2 2 0 2 3
3 3 1 0 1
4 4 0 0 NA
5 5 0 NA 0
我想在每一列(不包括前两列)上迭代一个 for 循环。基本上,循环应该根据该单元格中的值和该行第 2 列中的值打印特定字符串或 NA。在 C 中打印什么的规则是:
- 如果 C 为正且 B 为 1:"Ysnp, Yphen"
- 如果 C 为正且 B 为 0:"Ysnp, Nphen"
- 如果 C 为 0,B 为 1:"Nsnp, Yphen"
- 如果 C 为 0 且 B 为 0: "Nsnp, Nsnp"
- 如果 C 是 NA: NA
这些相同的规则也适用于 D 列(只需将上述规则中的 C 替换为 D)。对于我的示例数据,它看起来像这样:
A B C D
1 1 1 "Ysnp, Yphen" "Ysnp, Yphen"
2 2 0 "Ysnp, Nphen" "Ysnp, Nphen"
3 3 1 "Nsnp, Yphen" "Ysnp, Yphen"
4 4 0 "Nsnp, Nphen" NA
5 5 0 NA "Nsnp, Nphen"
我的真实数据集有 50 多列,因此对每一列应用 for 循环很繁琐。这是我试过的:
sapply(comp[,-(1:2)], function(snp) {
for (i in 1:nrow(comp)){
if (comp$snp[i]!=0 & !is.na(comp$snp[i])){
if (comp[i, 2]==1) comp$snp[i] <- "Ysnp, Yphen"
else comp$snp[i] <- "Ysnp, Nphen"
}
else if (comp$snp[i]==0 & !is.na(comp$snp[i])){
if (comp[i, 2]==1) comp$snp[i] <- "Nsnp, Yphen"
else comp$snp[i] <- "Nsnp, Nphen"
}
else comp$snp[i] <- NA
}
})
然而,当我 运行 这个循环时,我得到以下错误:
Error in if (comp$snp[i] != 0 & !is.na(comp$snp[i])) { :
argument is of length zero
我已经检查过我的数据框不包含任何 NULL
值,所以我不确定为什么循环会生成此错误。我还尝试在整个循环中将 comp$snp[i]
替换为 comp[i, snp]
,或者使用 apply
而不是 sapply
,但这并没有解决问题。
这对case_when
来说应该是一件简单的事情:
comp <- data.frame(A=c(1:5), B=c(1,0,1,0,0), C=c(5,2,0,0,NA))
library(tidyverse);
comp %>%
mutate(C = case_when(
C > 0 & B == 1 ~ "Ysnp, Yphen",
C > 0 & B == 0 ~ "Ysnp, Nphen",
C == 0 & B == 1 ~ "Nsnp, Yphen",
C == 0 & B == 0 ~ "Nsnp, Nsnp",
is.na(C) ~ "NA"));
# A B C
#1 1 1 Ysnp, Yphen
#2 2 0 Ysnp, Nphen
#3 3 1 Nsnp, Yphen
#4 4 0 Nsnp, Nsnp
#5 5 0 NA
规则:
- 如果 C 为正且 B 为 1:"Ysnp, Yphen"
- 如果 C 为正且 B 为 0:"Ysnp, Nphen"
- 如果 C 为 0,B 为 1:"Nsnp, Yphen"
- 如果 C 为 0,B 为 0:"Nsnp, Nsnp"
- 如果 C 是 NA: NA
更新
对于任意数量的列,您可以使用 for
循环。 for
循环将非常快,因为您只是替换现有 data.frame
中的条目,并且没有动态内存(重新)分配。
comp <- data.frame(A=c(1:5), B=c(1,0,1,0,0), C=c(5,2,0,0,NA), D=c(1,3,1,NA,0))
df <- comp;
for (i in 3:ncol(df)) {
df[, i] <- ifelse(is.na(df[, i]), "NA", paste(
ifelse(df[, i] > 0, "Ysnp", "Nsnp"),
ifelse(df$B == 1, "Yphen", "Nphen"), sep = ", "));
}
# A B C D
#1 1 1 Ysnp, Yphen Ysnp, Yphen
#2 2 0 Ysnp, Nphen Ysnp, Nphen
#3 3 1 Nsnp, Yphen Ysnp, Yphen
#4 4 0 Nsnp, Nphen NA
#5 5 0 NA Nsnp, Nphen
事实证明你甚至不需要 for
循环但可以使用直接索引。
df[, 3:ncol(df)] <- ifelse(is.na(df[, 3:ncol(df)]), "NA", paste(
ifelse(df[, 3:ncol(df)] > 0, "Ysnp", "Nsnp"),
ifelse(df$B == 1, "Yphen", "Nphen"), sep = ", "));
df;
# A B C D
#1 1 1 Ysnp, Yphen Ysnp, Yphen
#2 2 0 Ysnp, Nphen Ysnp, Nphen
#3 3 1 Nsnp, Yphen Ysnp, Yphen
#4 4 0 Nsnp, Nphen NA
#5 5 0 NA Nsnp, Nphen
我有一个数据框"comp"。参考样本:
comp <- data.frame(A=c(1:5), B=c(1,0,1,0,0), C=c(5,2,0,0,NA), D=c(1,3,1,NA,0))
A B C D
1 1 1 5 1
2 2 0 2 3
3 3 1 0 1
4 4 0 0 NA
5 5 0 NA 0
我想在每一列(不包括前两列)上迭代一个 for 循环。基本上,循环应该根据该单元格中的值和该行第 2 列中的值打印特定字符串或 NA。在 C 中打印什么的规则是:
- 如果 C 为正且 B 为 1:"Ysnp, Yphen"
- 如果 C 为正且 B 为 0:"Ysnp, Nphen"
- 如果 C 为 0,B 为 1:"Nsnp, Yphen"
- 如果 C 为 0 且 B 为 0: "Nsnp, Nsnp"
- 如果 C 是 NA: NA
这些相同的规则也适用于 D 列(只需将上述规则中的 C 替换为 D)。对于我的示例数据,它看起来像这样:
A B C D
1 1 1 "Ysnp, Yphen" "Ysnp, Yphen"
2 2 0 "Ysnp, Nphen" "Ysnp, Nphen"
3 3 1 "Nsnp, Yphen" "Ysnp, Yphen"
4 4 0 "Nsnp, Nphen" NA
5 5 0 NA "Nsnp, Nphen"
我的真实数据集有 50 多列,因此对每一列应用 for 循环很繁琐。这是我试过的:
sapply(comp[,-(1:2)], function(snp) {
for (i in 1:nrow(comp)){
if (comp$snp[i]!=0 & !is.na(comp$snp[i])){
if (comp[i, 2]==1) comp$snp[i] <- "Ysnp, Yphen"
else comp$snp[i] <- "Ysnp, Nphen"
}
else if (comp$snp[i]==0 & !is.na(comp$snp[i])){
if (comp[i, 2]==1) comp$snp[i] <- "Nsnp, Yphen"
else comp$snp[i] <- "Nsnp, Nphen"
}
else comp$snp[i] <- NA
}
})
然而,当我 运行 这个循环时,我得到以下错误:
Error in if (comp$snp[i] != 0 & !is.na(comp$snp[i])) { :
argument is of length zero
我已经检查过我的数据框不包含任何 NULL
值,所以我不确定为什么循环会生成此错误。我还尝试在整个循环中将 comp$snp[i]
替换为 comp[i, snp]
,或者使用 apply
而不是 sapply
,但这并没有解决问题。
这对case_when
来说应该是一件简单的事情:
comp <- data.frame(A=c(1:5), B=c(1,0,1,0,0), C=c(5,2,0,0,NA))
library(tidyverse);
comp %>%
mutate(C = case_when(
C > 0 & B == 1 ~ "Ysnp, Yphen",
C > 0 & B == 0 ~ "Ysnp, Nphen",
C == 0 & B == 1 ~ "Nsnp, Yphen",
C == 0 & B == 0 ~ "Nsnp, Nsnp",
is.na(C) ~ "NA"));
# A B C
#1 1 1 Ysnp, Yphen
#2 2 0 Ysnp, Nphen
#3 3 1 Nsnp, Yphen
#4 4 0 Nsnp, Nsnp
#5 5 0 NA
规则:
- 如果 C 为正且 B 为 1:"Ysnp, Yphen"
- 如果 C 为正且 B 为 0:"Ysnp, Nphen"
- 如果 C 为 0,B 为 1:"Nsnp, Yphen"
- 如果 C 为 0,B 为 0:"Nsnp, Nsnp"
- 如果 C 是 NA: NA
更新
对于任意数量的列,您可以使用 for
循环。 for
循环将非常快,因为您只是替换现有 data.frame
中的条目,并且没有动态内存(重新)分配。
comp <- data.frame(A=c(1:5), B=c(1,0,1,0,0), C=c(5,2,0,0,NA), D=c(1,3,1,NA,0))
df <- comp;
for (i in 3:ncol(df)) {
df[, i] <- ifelse(is.na(df[, i]), "NA", paste(
ifelse(df[, i] > 0, "Ysnp", "Nsnp"),
ifelse(df$B == 1, "Yphen", "Nphen"), sep = ", "));
}
# A B C D
#1 1 1 Ysnp, Yphen Ysnp, Yphen
#2 2 0 Ysnp, Nphen Ysnp, Nphen
#3 3 1 Nsnp, Yphen Ysnp, Yphen
#4 4 0 Nsnp, Nphen NA
#5 5 0 NA Nsnp, Nphen
事实证明你甚至不需要 for
循环但可以使用直接索引。
df[, 3:ncol(df)] <- ifelse(is.na(df[, 3:ncol(df)]), "NA", paste(
ifelse(df[, 3:ncol(df)] > 0, "Ysnp", "Nsnp"),
ifelse(df$B == 1, "Yphen", "Nphen"), sep = ", "));
df;
# A B C D
#1 1 1 Ysnp, Yphen Ysnp, Yphen
#2 2 0 Ysnp, Nphen Ysnp, Nphen
#3 3 1 Nsnp, Yphen Ysnp, Yphen
#4 4 0 Nsnp, Nphen NA
#5 5 0 NA Nsnp, Nphen