Как мне взять подмножества фрейма данных в соответствии с группировкой в ​​R? - PullRequest
2 голосов
/ 24 сентября 2011

У меня проблема с агрегацией, которую я не могу понять, как эффективно работать в R.

Скажем, у меня есть следующие данные:

group1 <- c("a","b","a","a","b","c","c","c","c",
            "c","a","a","a","b","b","b","b")
group2 <- c(1,2,3,4,1,3,5,6,5,4,1,2,3,4,3,2,1)
value  <- c("apple","pear","orange","apple",
            "banana","durian","lemon","lime",
            "raspberry","durian","peach","nectarine",
            "banana","lemon","guava","blackberry","grape")
df <- data.frame(group1,group2,value)

Я заинтересован в выборке из данныхкадр df такой, что я случайным образом выбираю только одну строку из каждой комбинации факторов group1 и group2.

Как видите, результаты table(df$group1,df$group2)

  1 2 3 4 5 6
a 2 1 2 1 0 0
b 2 2 1 1 0 0
c 0 0 1 1 2 1

показывает, что некоторые комбинации видны более одного раза, а другие никогда не видны.Для тех, которые видны более одного раза (например, group1="a" и group2=3), я хочу выбрать случайным образом только одну из соответствующих строк и вернуть новый фрейм данных, который имеет только это подмножество строк.Таким образом, каждая возможная комбинация группирующих факторов представлена ​​только одной строкой во фрейме данных.

Один важный аспект здесь заключается в том, что мои фактические наборы данных могут содержать от 500 000 строк до> 2 000 000 строк, поэтомуважно помнить о производительности.

Я относительно новичок в R, поэтому мне было трудно понять, как правильно сгенерировать эту структуру.Одна попытка выглядела так (с использованием пакета plyr):

choice <- function(x,label) {
    cbind(x[sample(1:nrow(x),1),],data.frame(state=label))
}

df <- ddply(df[,c("group1","group2","value")],
            .(group1,group2),
            pick_junc,
            label="test")

Обратите внимание, что в этом случае я также добавляю дополнительный столбец к фрейму данных, называемый «метка», который указывается как дополнительныйаргумент функции ddply.Однако я убил это примерно через 20 минут.

В других случаях я пытался использовать aggregate или by или tapply, но я никогда не знаю точно, что получает указанная функция, что онадолжен вернуться, или что делать с результатом (особенно для by).

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

Я хочу любить R, поэтомупожалуйста помоги!Спасибо!

Ури

Ответы [ 2 ]

6 голосов
/ 24 сентября 2011

Вот решение plyr

set.seed(1234)
ddply(df, .(group1, group2), summarize, 
     value = value[sample(length(value), 1)])

Это дает нам

   group1 group2      value
1       a      1      apple
2       a      2  nectarine
3       a      3     banana
4       a      4      apple
5       b      1      grape
6       b      2 blackberry
7       b      3      guava
8       b      4      lemon
9       c      3     durian
10      c      4     durian
11      c      5  raspberry
12      c      6       lime

РЕДАКТИРОВАТЬ.С таким большим фреймом данных вам лучше использовать data.table

library(data.table)
dt = data.table(df)
dt[,list(value = value[sample(length(value), 1)]),'group1, group2']

РЕДАКТИРОВАТЬ 2: Сравнение производительности: Таблица данных в ~ 15 раз быстрее

group1 = sample(letters, 1000000, replace = T)
group2 = sample(LETTERS, 1000000, replace = T)
value  = runif(1000000, 0, 1)
df     = data.frame(group1, group2, value)
dt     = data.table(df)

f1_dtab = function() {
   dt[,list(value = value[sample(length(value), 1)]),'group1, group2']
}
f2_plyr = function() {ddply(df, .(group1, group2), summarize, value =          
   value[sample(length(value), 1)])
}

f3_by = function() {do.call(rbind,by(df,list(grp1 = df$group1,grp2 = df$group2),
  FUN = function(x){x[sample(nrow(x),1),]}))
}


library(rbenchmark)
benchmark(f1_dtab(), f2_plyr(), f3_by(), replications = 10)

      test  replications elapsed relative
  f1_dtab()           10   4.764  1.00000    
  f2_plyr()           10  68.261 14.32851    
    f3_by()           10  67.369 14.14127 
0 голосов
/ 24 сентября 2011

Еще один способ:

with(df, tapply(value, list( group1,  group2), length))
   1  2 3 4  5  6
a  2  1 2 1 NA NA
b  2  2 1 1 NA NA
c NA NA 1 1  2  1
# Now use tapply to sample withing groups
# `resample` fn is from the sample help page:
# Avoids an error with sample when only one value in a group.
resample <- function(x, ...) x[sample.int(length(x), ...)]
#Create a row index
df$idx <- 1:NROW(df)
rowidxs <- with(df,  unique( c(    # the `c` function will make a matrix into a vector
              tapply(idx, list( group1,  group2),
                            function (x) resample(x, 1) ))))
rowidxs
# [1]  1  5 NA 12 16 NA  3 15  6  4 14 10 NA NA  7 NA NA  8
df[rowidxs[!is.na(rowidxs)] , ]
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...