Как изменить столбцы в том же порядке, что и в матрице заказа, для каждой строки - PullRequest
1 голос
/ 20 февраля 2020

У меня есть матрица, в которой я сохранил порядок элементов вопросника, где первый столбец содержит название отображаемого элемента, второй столбец содержит второй отображаемый элемент и т. Д. c. Каждая строка в этой матрице представляет новый вопросник с теми же элементами, но с рандомизированным порядком в другом порядке.

> order.matrix
     [,1]    [,2]    [,3]   
[1,] "Anger" "Happy" "Sad"  
[2,] "Happy" "Sad"   "Anger"
[3,] "Sad"   "Anger" "Happy"

Я сохранил ответы на элементы в кадре данных:

> df.responses
  Anger Happy Sad
1     1     2   3
2     3     2   0
3     9     2   1

Теперь я хочу изменить порядок ответов в df.responses, чтобы они были аналогичны порядку элементов в order.matrix для каждой строки . (В результате имена столбцов df.responses больше не должны быть в результирующем df.) Результат в этом примере должен выглядеть следующим образом:

> df.result
  V1 V2 V3
1  1  2  3
2  2  0  3
3  1  9  2

Как / как я могу это сделать?

РЕДАКТИРОВАТЬ, в связи с комментарием: я хочу заменить имена элементов в order.matrix на соответствующие значения в df.responses

Ответы [ 4 ]

2 голосов
/ 20 февраля 2020

Используя базу R, вы можете l oop по строкам матрицы и назначить значения из ваших df.responses, выбрав порядок столбцов по значениям строки матрицы:

# copy df.responses so we won't grow an object in the loop
df.result <- df.responses
# Rename the columns as they won't be correct after
colnames(df.result) <- c("V1","V2","V3")

for (x in 1:nrow(order.matrix)) {
  # replace the line with the value ordered by the matrix line names
  df.result[x,] <- df.responses[x,order.matrix[x,]]  
}
2 голосов
/ 20 февраля 2020

1.Создать воспроизводимый пример

order.matrix <- matrix(c("Anger", "Happy", "Sad", "Happy", "Sad","Anger", "Sad", "Anger", "Happy"),
                       ncol=3,
                       byrow=TRUE)

df.responses <-matrix(c(1, 2, 3, 3, 2, 0, 9, 2, 1),
                        ncol=3,
                        byrow=TRUE)
colnames(df.responses) <- c("Anger", "Happy", "Sad")

2.Решение с использованием базы R:

result <- NULL
for (i in seq_along(order.matrix[, 1])) {
  result <- rbind(result, df.responses[i, order.matrix[i, ]])
}
colnames(result) <- c("V1", "V2", "V3")

        V1    V2  V3
[1,]     1     2   3
[2,]     2     0   3
[3,]     1     9   2
1 голос
/ 21 февраля 2020

Решение с purrr может быть следующим

df.result <- map2(.x = lapply(seq_len(nrow(responses)), function(i) responses[i,]),
                  .y = lapply(seq_len(nrow(order)), function(i) order[i,]),
                  .f = ~ .x[.y])
do.call("rbind", df.result)

В этом коде .x и .y являются списками векторов, то есть списком строк (после этого поста { ссылка }). Выходные данные map2 затем агрегируются в матрицу с do.call и rbind.

В случае, если кому-то интересно, как это можно сравнить с другими решениями, вот сравнение.

library(microbenchmark)
library(purrr)
set.seed(42) # For reproducibility purposes

# Comparison with given data
order.matrix <- matrix(c("Anger", "Happy", "Sad", "Happy", "Sad","Anger", "Sad", "Anger", "Happy"),
                       ncol=3,
                       byrow=TRUE)

df.responses <- matrix(c(1, 2, 3, 3, 2, 0, 9, 2, 1),
                       ncol=3,
                       byrow=TRUE)
colnames(df.responses) <- c("Anger", "Happy", "Sad")

solForLoop <- function(order, responses) {
  df.result <- responses
  colnames(df.result) <- paste0("V", 1:ncol(responses))
  for (i in 1:nrow(order)) {
    df.result[i,] <- responses[i,order[i,]]  
  }
  df.result
}

solmApply <- function(order, responses) {
  t(mapply(FUN = function(x, y) x[y], 
           as.data.frame(t(responses)),
           as.data.frame(t(order)),
           USE.NAMES = F
  ))
 }

solPurrr <- function(order, responses) {
  df.result <- map2(.x = lapply(seq_len(nrow(responses)), function(i) responses[i,]),
                    .y = lapply(seq_len(nrow(order)), function(i) order[i,]),
                    .f = ~ .x[.y])
  do.call("rbind", df.result)
}

microbenchmark::microbenchmark(
  solForLoop(order.matrix, df.responses),
  solmApply(order.matrix, df.responses),
  solPurrr(order.matrix, df.responses),
  times = 1000L,
  check = "equivalent"
)

# Unit: microseconds
#                                   expr     min      lq      mean   median       uq       max neval
# solForLoop(order.matrix, df.responses)   8.601  11.101  15.03331  15.9010  17.3020    62.002  1000
#  solmApply(order.matrix, df.responses) 313.801 346.701 380.32261 357.7510 374.2010 14322.900  1000
#   solPurrr(order.matrix, df.responses)  49.900  61.301  70.68950  70.7015  75.8015   190.700  1000

Учитывая, что данные взяты из вопросника, я буду считать, что каждое значение в строке order.matrix может встречаться только один раз. Для матрицы с теми же 3 столбцами, но 100 000 строк, мы находим, что

# Comparison for big data
order.matrix.big <- as.matrix(sample_n(as.data.frame(order.matrix), 100000, replace = TRUE))
df.responses.big <- as.matrix(sample_n(as.data.frame(df.responses), 100000, replace = TRUE))

microbenchmark::microbenchmark(
    solForLoop(order.matrix.big, df.responses.big),
    solmApply(order.matrix.big, df.responses.big),
    solPurrr(order.matrix.big, df.responses.big),
    times = 100L,
    check = "equivalent"
)

# Unit: milliseconds
#                                           expr       min        lq      mean    median        uq       max neval
# solForLoop(order.matrix.big, df.responses.big)  110.2585  130.0916  163.3382  142.4249  167.7584  514.7262   100
#  solmApply(order.matrix.big, df.responses.big) 4669.8815 4866.6152 5232.1814 5160.2967 5385.5000 6568.1718   100
#   solPurrr(order.matrix.big, df.responses.big)  441.6195  502.0853  697.7207  669.4963  871.9122 1218.6721   100

Так что, хотя map2 предоставляет интересный способ работы для "зацикливания" строк, в этом случае это не так быстрый простой для l oop.

1 голос
/ 20 февраля 2020

Базовым вариантом R является использование mapply, т. Е.

df.result <- t(mapply(function(v,k) v[k], 
                      data.frame(t(df.responses)),
                      data.frame(t(order.matrix)),
                      USE.NAMES = F
                      )
               )

таким, что

> df.responses
     [,1] [,2] [,3]
[1,]    1    2    3
[2,]    2    0    3
[3,]    1    9    2
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...