替换基于dplyr中的crossing函数的值

nqwrtyyt  于 2023-06-19  发布在  其他
关注(0)|答案(2)|浏览(95)

示例数据集:

library(tidyverse)    

data <- data.frame(
l = c(NA, 2, NA, 4),
m = c(5, NA, 7, NA),
n = c(NA, 10, NA, NA),
o = c(6, 7, NA, 8),
y = c(2, 3, 4, 5))

因此,我需要替换每行中的第一个非“NA”值,当它在四行1到0中依次出现时。我想用一个新的值替换第一个非NA值,这个值是原始的第一个非NA值和y列中的值的乘积。
我尝试使用dplyr运行以下代码:

result <- data %>%
  rowwise() %>%
  mutate(
    first_non_na_value = first(na.omit(c_across(l:o))),
    replaced_value = ifelse(
      !is.na(first_non_na_value),
      first_non_na_value * y,
      first_non_na_value
    )
  ) %>%
  ungroup()

然而,这给了我两个新的列,我不需要。我只希望新的“replaced_values”实际上替换每行中从左到右的l:o列中出现的第一个不是NA的值。我找不到一种方法来定义哪个列的值被替换,因为列将根据第一个(na.omit(c_across(l:o)))值出现的位置而改变。
预期结果应该如下所示:

result <- data.frame(
l = c(NA, 6, NA, 20),
m = c(10, NA, 28, NA),
n = c(NA, 10, NA, NA),
o = c(6, 7, NA, 8),
y = c(2, 3, 4, 5))

result

任何建议都将不胜感激

ujv3wf0j

ujv3wf0j1#

这里有一个相当迂回的tidyverse解决方案。我肯定还有更简洁优雅的。
1.将数据透视为长格式并按y分组
1.按组查找第一个非NA值的索引(行
1.按组比较索引与行号,如果匹配,则计算乘积,否则保留原始值
1.选择所需的列并透视回宽格式
把这些放在一起:

library(dplyr)
library(tidyr)

data %>% 
  pivot_longer(-y) %>% 
  group_by(y) %>% 
  mutate(i = which.min(is.na(value)), 
         r = row_number(), 
         newval = ifelse(i == r, y * value, value)) %>% 
  ungroup() %>% 
  select(y, name, newval) %>% 
  pivot_wider(names_from = name, values_from = newval)

结果:

# A tibble: 4 × 5
      y     l     m     n     o
  <dbl> <dbl> <dbl> <dbl> <dbl>
      2    NA    10    NA     6
      3     6    NA    10     7
      4    NA    28    NA    NA
      5    20    NA    NA     8
vfwfrxfs

vfwfrxfs2#

很高兴能在这里帮忙!我确信你可以用*apply函数而不是for循环来解决这个问题。可能sapply会工作,但我不知道如何轻松地解决这个问题。此外,我无法让dplyr::coalesce以与这里相同的方式工作。coalesce(l,m,n,o)可以完成任务,但coalesce(l:o)不能。如此快速和肮脏,对于几行,这里的输入略有不同。

data <- data.frame(
  l = c(NA, 2, NA, 4, NA),
  m = c(5, NA, NA, NA, NA),
  n = c(NA, 10, NA, NA, 3),
  o = c(6, 7, NA, 8, 5),
  y = c(2, 3, 4, 5, 2))

library(dplyr)

t <- data %>%
  rowwise() %>%
  mutate(
    first_non_na_value = first(na.omit(c_across(l:o)))
    ,column_index=match(first_non_na_value,c_across(l:o))
    ,replaced_value = ifelse(
      !is.na(first_non_na_value),
      first_non_na_value * y,
      first_non_na_value
    )
  )

for (i in 1:nrow(t)) { 
  t[i,t$column_index[i]] <- t[i,"replaced_value"]
}

t %>% select(-c(first_non_na_value,column_index,replaced_value))

输入

l  m  n  o y
1 NA  5 NA  6 2
2  2 NA 10  7 3
3 NA NA NA NA 4
4  4 NA NA  8 5
5 NA NA  3  5 2

结果

l  m  n  o y
1 NA 10 NA  6 2
2  6 NA 10  7 3
3 NA NA NA NA 4
4 20 NA NA  8 5
5 NA NA  6  5 2

相关问题