R повторять элементы фрейма данных - PullRequest
4 голосов
/ 04 января 2012

Я искал в Интернете, но не смог найти решение своей проблемы.У меня есть фрейм данных из цифр и символов:

mydf <- data.frame(col1=c(1, 2, 3, 4), 
                   col2 = c(5, 6, 7, 8), 
                   col3 = c("a", "b", "c", "d"), stringsAsFactors  = FALSE)

mydf:

col1 col2 col3
  1    5   a
  2    6   b
  3    7   c
  4    8   d

Я хотел бы повторить это в

col1 col2 col3
  1   5    a
  1   5    a
  1   5    a
  2   6    b
  2   6    b
  2   6    b
  3   7    c
  3   7    c
  3   7    c
  4   8    d
  4   8    d
  4   8    d

Использование apply(mydf, 2, function(x) rep(x, each = 3))даст правильное повторение, но не сохранит классы col1, col2 и col3 как числовые, числовые и символьные, соответственно, как мне бы хотелось.Это построенный пример, и установка классов каждого столбца в моем фрейме данных немного утомительна.

Есть ли способ сделать повторение при сохранении классов?

Ответы [ 6 ]

10 голосов
/ 04 января 2012

Это даже проще, чем вы думаете.

index <- rep(seq_len(nrow(mydf)), each = 3)
mydf[index, ]

Это также позволяет избежать неявного зацикливания с apply.

4 голосов
/ 04 января 2012

Это неудачное и неожиданное преобразование класса (в любом случае, я тоже).Вот простой обходной путь, который использует тот факт, что data.frame - это просто специальный список.

data.frame(lapply(mydf, function(x) rep(x, each = 3)))

(кто-нибудь знает, почему поведение, которое наблюдатель задал, не следует сообщать как ошибку?)

2 голосов
/ 04 января 2012

Просто еще одно решение:

mydf3 <- do.call(rbind, rep(list(mydf), 3))
1 голос
/ 04 января 2012

Мне очень нравится ответ Ричи Коттона.

Но вы также можете просто использовать rbind и изменить его порядок.

res <-rbind(mydf,mydf,mydf)
res[order(res[,1],res[,2],res[,3]),]
1 голос
/ 04 января 2012

Посмотрите на aggregate и disaggregate в пакете raster. Или используйте мою модифицированную версию zexpand ниже:

# zexpand: analogous to disaggregate

zexpand<-function(inarray, fact=2, interp=FALSE,  ...)  {
# do same analysis of fact to allow one or two values, fact >=1 required, etc.
fact<-as.integer(round(fact))
switch(as.character(length(fact)),
            '1' = xfact<-yfact<-fact,
            '2'= {xfact<-fact[1]; yfact<-fact[2]},
            {xfact<-fact[1]; yfact<-fact[2];warning(' fact is too long. First two values used.')})
if (xfact < 1) { stop('fact[1] must be > 0') } 
if (yfact < 1) { stop('fact[2] must be > 0') }

bigtmp <- matrix(rep(t(inarray), each=xfact), nrow(inarray), ncol(inarray)*xfact, byr=T)  #does column expansion
bigx <- t(matrix(rep((bigtmp),each=yfact),ncol(bigtmp),nrow(bigtmp)*yfact,byr=T))
# the interpolation would go here. Or use interp.loess on output (won't
# handle complex data). Also, look at fields::Tps which probably does
# a much better job anyway.  Just do separately on Re and Im data
return(invisible(bigx))
}
0 голосов
/ 22 августа 2013

Пакет mefa поставляется с красивой оберткой для rep, примененной к data.frame. Это будет соответствовать вашему примеру в одной строке:

mefa:::rep.data.frame(mydf, each=3)
...