L oop через и изменить несколько столбцов с помощью переменной с приращением - PullRequest
3 голосов
/ 09 июля 2020

Моя цель - выполнить несколько операций с столбцами в одной строке кода без жесткого кодирования имен переменных.

structure(list(Subject = 1:6, Congruent_1 = c(359, 391, 384, 
316, 287, 403), Congruent_2 = c(361, 378, 322, 286, 276, 363), 
    Congruent_3 = c(342, 355, 334, 274, 297, 335), Congruent_4 = c(365, 
    503, 324, 256, 266, 388), Congruent_5 = c(335, 354, 320, 
    272, 260, 337), Incongruent_1 = c(336, 390, 402, 305, 310, 
    400), Incongruent_2 = c(366, 407, 386, 280, 243, 393), Incongruent_3 = c(323, 
    455, 317, 308, 259, 325), Incongruent_4 = c(361, 392, 357, 
    274, 342, 350), Incongruent_5 = c(300, 366, 378, 263, 258, 
    349)), row.names = c(NA, 6L), class = "data.frame")

Мои данные выглядят так .

Мне нужно выполнить вычитание столбцов и сохранить эти новые значения в новых столбцах. Например, новый столбец с именем selhist_1 должен быть вычислен как Incongruent_1 - Congruent_1. Я попытался написать для l oop, который индексирует существующие столбцы по их именам и создает новые столбцы, используя ту же переменную индексации:

for(i in 1:5)(
DP4 = mutate(DP4, as.name(paste("selhistB_",i,sep="")) = as.name(paste("Incongruent_",i,sep="")) - as.name(paste("Congruent_",i,sep="")))
)

, но я получил эту ошибку:

Error: unexpected '=' in: "for(i in 1:5)( DP4 = mutate(DP4, as.name(paste("selhistB_",i,sep="")) ="

Я предпочитаю использовать этот модульный подход, а не жестко кодировать и писать «selhistB = incongruent_1 - congruent_1» пять раз, используя функцию mutate().

Мне также интересно, смогу ли я достичь той же цели в длинной версии этих данных, и, возможно, это будет иметь больше смысла.

Ответы [ 4 ]

3 голосов
/ 09 июля 2020
library(dplyr)

d %>% 
  pivot_longer(-Subject, 
               names_to = c(".value", "id"), 
               names_sep = "_") %>% 
  mutate(selhistB = Incongruent - Congruent) %>% 
  pivot_wider(names_from = id, values_from = c(Congruent, Incongruent, selhistB))

Или просто пропустите последний поворот и оставьте все как можно дольше.

2 голосов
/ 09 июля 2020

Вы можете использовать split.default и разделить суффикс имен столбцов, затем l oop по списку и вычесть столбец 2 из столбца 1, т.е.

lapply(split.default(df[-1], sub('.*_', '', names(df[-1]))), function(i) i[1] - i[2])
1 голос
/ 09 июля 2020

Если вы уже используете пакеты tidyverse, следующий код будет делать именно то, что вам нужно:

library(dplyr)

for(i in 1:5){
  DP4 <- DP4 %>% mutate(UQ(sym(paste0("selhistB_",i))) := 
  UQ(sym(paste0("Incongruent_",i))) - UQ(sym(paste0("Congruent_",i))))
}
DP4

  Subject Congruent_1 Congruent_2 Congruent_3 Congruent_4 Congruent_5
1       1         359         361         342         365         335
2       2         391         378         355         503         354
3       3         384         322         334         324         320
4       4         316         286         274         256         272
5       5         287         276         297         266         260
6       6         403         363         335         388         337
  Incongruent_1 Incongruent_2 Incongruent_3 Incongruent_4 Incongruent_5
1           336           366           323           361           300
2           390           407           455           392           366
3           402           386           317           357           378
4           305           280           308           274           263
5           310           243           259           342           258
6           400           393           325           350           349
  selhistB_1 selhistB_2 selhistB_3 selhistB_4 selhistB_5
1         23         -5         19          4         35
2          1        -29       -100        111        -12
3        -18        -64         17        -33        -58
4         11          6        -34        -18          9
5        -23         33         38        -76          2
6          3        -30         10         38        -12
1 голос
/ 09 июля 2020

Используя вычитание по всем совпадающим столбцам, попробуйте:

x <- df1[, grepl("^C", colnames(df1)) ] - df1[, grepl("^I", colnames(df1)) ]
names(x) <- paste0("selhistB_", seq_along(names(x)))

res <- cbind(df1, x)
res

  Subject Congruent_1 Congruent_2 Congruent_3 Congruent_4 Congruent_5
1       1         359         361         342         365         335
2       2         391         378         355         503         354
3       3         384         322         334         324         320
4       4         316         286         274         256         272
5       5         287         276         297         266         260
6       6         403         363         335         388         337
  Incongruent_1 Incongruent_2 Incongruent_3 Incongruent_4 Incongruent_5
1           336           366           323           361           300
2           390           407           455           392           366
3           402           386           317           357           378
4           305           280           308           274           263
5           310           243           259           342           258
6           400           393           325           350           349
  selhistB_1 selhistB_2 selhistB_3 selhistB_4 selhistB_5
1         23         -5         19          4         35
2          1        -29       -100        111        -12
3        -18        -64         17        -33        -58
4         11          6        -34        -18          9
5        -23         33         38        -76          2
6          3        -30         10         38        -12

Изменить: моя неудачная попытка dplyr с 4 поворотами, конечно, есть лучший способ:

library(dplyr)
library(tidyr)

pivot_longer(df1, cols = -1, names_to = c("grp", "id"), names_sep = "_") %>%
  pivot_wider(id_cols = c(Subject, id), names_from = grp, values_from = value) %>% 
  mutate(selhistB = Congruent - Incongruent) %>% 
  pivot_longer(cols = -c(Subject, id)) %>% 
  mutate(name_id = paste(name, id, sep = "_")) %>% 
  pivot_wider(id_cols = Subject, names_from = name_id) %>% 
  data.frame # ignore: just using this to print the full data

  Subject Congruent_1 Incongruent_1 selhistB_1 Congruent_2 Incongruent_2 selhistB_2 Congruent_3 Incongruent_3
1       1         359           336         23         361           366         -5         342           323
2       2         391           390          1         378           407        -29         355           455
3       3         384           402        -18         322           386        -64         334           317
4       4         316           305         11         286           280          6         274           308
5       5         287           310        -23         276           243         33         297           259
6       6         403           400          3         363           393        -30         335           325
  selhistB_3 Congruent_4 Incongruent_4 selhistB_4 Congruent_5 Incongruent_5 selhistB_5
1         19         365           361          4         335           300         35
2       -100         503           392        111         354           366        -12
3         17         324           357        -33         320           378        -58
4        -34         256           274        -18         272           263          9
5         38         266           342        -76         260           258          2
6         10         388           350         38         337           349        -12
...