Использование dplyr / purrr вместо циклов for для маскирования нескольких столбцов и / или расширения строк - PullRequest
0 голосов
/ 05 февраля 2019

По сути, речь идет об использовании битовых масок / двоичных столбцов и ориентированных на строки операций с таблицей / фреймом данных: во-первых, для создания логического вектора из комбинации выбранных столбцов, которые можно использовать для маскирования вектора символов, представляющего «что»столбцы помечены.Во-вторых, расширение строки - учитывая количество в одном столбце, создайте таблицу данных, содержащую исходные данные строки, реплицированные это число раз.

Для суммирования флагов используется побитовая маска с разбивкой по строкам, которая использует purrr:уменьшить для конкатенации флагов, представленных строк, я не могу найти краткий метод, чтобы сделать это в цепочке%>%, а не отдельный цикл for.Я подозреваю, что purrr :: map требуется, но я не могу получить его / правильный синтаксис.

Для раскрытия строки вложенный цикл имеет ужасающую производительность, и я не могу найти путь для dplyr / purrr в строку-произведите эту строку определенное количество раз в строке.Карта и другие функции должны были бы создавать и добавлять несколько строк, на которые, я думаю, карта не способна.

Следующий код производит требуемый вывод - но, кроме проблем с производительностью (особенно в отношении расширения строк)), Я хотел бы иметь возможность делать это как векторизованные операции.

library(tidyverse)
library(data.table)
dt <- data.table(C1=c(0,0,1,0,1,0),
         C2=c(1,0,0,0,0,1),
         C3=c(0,1,0,0,1,0),
         C4=c(0,1,1,0,0,0),
         C5=c(0,0,0,0,1,1),
         N=c(5,2,6,8,1,3),
         Spurious = '')
flags <- c("Scratching Head","Screaming",
       "Breaking Keyboard","Coffee Break",
       "Giving up")

# Summarise states
flagSummary <- function(dt){
    interim <- dt %>%
            dplyr::mutate_at(vars(C1:C5),.funs=as.logical) %>%
    dplyr::mutate(States=c(""))

    for(i in 1:nrow(interim)){
        interim$States[i] <-
        flags[as.logical(interim[i,1:5])] %>%
        purrr::reduce(~ paste(.x, .y, sep = ","),.init="") %>%
        stringr::str_replace("^[,]","") }
      dplyr::select(interim,States,N) }

summary <- flagSummary(dt)
View(summary)

# Expand states
expandStates <- function(dt){
    interim <- dt %>%
    dplyr::mutate_at(vars(C1:C5), .funs=as.logical) %>%
    dplyr::select_at(vars(C1:C5,N)) %>%
    data.table::setnames(.,append(flags,"Count"))

    expansion <- interim[0,1:5]
    for(i in 1:nrow(interim)){
        for(j in 1:interim$Count[i]){
        expansion <- bind_rows(expansion, interim[i,1:5]) } }
      expansion }

expansion <- expandStates(dt)
View(expansion)

Как уже говорилось, код дает ожидаемый результат.Я бы хотел увидеть то же самое, не прибегая к циклам for и не имея возможности объединить функции в исходные мутировать / выбирать.

1 Ответ

0 голосов
/ 08 февраля 2019

Что касается расширения строки функции expandStates, здесь предлагается ответ Реплицируйте каждую строку data.frame и укажите количество репликаций для каждой строки? с помощью A5C1D2H2I1M1N2O1R2T1.

По сути, вложенный цикл for просто заменяется на

interim[rep(rownames(interim[,1:5]),interim$Count),][1:5]

. По моим «фактическим» данным это сокращает системное время пользователя с 28,64 секунды до 0,06, чтобы получить около 26000 строк.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...