Создание фрейма данных с использованием 3 других фреймов данных, которые не имеют общих значений слияния - PullRequest
0 голосов
/ 14 февраля 2020

Я пытаюсь выполнить sh очень специфический тип процесса очистки данных с использованием R.

Мне даны 2 структуры данных и одна матричная структура. Матрица соответствует DF1 в качестве заголовков столбцов и DF2 в качестве заголовков строк, но я хочу взять все эти данные и преобразовать их в прямоугольный angular кадр данных с одним наблюдением на строку (на основе матрицы результатов, matrix_data ).

Используя приведенный ниже код, я могу создать по одному наблюдению на строку, но для больших наборов данных (~ 1M + уникальные записи) это может занять несколько минут для запуска (~ 5 мин). Прямо сейчас я использую для l oop для циклического перехода по DF1, и я использую do.call(... replicate()) для добавления строк к DF2. Обработка matrix_data проста - я разворачиваю данные в вектор и привязываю их к фреймам данных DF1_ext и DF2_ext. Есть ли лучший способ выполнить это for() l oop в R?

DF1 <- data.frame(x_1 = c('a','b','c','d','e'), y_1 = c('f','g','h','i','j'), z_1 = c('k','l','m','n','o'))
DF2 <- data.frame(v_2 = 1:3, w_2 = 4:6, x_2 = 7:9, y_2 = 10:12, z_2 = 13:15)
matrix_data <- matrix(data = 1:15, nrow = 3, ncol = 5)


DF1_ext <- NULL
DF1_length <- nrow(DF1) * nrow(DF2)

#Use ceiling function to determine which row to put in NULL dataframe
#i.e. ceiling() rounds up to nearest integer value, setting j = to incremental step in origin dataframe
#See resultant DF

for (k in 1:DF1_length) {
  j = ceiling(k / DF1_length * length(DF1[,2]))
  DF1_ext <- rbind(DF1_ext[], DF1[j,])
}

#replicate DF2 matrix with rbind() based on the number of rows in DF1
DF2_ext <- do.call(rbind, replicate(nrow(DF1), DF2, simplify = FALSE))

#cbind() all values together. 
#matrix_data can be transposed or not. This matters in the actual analysis, but should not matter here. 
DF_result <- cbind(DF1_ext, DF2_ext, as.vector(t(matrix_data)))

View(DF_result)

Я ищу более "R" способ выполнения этого кода, надеясь, что могут быть некоторые более эффективные функции по пути. Этот код, как есть, может быть скопирован в R и запущен только с базовыми функциями. Чтобы было ясно, я ищу лучший способ выполнения в R, потому что этот метод выполняется очень медленно, и кажется, что нужно много бегать по сравнению с большинством методологий R.

Ответы [ 3 ]

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

А как насчет пакета data.table? rbindlist является обязательной более быстрой альтернативой rbind.

Кроме того, @akrun предложил bind_rows из dplyr, что также намного быстрее, чем do.call.

library(data.table)
DF2_ext <- rbindlist(replicate(nrow(DF1), DF2, simplify = FALSE))

library(microbenchmark)
microbenchmark(do.call(rbind, replicate(nrow(DF1), DF2, simplify = FALSE)),
           rbindlist(replicate(nrow(DF1), DF2, simplify = FALSE)),
           bind_rows(replicate(nrow(DF1), DF2, simplify = FALSE)),
           cbind(sqldf("select * from DF1 join DF2"), data = c(t(matrix_data))))

Unit: microseconds
expr       min         lq       mean     median         uq       max neval cld
do.call(rbind, replicate(nrow(DF1), DF2, simplify = FALSE))   424.572   451.0790   515.0016   473.8225   500.0185  1243.674   100  a 
rbindlist(replicate(nrow(DF1), DF2, simplify = FALSE))   105.988   124.3765   164.1111   159.7705   173.8210   563.697   100  a 
bind_rows(replicate(nrow(DF1), DF2, simplify = FALSE))    36.590    48.9140   528.4883    62.6580    75.0540 46448.825   100  a 
cbind(sqldf("select * from DF1 join DF2"), data = c(t(matrix_data))) 15201.367 15771.5310 18581.6682 16308.9790 18329.5940 54964.681   100   b
1 голос
/ 14 февраля 2020

Это можно сделать довольно просто с пакетами dplyr и tidyr.

library(dplyr)
library(tidyr)
test <- DF1 %>% mutate(list_col = list(DF2)) %>% unnest() %>% 
  mutate(matrix_data = as.vector(t(matrix_data)))

В основном он повторяет DF2 столько, сколько необходимо для заполнения всех строк в DF1, а затем unnest повторяет каждую строку DF1 для каждой строки в DF2.

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

Выполните объединение, используя SQL, а затем cbind развернутое транспонирование matrix_data.

library(sqldf)
cbind(sqldf("select * from DF1 join DF2"), data = c(t(matrix_data)))
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...