嵌套for循环中向量之间的计算
Calculation between vectors in nested for loops
我正在努力解决与嵌套 for 循环和条件计算有关的问题。
假设我有一个这样的数据框:
df = data.frame("a" = c(2, 3, 3, 4),
"b" = c(4, 4, 4, 4),
"c" = c(5, 5, 4, 4),
"d" = c(3, 4, 4, 2))
有了这个 df,我想用一个条件比较向量之间的每个元素:如果两个元素之间的绝对差值小于 2(即 0 和 1 的差值),我想在 a 中给出 1新创建的向量,而两个元素之间的绝对差 >= 2,我想附加 0.
例如,对于向量“a”和其他向量“b”、“c”、“d”之间的计算,我想要这样的结果:0 0 1。第一个 0 是基于a1 和 b1 相差 2;第二个0是基于a1和c1的差3; 1基于a1和d1的差异。因此,我尝试制作一个嵌套的 for 循环,以将相同的行程也应用于以下行中的元素。
所以我的第一次试用是这样的:
list_all = list(df$a, df$b, df$c, df$d)
v0<-c()
for (i in list_all)
for (j in list_all)
if (i != j) {
if(abs(i-j)<2) {
v0<-c(v0, 1)
} else {
v0<-append(v0, 0)
}} else {
next}
结果是这样的:
v0
[1] 0 0 1 0 1 1 0 1 0 1 1 0
但是好像只计算了第一个元素,后面的元素没有计算
所以我的二审是这样的:
list = list(df$b, df$c, df$d)
v1<-c()
for (i in df$a){
for (j in list){
if(abs(i-j)<2) {
v1<-append(v1, 1)
} else {
v1<-append(v1, 0)
}
}
}
v1
v1
[1] 0 0 1 1 0 1 1 0 1 1 1 1
似乎计算是在 df$a 的所有元素和其他元素的第一个元素之间进行的。所以这也不是我需要的。
当我把 df$b 而不是 list 放在嵌套的 for 循环中时,结果更加混乱。
v2<-c()
for (i in df$a){
for (j in df$b){
if(abs(i-j)<2) {
v2<-append(v2, 1)
} else {
v2<-append(v2, 0)
}
}
}
v2
[1] 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1
好像不是在对应元素(同一行)之间计算,而是在所有向量之间计算,不分位置。
谁能告诉我如何解决这个问题?我不明白为什么嵌套 for 循环只适用于第一个元素。
提前致谢。
我不确定我是否理解正确,但是这个怎么样?
df = data.frame("a" = c(2, 3, 3, 4),
"b" = c(4, 4, 4, 4),
"c" = c(5, 5, 4, 4),
"d" = c(3, 4, 4, 2))
as.vector(apply(df, 1, \(x) ifelse(abs(x[1] - x[2:4]) < 2, 1, 0)))
#> [1] 0 0 1 1 0 1 1 1 1 1 1 0
我认为您正在让自己的生活变得不必要地复杂化。如果我理解正确的话,你可以做你想做的,根本不需要嵌套循环。
要记住的关键是 R 默认是 向量化的 。这意味着 R 将同时修改向量的所有行。没有必要循环。因此,例如,如果 a
是一个具有值 1
和 2
的向量,我写 a + 1
,结果将是一个具有值 2
和3
.
将此逻辑应用到您的案例中,您可以这样写:
df$diffB <- ifelse(abs(df$a-df$b) < 2, 1, 0)
df$diffC <- ifelse(abs(df$a-df$c) < 2, 1, 0)
df$diffD <- ifelse(abs(df$a-df$d) < 2, 1, 0)
df
给予
a b c d diffB diffC diffD
1 2 4 5 3 0 0 1
2 3 4 5 4 1 0 1
3 3 4 4 4 1 1 1
4 4 4 4 2 1 1 0
如果您愿意,您可以编写一个循环遍历 列 ,Aron 在他的回答中给了您一个选择。
就个人而言,我发现使用 tidyverse 的代码比使用 base R 编写的代码更容易理解。这是因为我可以从左到右阅读 tidyverse 代码,而 base R 代码(通常)需要阅读从里到外。 Tidyverse 的语法也比基础 R 的语法更一致。
以下是我如何使用 tidyverse 解决您的问题:
library(tidyverse)
df %>%
mutate(
diffB=ifelse(abs(a-b) < 2, 1, 0),
diffC=ifelse(abs(a-c) < 2, 1, 0),
diffD=ifelse(abs(a-d) < 2, 1, 0)
)
并且“遍历列”变为
df %>%
mutate(
across(
c(b, c, d),
~ifelse(abs(a-.x) < 2, 1, 0),
.names="diff{.col}"
)
)
我正在努力解决与嵌套 for 循环和条件计算有关的问题。
假设我有一个这样的数据框:
df = data.frame("a" = c(2, 3, 3, 4),
"b" = c(4, 4, 4, 4),
"c" = c(5, 5, 4, 4),
"d" = c(3, 4, 4, 2))
有了这个 df,我想用一个条件比较向量之间的每个元素:如果两个元素之间的绝对差值小于 2(即 0 和 1 的差值),我想在 a 中给出 1新创建的向量,而两个元素之间的绝对差 >= 2,我想附加 0.
例如,对于向量“a”和其他向量“b”、“c”、“d”之间的计算,我想要这样的结果:0 0 1。第一个 0 是基于a1 和 b1 相差 2;第二个0是基于a1和c1的差3; 1基于a1和d1的差异。因此,我尝试制作一个嵌套的 for 循环,以将相同的行程也应用于以下行中的元素。
所以我的第一次试用是这样的:
list_all = list(df$a, df$b, df$c, df$d)
v0<-c()
for (i in list_all)
for (j in list_all)
if (i != j) {
if(abs(i-j)<2) {
v0<-c(v0, 1)
} else {
v0<-append(v0, 0)
}} else {
next}
结果是这样的:
v0
[1] 0 0 1 0 1 1 0 1 0 1 1 0
但是好像只计算了第一个元素,后面的元素没有计算
所以我的二审是这样的:
list = list(df$b, df$c, df$d)
v1<-c()
for (i in df$a){
for (j in list){
if(abs(i-j)<2) {
v1<-append(v1, 1)
} else {
v1<-append(v1, 0)
}
}
}
v1
v1
[1] 0 0 1 1 0 1 1 0 1 1 1 1
似乎计算是在 df$a 的所有元素和其他元素的第一个元素之间进行的。所以这也不是我需要的。
当我把 df$b 而不是 list 放在嵌套的 for 循环中时,结果更加混乱。
v2<-c()
for (i in df$a){
for (j in df$b){
if(abs(i-j)<2) {
v2<-append(v2, 1)
} else {
v2<-append(v2, 0)
}
}
}
v2
[1] 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1
好像不是在对应元素(同一行)之间计算,而是在所有向量之间计算,不分位置。
谁能告诉我如何解决这个问题?我不明白为什么嵌套 for 循环只适用于第一个元素。
提前致谢。
我不确定我是否理解正确,但是这个怎么样?
df = data.frame("a" = c(2, 3, 3, 4),
"b" = c(4, 4, 4, 4),
"c" = c(5, 5, 4, 4),
"d" = c(3, 4, 4, 2))
as.vector(apply(df, 1, \(x) ifelse(abs(x[1] - x[2:4]) < 2, 1, 0)))
#> [1] 0 0 1 1 0 1 1 1 1 1 1 0
我认为您正在让自己的生活变得不必要地复杂化。如果我理解正确的话,你可以做你想做的,根本不需要嵌套循环。
要记住的关键是 R 默认是 向量化的 。这意味着 R 将同时修改向量的所有行。没有必要循环。因此,例如,如果 a
是一个具有值 1
和 2
的向量,我写 a + 1
,结果将是一个具有值 2
和3
.
将此逻辑应用到您的案例中,您可以这样写:
df$diffB <- ifelse(abs(df$a-df$b) < 2, 1, 0)
df$diffC <- ifelse(abs(df$a-df$c) < 2, 1, 0)
df$diffD <- ifelse(abs(df$a-df$d) < 2, 1, 0)
df
给予
a b c d diffB diffC diffD
1 2 4 5 3 0 0 1
2 3 4 5 4 1 0 1
3 3 4 4 4 1 1 1
4 4 4 4 2 1 1 0
如果您愿意,您可以编写一个循环遍历 列 ,Aron 在他的回答中给了您一个选择。
就个人而言,我发现使用 tidyverse 的代码比使用 base R 编写的代码更容易理解。这是因为我可以从左到右阅读 tidyverse 代码,而 base R 代码(通常)需要阅读从里到外。 Tidyverse 的语法也比基础 R 的语法更一致。
以下是我如何使用 tidyverse 解决您的问题:
library(tidyverse)
df %>%
mutate(
diffB=ifelse(abs(a-b) < 2, 1, 0),
diffC=ifelse(abs(a-c) < 2, 1, 0),
diffD=ifelse(abs(a-d) < 2, 1, 0)
)
并且“遍历列”变为
df %>%
mutate(
across(
c(b, c, d),
~ifelse(abs(a-.x) < 2, 1, 0),
.names="diff{.col}"
)
)