2013-07-24 4 views
3

Скажем, у меня есть этот data.frameГруппа data.frame по нескольким столбцам

data <- data.frame(foo = c(1, 1, 2, 2), 
        bar = c(10,10,10,20), 
        baz = c(1, 2, 3, 4), 
        qux = c(5, 6, 7, 8)) 

Я хочу, чтобы сгруппировать его по foo и bar столбцов, чтобы прибыть на это:

expected <- list(
    data.frame(foo = c(1, 1), 
      bar = c(10, 10), 
      baz = c(1, 2), 
      qux = c(5, 6)), 
    data.frame(foo = 2, 
      bar = 10, 
      baz = 3, 
      qux = 7), 
    data.frame(foo = 2, 
      bar = 20, 
      baz = 4, 
      qux = 8) 
) 

я могу генерировать кадр со строкой для каждой группы, но я не смог найти функцию MATCH; что при заданном входном кадре со столбцами foo,bar,baz,qux и в кадре фильтра с столбцами foo,bar возвращаются строки, в которых соответствует содержимое ячейки foo,bar.

groups <- unique(data[c("foo","bar")]) 
MATCH(data, groups[1,]) == expected[[1]] 
MATCH(data, groups[2,]) == expected[[2]] 
MATCH(data, groups[3,]) == expected[[3]] 

Или более высокий уровень GROUP функция, которая просто возвращает список фреймов, где столбцы данный матч:

GROUP(data, by=c("foo","bar")) == expected 

Ближайший я пришел к тому, что это

out <- aggregate(. ~ foo + bar, data, list) 

Где ячейки baz, qux являются следующими:

> out 
    foo bar baz qux 
1 1 10 1, 2 5, 6 
2 2 10 3 7 
3 2 20 4 8 
> class(out[,"baz"]) 
[1] "list" 

Таким образом, каждая группа представляет собой строку в out, но как я могу развернуть это снова, так что out[1,] станет data.frame с двумя строками, например expected[[1]]?

ответ

7

Похоже, вам просто нужно split.

Вариант 1: Сохранение всех «уровней» комбинации «foo» и «bar», даже если это приводит к пустой data.frame.

> split(data, list(data$foo, data$bar)) 
$`1.10` 
    foo bar baz qux 
1 1 10 1 5 
2 1 10 2 6 

$`2.10` 
    foo bar baz qux 
3 2 10 3 7 

$`1.20` 
[1] foo bar baz qux 
<0 rows> (or 0-length row.names) 

$`2.20` 
    foo bar baz qux 
4 2 20 4 8 

Вариант 2: Удаление пустых «уровней» комбинация «Foo» и «бар» - как вы делаете в вашем ожидаемом результате.

> split(data, list(data$foo, data$bar), drop=TRUE) 
$`1.10` 
    foo bar baz qux 
1 1 10 1 5 
2 1 10 2 6 

$`2.10` 
    foo bar baz qux 
3 2 10 3 7 

$`2.20` 
    foo bar baz qux 
4 2 20 4 8 
+0

другой вариант по той же схеме является ' split (данные, вставка (данные $ foo, данные $ bar)) ' – eddi

+0

@eddi, конечно. Я просто использую 'split' так, как он разработан/документирован, предоставляя« список »факторов группировки при расщеплении более чем на один фактор. Решение 'paste' устраняет необходимость использования' drop'. Вы видите какие-либо преимущества 'paste' над' взаимодействием' (что по умолчанию используется 'split')? Кажется, я помню, как я видел ответ на SO, где 'paste' был значительно быстрее, чем« взаимодействие », но не может найти его прямо сейчас. – A5C1D2H2I1M1N2O1R2T1

+0

afaik 'interactive' просто добавляет много лишних вещей (а потом и в конце концов« вставляет »), которые просто не нужны для этого конкретного случая. – eddi

3

dlply от plyr предназначен именно для этой цели:

require(plyr)  
dlply(data , .(foo , bar)) 

$`1.10` 
    foo bar baz qux 
1 1 10 1 5 
2 1 10 2 6 

$`2.10` 
    foo bar baz qux 
1 2 10 3 7 

$`2.20` 
    foo bar baz qux 
1 2 20 4 8 
+0

I «Я никогда не получал висеть« plyr », но +1 для обмена альтернативами! – A5C1D2H2I1M1N2O1R2T1

+0

@AnandaMahto спасибо.Я жду, пока eddi опубликует решение 'data.table' .... :-) –

+0

Я вижу ваш смайлик, но может ли« data.table »извлечь выгоду из такой структуры? Я так не думаю. Я бы предположил, что «ключ» позаботится об этом в значительной степени. – A5C1D2H2I1M1N2O1R2T1

0

Try это, что как @ решение Ананды, но использует interaction:

> split(data,interaction(data$foo,data$bar)) 
$`1.10` 
    foo bar baz qux 
1 1 10 1 5 
2 1 10 2 6 

$`2.10` 
    foo bar baz qux 
3 2 10 3 7 

$`1.20` 
[1] foo bar baz qux 
<0 rækker> (eller 0-længde row.names) 

$`2.20` 
    foo bar baz qux 
4 2 20 4 8 

> split(data,interaction(data$foo,data$bar), drop=TRUE) 
$`1.10` 
    foo bar baz qux 
1 1 10 1 5 
2 1 10 2 6 

$`2.10` 
    foo bar baz qux 
3 2 10 3 7 

$`2.20` 
    foo bar baz qux 
4 2 20 4 8 
+2

Считаете ли вы, что, поскольку это якобы тот же ответ, что и @AnandaMahto, но с использованием другого метода для создания переменной группировки, лучше служил комментарием или редактировал ответ Ананды? –

+0

@ Simono101 Я отправил исходную версию, пока он публиковал его. Затем я отредактировал после того, как увидел его ответ ... так ... что мне делать ... – Thomas

+0

@ SimonO101, еще лучше, посмотрите код для 'split.default' или объяснение' f' на странице справки для «раскола». Аргумент 'f' - это именно« взаимодействие ». – A5C1D2H2I1M1N2O1R2T1

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