Условно изменить значение последнего столбца - PullRequest
2 голосов
/ 21 июня 2020

У меня data.frame и я хочу изменить значение последнего столбца на основе значений всех предыдущих (кроме первого!) Столбцов.

Итак, если у меня есть:

id v1 v2 v3 wei
1  NA NA NA  1
2  1  1  2   2
3  1  1  NA  1
4  1  1  1   3

Мне нужно получить

id v1 v2 v3 wei
1  NA NA NA  0
2  1  1  2   2
3  1  1  NA  1
4  1  1  1   3

В основном, если у меня есть все переменные, начинающиеся с «v» с пропущенными значениями, wei должно быть 0. То же самое произойдет с df, в котором все значения в переменные равны 0. Значит, это должно работать для NA или 0.

Возможно ли это? Я хочу сохранить тот же столбец с именем wei и просто «обновить значение в соответствии с условием.

Ответы [ 4 ]

2 голосов
/ 21 июня 2020

Это то, что я придумал, возможно, не самое элегантное решение, но работает для любого количества столбцов, начинающихся с «v»:

library(dplyr)
df <- tibble::tribble(
  ~id, ~v1, ~v2, ~v3, ~wei,
  1 , NA, NA, NA, 1,
  2 , 1 , 1 , 2 , 2, 
  3 , 1 , 1 , NA, 1,
  4 , 1 , 1 , 1 , 3)


df %>% 
  rowwise() %>% 
  mutate(all_na = all(is.na(c_across(starts_with("v")))),
         all_zero = all(c_across(starts_with("v")) == 0)) %>% 
  mutate(wei = case_when(
    all_na | all_zero ~ 0,
    TRUE ~ wei
  )) %>% 
  ungroup() %>% 
  select(-all_na, -all_zero) # remove intermediate columns if needed, can be removed for debugging
2 голосов
/ 21 июня 2020

Вот способ tidyverse с ifelse

library(tidyverse)

df <- read.table(text="id v1 v2 v3 wei
1  NA NA NA  1
2  1  1  2   2
3  1  1  NA  1
4  1  1  1   3", header=T)
colnames(df)
#> [1] "id"  "v1"  "v2"  "v3"  "wei"
df
#>   id v1 v2 v3 wei
#> 1  1 NA NA NA   1
#> 2  2  1  1  2   2
#> 3  3  1  1 NA   1
#> 4  4  1  1  1   3
df %>% 
  mutate(wei = ifelse(is.na(v1) & is.na(v2) & is.na(v3), 0, wei))
#>   id v1 v2 v3 wei
#> 1  1 NA NA NA   0
#> 2  2  1  1  2   2
#> 3  3  1  1 NA   1
#> 4  4  1  1  1   3

, вы можете добиться этого в базе R аналогичным образом
# the same in base-R
df[is.na(df$v1)& is.na(df$v2)&is.na(df$v3),]$wei <- 0
df
#>   id v1 v2 v3 wei
#> 1  1 NA NA NA   0
#> 2  2  1  1  2   2
#> 3  3  1  1 NA   1
#> 4  4  1  1  1   3
2 голосов
/ 21 июня 2020

Использование rowSums:

cols <- grep('^v', names(df))
df$wei[rowSums(is.na(df[cols])) == length(cols) | 
       rowSums(df[cols] == 0, na.rm = TRUE) == length(cols)] <- 0
df

#  id v1 v2 v3 wei
#1  1 NA NA NA   0
#2  2  1  1  2   2
#3  3  1  1 NA   1
#4  4  1  1  1   3

Это превратит wei значения в 0, где все столбцы «v» - NA или 0.

В случае, если есть строку с 0 и NA мы можем сделать:

df$wei[rowSums(is.na(df[cols])|df[cols] == 0, na.rm = TRUE) == length(cols)] <- 0
2 голосов
/ 21 июня 2020

Использование dplyr (см. Примечания ниже):

columns <- grep("^v", names(df))
df %>% 
   mutate(wei = ifelse(apply(df[columns],1, function(x) all(is.na(x))),0,wei))
  id v1 v2 v3 wei
1  1 NA NA NA   0
2  2  1  1  2   2
3  3  1  1 NA   1
4  4  1  1  1   3

ПРИМЕЧАНИЕ

  • Это, вероятно, будет очень медленным из-за использования apply. Возможно, сначала можно использовать rowwise и / или t, либо pivot_*.

Данные:

df <- structure(list(id = 1:4, v1 = c(NA, 1L, 1L, 1L), v2 = c(NA, 1L, 
1L, 1L), v3 = c(NA, 2L, NA, 1L), wei = c(1L, 2L, 1L, 3L)), class = "data.frame", row.names = c(NA, 
-4L))
...