Использование функции мутации с циклами - PullRequest
2 голосов
/ 19 января 2020

У меня есть df с несколькими столбцами, как в примере ниже. Я хочу изменить все нули на число два в столбцах от A1 до A5, но я не хочу записывать имена всех столбцов в функции mutate. Кто-нибудь знает, как я могу создать al oop, который идет от A1 до A5 и изменить нули на два с помощью функции mutate?

df = data.frame(A1 = c(0,1,1,0,0,1,1,1), B1 = c(0,1,1,0,0,0,0,0), C1 = c(1,1,1,0,0,0,0,0), A2 = c(0,1,1,0,0,0,0,0), A3 = c(1,1,1,0,1,1,1,1), A4 = c(1,1,1,0,0,1,1,1), A5 = c(0,1,1,0,0,1,1,1), C2 = c(1,1,1,0,0,1,0,0))

Я пытался сделать это с помощью следующего l oop

for (i in 1:5) {
   a = paste0('A', i)
  df = df %>% mutate(a = ifelse( a == 0, 2, 1))
}

... но функция изменения не принимает переменную.

Ответы [ 3 ]

5 голосов
/ 19 января 2020

Это можно сделать без всяких l oop. Создайте числовой c индекс или вектор имени столбца ('nm1') столбцов, которые нужно изменить, создайте подмножество набора данных при создании логической матрицы для подмножества набора данных и назначьте его 2

nm1 <- paste0("A", 1:5)
#Or use `startsWith`
#nm1 <- startsWith(names(df), "A")
df[nm1][!df[nm1]] <- 2
df
#  A1 B1 C1 A2 A3 A4 A5 C2
#1  2  0  1  2  1  1  2  1
#2  1  1  1  1  1  1  1  1
#3  1  1  1  1  1  1  1  1
#4  2  0  0  2  2  2  2  0
#5  2  0  0  2  1  2  2  0
#6  1  0  0  2  1  1  1  1
#7  1  0  0  2  1  1  1  0
#8  1  0  0  2  1  1  1  0

Или это также может быть обновлено как

df[nm1] <-  (!df[nm1]) + 1

Или с replace

cbind(df[setdiff(names(df), nm1)], replace(df[nm1], !df[nm1], 2))

С dplyr, для нескольких столбцов мы можем использовать mutate_all ( для всех столбцов) и mutate_at (выбранные столбцы)

library(dplyr)
df %>%
    mutate_at(vars(nm1), ~ replace(., .== 0, 2))

Или мы можем использовать al oop (так как кажется, что OP интересуется только циклами), где мы используем :=, оценивая 'a' на нем 'lhs' при преобразовании значения 'a' в sym bol, выполните оценку (!!), чтобы проверить, равно ли оно 0, затем верните 2 или 1

for (i in 1:5) {
    a <- paste0('A', i)
    df <- df %>%
               mutate(!!a := ifelse( !!rlang::sym(a) == 0, 2, 1))
  }

ПРИМЕЧАНИЕ: paste векторизовано, поэтому нам не нужно создавать 'a' внутри l oop. Он может

a <- paste0("A", 1:5)
for(nm in a) {
  df <- df %>%
          mutate(!! nm := ifelse(!! rlang::sym(nm) == 0, 2, 1))
 }

или другой вариант data.table

library(data.table)
setDT(df)[, (nm1) := replace(.SD, .SD == 0, 2), .SDcols = nm1]

или с set

setDT(df)
for(j in nm1) set(df, i = which(df[[j]] == 0), j = j, value = 2)
2 голосов
/ 19 января 2020

В качестве альтернативы, используя функцию apply, вы можете сделать:

apply(df,2,function(x) {ifelse(x==0,2,x)})

     A1 B1 C1 A2 A3 A4 A5 C2
[1,]  2  2  1  2  1  1  2  1
[2,]  1  1  1  1  1  1  1  1
[3,]  1  1  1  1  1  1  1  1
[4,]  2  2  2  2  2  2  2  2
[5,]  2  2  2  2  1  2  2  2
[6,]  1  2  2  2  1  1  1  1
[7,]  1  2  2  2  1  1  1  2
[8,]  1  2  2  2  1  1  1  2

РЕДАКТИРОВАТЬ мутирование только столбцов А1-А5

df[,paste0("A",1:5)] <- apply(df[,paste0("A",1:5)],2,function(x) {ifelse(x==0,2,x)})

  A1 B1 C1 A2 A3 A4 A5 C2
1  2  0  1  2  1  1  2  1
2  1  1  1  1  1  1  1  1
3  1  1  1  1  1  1  1  1
4  2  0  0  2  2  2  2  0
5  2  0  0  2  1  2  2  0
6  1  0  0  2  1  1  1  1
7  1  0  0  2  1  1  1  0
8  1  0  0  2  1  1  1  0
0 голосов
/ 19 января 2020

Вы можете попробовать следующий базовый код R, используя grepl() и &

df[df==0 & t(replicate(nrow(df),grepl("A",names(df))))]<- 2

или

df[df==0 & !!outer(rep(1,nrow(df)),grepl("A",names(df)))]<- 2

, такие как

> df
  A1 B1 C1 A2 A3 A4 A5 C2
1  2  0  1  2  1  1  2  1
2  1  1  1  1  1  1  1  1
3  1  1  1  1  1  1  1  1
4  2  0  0  2  2  2  2  0
5  2  0  0  2  1  2  2  0
6  1  0  0  2  1  1  1  1
7  1  0  0  2  1  1  1  0
8  1  0  0  2  1  1  1  0
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...