2010-05-24 4 views
76
df <- data.frame(var1=c('a', 'b', 'c'), var2=c('d', 'e', 'f'), freq=1:3) 

Что самый простой способ расширить первые две колонны выше data.frame, так что каждая строка отображается количество раз указанном в колонке «freq»?Репликация каждую строку data.frame и указать количество повторений для каждой строки

Другими словами, перейти от этого:

df 
    var1 var2 freq 
1 a d 1 
2 b e 2 
3 c f 3 

к этому:

df.expanded 
    var1 var2 
1 a d 
2 b e 
3 b e 
4 c f 
5 c f 
6 c f 

ответ

106

Вот одно решение:

df.expanded <- df[rep(row.names(df), df$freq), 1:2] 

Результат:

var1 var2 
1  a d 
2  b e 
2.1 b e 
3  c f 
3.1 c f 
3.2 c f 
+0

Отлично! Я всегда забываю, что вы можете использовать квадратные скобки таким образом. Я продолжаю думать об индексировании только для подмножества или переупорядочения. У меня было другое решение, которое намного менее изящно и, без сомнения, менее эффективно. Я мог бы опубликовать так, чтобы другие могли сравнивать. – wkmor1

+14

Для больших 'data.frame' более эффективным является замена' row.names (df) 'на' seq.int (1, nrow (df)) 'или' seq_len (nrow (df)) '. – Marek

+0

Это сработало фантастически для большого кадра данных - 1,5 миллиона рядов, 5 колос, очень быстро. Благодаря! – gabe

13

@ Решение neilfws отлично подходит для data.frame s, но не для data.table s, так как им не хватает row.names. Этот подход работает для обоих:

df.expanded <- df[rep(seq(nrow(df)), df$freq), 1:2] 

Для data.table хотя вам нужно добавить with=F и опционально может удалить df$:

dt <- data.table(df) 
dt.expanded <- dt[rep(seq(.N), freq), !"freq", with=F] 
+6

'.N' теперь доступен в первом аргументе' dt [] ', поэтому вы можете сделать' dt [rep (seq (.N), freq) ,! «freq», with = FALSE] 'или подобное. – Frank

+0

Спасибо, обновлено. –

+1

Другая альтернатива: 'df [rep (seq (.N), freq)] [, freq: = NULL]' – Jaap

33

Использование expandRows() из splitstackshape пакета:

library(splitstackshape) 
expandRows(df, "freq") 

Простой синтаксис, очень быстрый, работает на data.frame или data.table.

Результат:

var1 var2 
1  a d 
2  b e 
2.1 b e 
3  c f 
3.1 c f 
3.2 c f 
2

В случае, если вам нужно сделать эту операцию на очень больших data.frames я рекомендовал бы преобразовать его в data.table и использовать следующие, которые должны работать намного быстрее:

library(data.table) 
dt <- data.table(df) 
dt.expanded <- dt[ ,list(freq=rep(1,freq)),by=c("var1","var2")] 
dt.expanded[ ,freq := NULL] 
dt.expanded 

Смотрите, насколько быстрее это решение:

df <- data.frame(var1=1:2e3, var2=1:2e3, freq=1:2e3) 
system.time(df.exp <- df[rep(row.names(df), df$freq), 1:2]) 
## user system elapsed 
## 4.57 0.00 4.56 
dt <- data.table(df) 
system.time(dt.expanded <- dt[ ,list(freq=rep(1,freq)),by=c("var1","var2")]) 
## user system elapsed 
## 0.05 0.01 0.06 
+0

Я получаю сообщение об ошибке: 'Ошибка в rep (1, freq): неверный аргумент« times ». И учитывая, что уже есть данные.table ответ на этот вопрос, вы можете указать, как ваш подход отличается или когда он лучше, чем текущий answer.table ответ. Или, если нет существенного различия, вы можете добавить его как комментарий к существующему ответу. –

+0

@SamFirke: Спасибо за ваш комментарий. Странно, я просто попробовал еще раз, и я не получил такой ошибки. Используете ли вы оригинальный 'df'из вопроса OP? Мой ответ лучше, потому что другой ответ является неправильным использованием пакета data.table' с помощью синтаксиса 'data.frame', см. FAQ' data.table': «Как правило, плохой практикой является обращение к столбцам по номеру а не имя ». – vonjd

+1

Спасибо за объяснение. Ваш код работает для меня на образце 'df', отправленном OP, но когда я попытался сравнить это на более крупном data.frame, я получил эту ошибку. Я использовал data.frame: 'set.seed (1) dfbig <- data.frame (var1 = sample (буквы, 1000, replace = TRUE), var2 = sample (LETTERS, 1000, replace = TRUE), freq = sample (1:10, 1000, replace = TRUE)) 'На крошечном data.frame базовый ответ хорошо работает в моем бенчмаркинге, он просто не масштабируется для более крупных data.frames. Остальные три ответа успешно выполнялись с этим более крупным файлом данных. –

4

старый вопрос, новый глагол в tidyverse:

library(tidyr) # version >= 0.8.0 
df <- data.frame(var1=c('a', 'b', 'c'), var2=c('d', 'e', 'f'), freq=1:3) 
df %>% 
    uncount(freq) 

е

 Смежные вопросы

  • Нет связанных вопросов^_^