Бесконечная функция / цикл в R: Управление данными - PullRequest
2 голосов
/ 04 ноября 2011

Я пытаюсь реструктурировать огромный фрейм данных (около 12.000 случаев): в старом фрейме данных один человек занимает одну строку и имеет около 250 столбцов (например, Person 1, test A1, testA2, testB, ...), и я хочу все результаты теста A (1 - 10 A в целом и 24 элемента (AY) для этого человека в одном столбце, поэтому один человек в итоге получает 24 столбца и 10 строк. Перед элементами AY также имеется фиксированная часть информационного кадра) start (личная информация, такая как возраст, пол и т. д.), которую я хочу сохранить как есть (fixdata). Функция / цикл работает для 30 случаев (я пробовал это заранее), но для 12.000 он все еще рассчитывается, в течение почти 24 часов. Есть идеи почему?

restructure <- function(data, firstcol, numcol, numsets){
    out <- data.frame(t(rep(0, (firstcol-1)+ numcol)) )
    names(out) <- names(daten[0:(firstcol+numcol-1)])
      for(i in 1:nrow(daten)){
         fixdata <- (daten[i, 1:(firstcol-1)])

          for (j in (seq(firstcol, ((firstcol-1)+ numcol* numsets), by = numcol))){
              flexdata <- daten[i, j:(j+numcol-1)]
              tmp <- cbind(fixdata, flexdata)
              names(tmp) <- names(daten[0:(firstcol+numcol-1)])
              out <- rbind(out,tmp)
          }  
      }
    out <- out[2:nrow(out),]
    return(out)
}

Заранее спасибо!

Ответы [ 3 ]

5 голосов
/ 04 ноября 2011

Идея почему: вы rbind до out в каждой итерации.Это будет увеличиваться на дольше на каждую итерацию по мере роста - поэтому вы должны ожидать более линейного роста во время выполнения с увеличением наборов данных.

Итак, как говорит Андри, вы можете посмотреть на melt.

Или вы можете сделать это с ядром R: stack.Затем вам нужно привязать фиксированную часть к результату самостоятельно (вам нужно повторить фиксированные столбцы с each = n.var.cols

Третьим вариантом будет array2df из пакета arrayhelpers.

1 голос
/ 04 ноября 2011

Я согласен с остальными, посмотрите на reshape2 и пакет plyr, просто хочу немного добавить в другом направлении. В частности, melt, cast, dcast могут вам помочь. Кроме того, это может помочь использовать интеллектуальные имена столбцов, например ::1006

As<-grep("^testA",names(yourdf))
# returns a vector with the column position of all testA1 through 10s.

Кроме того, если вы «потратили» два измерения data.frame на test # и тип теста, то, очевидно, ничего не останется для человека. Конечно, вы идентифицируете их по идентификатору, к которому вы можете добавить эстетику при печати, но в зависимости от того, что вы хотите сделать, вы можете сохранить их в list. Таким образом, вы получите список людей с датафреймом для каждого человека. Я не уверен, что вы пытаетесь сделать, но все же надеюсь, что это поможет.

0 голосов
/ 04 ноября 2011

Возможно, вы не получаете plyr или другие функции для изменения формы компонента данных. Как насчет чего-то более прямого и низкого уровня. Если в настоящее время у вас есть только одна строка с A1, A2, A3 ... A10, B1-B10 и т. Д., Затем извлеките этот кусок материала из вашего фрейма данных, я предполагаю столбцы 11-250, а затем просто сделайте это разделите желаемую форму и соедините их вместе.

yDat <- data[, 11:250]
yDF <- lapply( 1:nrow(data), function(i) matrix(yDat[i,], ncol = 24) )
yDF <- do.call(rbind, y) #combine the list of matrices returned above into one
yDF <- data.frame(yDF) #get it back into a data.frame
names(yDF) <- LETTERS[1:24] #might as well name the columns

Это самый быстрый способ получить большую часть ваших данных в нужной форме. Все, что сделала функция lapply, это добавила атрибуты измерения в каждую строку, чтобы они были в нужной форме, а затем вернула их в виде списка, который был массифицирован с последующими строками. Но теперь он не имеет никакой вашей идентификационной информации из основного data.frame. Вам просто нужно повторить каждую строку первых 10 столбцов 10 раз. Или вы можете использовать вспомогательную функцию merge, чтобы помочь с этим. Создайте общий столбец, который уже входит в ваши первые 10 строк, в один из столбцов нового data.frame, а затем просто объедините их.

yInfo <- data[, 1:10]
ID <- yInfo$ID
yDF$ID <- rep( yInfo$ID, each = 10 )
newDat <- merge(yInfo, yDF)

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

newDat$condNum <- rep(1:10, nrow(newDat)/10)

Это будет очень быстро работающий код. Ваш data.frame на самом деле не так уж и велик, и большая часть вышеперечисленного будет выполнена через пару секунд.

Вот как вы должны думать о данных в R. Не то, чтобы не было вспомогательных функций для обработки большей части этого, но вы должны делать это, чтобы избежать как можно большего количества циклов. Технически, то, что произошло выше, имело только один цикл, lapply, использованный прямо в начале. В этом цикле тоже было очень мало (они должны быть компактными, когда вы их используете). Вы пишете в скалярном коде, а в R это очень и очень медленно ... даже если вы при этом не злоупотребляли памятью и не увеличивали объем данных. Кроме того, имейте в виду, что, хотя вы не всегда можете избежать какого-либо цикла, вы почти всегда можете избежать вложенных циклов, что является одной из ваших самых больших проблем.

(прочитайте это , чтобы лучше понять ваши проблемы в этом коде ... вы там сделали большинство больших ошибок)

...