在r中的特定条件下从特定列填充一行
Filling a row from a certain column under certain condition in r
当这些列在该行中包含“-3”时,我想用某些特定列(本例中的 B 和 E)的“-3”填充到最后一行。我想出了一个解决方案,但它在我的原始数据集(2435 x 431 个单元格)中非常慢并且有 15 列来检查值 ==“-3”。
在此示例中,要填充“-3”的行是“B”列中的第 4 行和第 10 行以及“D”列中的第 3 行。请注意,4 和 10 在“E”列中也包含值 ==“-3”,但在迭代“B”列时它们已经被填充
library(tidyverse)
values <- as.character(-3:3)
set.seed(123)
data <- tibble(
A = sample(values, 10, replace = T),
B = sample(values, 10, replace = T),
C = sample(values, 10, replace = T),
D = sample(values, 10, replace = T),
E = sample(values, 10, replace = T),
F = sample(values, 10, replace = T)
)
fill_minus_three <- function(x){
for (i in 1:length(x)){
if ((names(x)[i] %in% c("B", "E")) && x[i] == "-3"){
x[i:length(x)] <- "-3"
break
}
}
return(x)
}
t(apply(data, 1, fill_minus_three)) %>%
as_tibble()
#> # A tibble: 10 x 6
#> A B C D E F
#> <chr> <chr> <chr> <chr> <chr> <chr>
#> 1 3 0 0 -1 1 1
#> 2 3 2 -3 0 3 -1
#> 3 -1 2 -3 2 -3 -3
#> 4 2 -3 -3 -3 -3 -3
#> 5 -1 -2 -1 -1 -2 -2
#> 6 -2 -1 -2 3 3 1
#> 7 -2 1 3 1 -1 1
#> 8 2 -1 -2 0 0 0
#> 9 -1 -1 -3 3 1 3
#> 10 1 -3 -3 -3 -3 -3
此外,我想使用 map_* 系列,因为其余脚本遵循 tidyverse 方法(但是,这是可选的)。
如果在当前列之前的指定列中遇到任何 -3,您可以通过转换为长格式、按原始行分组并切换值来解决此问题:
library(tidyverse)
columns_I_care_about <- c("B", "D")
data %>%
mutate(row = row_number()) %>%
pivot_longer(-row) %>%
group_by(row) %>%
mutate(flag = value == "-3" & name %in% columns_I_care_about,
value = if_else(cumsum(flag) > 0, "-3", value)) %>%
ungroup() %>%
select(row, name, value) %>%
pivot_wider(names_from = name, values_from = value)
结果
# A tibble: 10 × 7
row A B C D E F
<int> <chr> <chr> <chr> <chr> <chr> <chr>
1 1 3 0 0 -1 1 1
2 2 3 2 -3 0 3 -1
3 3 -1 2 -3 2 -3 2
4 4 2 -3 -3 -3 -3 -3
5 5 -1 -2 -1 -1 -2 -2
6 6 -2 -1 -2 3 3 1
7 7 -2 1 3 1 -1 1
8 8 2 -1 -2 0 0 0
9 9 -1 -1 -3 3 1 3
10 10 1 -3 -3 -3 -3 -3
Si entenc bé,您正在尝试根据 B 列和 E 列中的值更改多列中的值。
不需要 for 循环或 map/apply 函数,您只需使用 mutate
并将其与 across
:
配对
library(dplyr)
data |>
mutate(across(C:F, ~ if_else(B == "-3", "-3", .x)),
F = if_else(E == "-3", "-3", F))
输出
#> # A tibble: 10 × 6
#> A B C D E F
#> <chr> <chr> <chr> <chr> <chr> <chr>
#> 1 3 0 0 -1 1 1
#> 2 3 2 -3 0 3 -1
#> 3 -1 2 -3 2 -3 -3
#> 4 2 -3 -3 -3 -3 -3
#> 5 -1 -2 -1 -1 -2 -2
#> 6 -2 -1 -2 3 3 1
#> 7 -2 1 3 1 -1 1
#> 8 2 -1 -2 0 0 0
#> 9 -1 -1 -3 3 1 3
#> 10 1 -3 -3 -3 -3 -3
由 reprex package (v2.0.1)
创建于 2022-06-02
我想了想,我意识到我不需要遍历所有列,只需要检查值 ==“-3”的列。所以我稍微改变了函数,我工作得更快(整个数据集中 0.3 秒,而之前花了两分钟)。然而,它不是 tidy-friendly。 :/
positions <- which(names(data) %in% c("B", "E"))
fill_minus_three <- function(x, positions){
for (i in positions){
if (x[i] == "-3"){
x[i:length(x)] <- "-3"
break
}
}
return(x)
}
t(apply(data, 1, function(x) fill_minus_three(x, positions))) %>%
as_tibble()
当这些列在该行中包含“-3”时,我想用某些特定列(本例中的 B 和 E)的“-3”填充到最后一行。我想出了一个解决方案,但它在我的原始数据集(2435 x 431 个单元格)中非常慢并且有 15 列来检查值 ==“-3”。
在此示例中,要填充“-3”的行是“B”列中的第 4 行和第 10 行以及“D”列中的第 3 行。请注意,4 和 10 在“E”列中也包含值 ==“-3”,但在迭代“B”列时它们已经被填充
library(tidyverse)
values <- as.character(-3:3)
set.seed(123)
data <- tibble(
A = sample(values, 10, replace = T),
B = sample(values, 10, replace = T),
C = sample(values, 10, replace = T),
D = sample(values, 10, replace = T),
E = sample(values, 10, replace = T),
F = sample(values, 10, replace = T)
)
fill_minus_three <- function(x){
for (i in 1:length(x)){
if ((names(x)[i] %in% c("B", "E")) && x[i] == "-3"){
x[i:length(x)] <- "-3"
break
}
}
return(x)
}
t(apply(data, 1, fill_minus_three)) %>%
as_tibble()
#> # A tibble: 10 x 6
#> A B C D E F
#> <chr> <chr> <chr> <chr> <chr> <chr>
#> 1 3 0 0 -1 1 1
#> 2 3 2 -3 0 3 -1
#> 3 -1 2 -3 2 -3 -3
#> 4 2 -3 -3 -3 -3 -3
#> 5 -1 -2 -1 -1 -2 -2
#> 6 -2 -1 -2 3 3 1
#> 7 -2 1 3 1 -1 1
#> 8 2 -1 -2 0 0 0
#> 9 -1 -1 -3 3 1 3
#> 10 1 -3 -3 -3 -3 -3
此外,我想使用 map_* 系列,因为其余脚本遵循 tidyverse 方法(但是,这是可选的)。
如果在当前列之前的指定列中遇到任何 -3,您可以通过转换为长格式、按原始行分组并切换值来解决此问题:
library(tidyverse)
columns_I_care_about <- c("B", "D")
data %>%
mutate(row = row_number()) %>%
pivot_longer(-row) %>%
group_by(row) %>%
mutate(flag = value == "-3" & name %in% columns_I_care_about,
value = if_else(cumsum(flag) > 0, "-3", value)) %>%
ungroup() %>%
select(row, name, value) %>%
pivot_wider(names_from = name, values_from = value)
结果
# A tibble: 10 × 7
row A B C D E F
<int> <chr> <chr> <chr> <chr> <chr> <chr>
1 1 3 0 0 -1 1 1
2 2 3 2 -3 0 3 -1
3 3 -1 2 -3 2 -3 2
4 4 2 -3 -3 -3 -3 -3
5 5 -1 -2 -1 -1 -2 -2
6 6 -2 -1 -2 3 3 1
7 7 -2 1 3 1 -1 1
8 8 2 -1 -2 0 0 0
9 9 -1 -1 -3 3 1 3
10 10 1 -3 -3 -3 -3 -3
Si entenc bé,您正在尝试根据 B 列和 E 列中的值更改多列中的值。
不需要 for 循环或 map/apply 函数,您只需使用 mutate
并将其与 across
:
library(dplyr)
data |>
mutate(across(C:F, ~ if_else(B == "-3", "-3", .x)),
F = if_else(E == "-3", "-3", F))
输出
#> # A tibble: 10 × 6
#> A B C D E F
#> <chr> <chr> <chr> <chr> <chr> <chr>
#> 1 3 0 0 -1 1 1
#> 2 3 2 -3 0 3 -1
#> 3 -1 2 -3 2 -3 -3
#> 4 2 -3 -3 -3 -3 -3
#> 5 -1 -2 -1 -1 -2 -2
#> 6 -2 -1 -2 3 3 1
#> 7 -2 1 3 1 -1 1
#> 8 2 -1 -2 0 0 0
#> 9 -1 -1 -3 3 1 3
#> 10 1 -3 -3 -3 -3 -3
由 reprex package (v2.0.1)
创建于 2022-06-02我想了想,我意识到我不需要遍历所有列,只需要检查值 ==“-3”的列。所以我稍微改变了函数,我工作得更快(整个数据集中 0.3 秒,而之前花了两分钟)。然而,它不是 tidy-friendly。 :/
positions <- which(names(data) %in% c("B", "E"))
fill_minus_three <- function(x, positions){
for (i in positions){
if (x[i] == "-3"){
x[i:length(x)] <- "-3"
break
}
}
return(x)
}
t(apply(data, 1, function(x) fill_minus_three(x, positions))) %>%
as_tibble()