R Группировка / агрегация, где условие включает другие строки в таблице, а не только текущую строку - PullRequest
2 голосов
/ 01 июля 2011

Используя R, лучше всего объединять строки в условии, которое охватывает несколько строк. Например, для агрегирования любых строк, где z = 0 для n или более раз.

Как это будет выглядеть, запустите следующую таблицу с n = 3.

Пример таблицы x:

x   y   z
0   0   6
5   5   0
40  2   0
4   0   0
10  0   1
0   0   2
11  7   0
0   4   0
0   0   0
0   0   0
0   0   2
18  0   4

Таблица результатов:

x   y   z
0   0   6
49  7   0 <- Above two rows got aggregated
10  0   1
0   0   2
11  11  0 <- Above three rows got aggregated
0   0   2
18  0   4

Ответы [ 3 ]

4 голосов
/ 01 июля 2011

Поскольку кажется, что вы все еще находитесь в "фазе старта", я подумал, что пример использования пакета plyr будет полезен. plyr - чрезвычайно удобная библиотека, которая позволяет вам гибко (и кратко - как вы увидите ниже) гибко (и кратко - как вы увидите ниже) гибко (и кратко - как вы увидите ниже) обмениваться наборами данных / кубиками, так что вам, вероятно, стоит потратить на это время. Если вам понадобится выполнить аналогичные операции с очень большими наборами данных, вы можете также изучить пакет data.table .

Я предполагаю, что вы проделали у Романа трюк textConnection, чтобы получить данные в фрейм данных с именем mmf. Я добавляю столбец idx к mmf, чтобы вы могли установить его подмножество и обработать группу результатов по группам:

library(plyr)
# mmf <- read.table(textConnection( ...
rle.idx <- rle(mmf$z)
mmf$idx <- rep(seq(RLE$lengths), RLE$lengths)
ans <- ddply(mmf, .(idx), colwise(sum))

А ans выглядит так:

 x  y z idx
 0  0 6   1
49  7 0   6
10  0 1   3
 0  0 2   4
11 11 0  20
 0  0 2   6
18  0 4   7

Просто удалите столбец idx и все готово, например:

ans <- ans[, -4]
3 голосов
/ 01 июля 2011

Это код, который я использовал для получения вашего результата. Если у вас есть какие-либо вопросы, стреляйте.

mmf <- read.table(textConnection("x   y   z # read in your example data
0   0   6
5   5   0
40  2   0
4   0   0
10  0   1
0   0   2
11  7   0
0   4   0
0   0   0
0   0   0
0   0   2
18  0   4"), header = TRUE)

# see where there are zeros in the y column
mmf.rle <- rle(mmf$z) 
mmf.rle <- data.frame(lengths = mmf.rle$lengths, values = mmf.rle$values)

merge.rows <- 3
# select rows that have more or equal to three zeros
mmf.zero <- which(mmf.rle$values == 0 & mmf.rle$lengths >= merge.rows)

for (i in mmf.zero) {
# find which positions are zero, calculate sums and insert the result into a data.frame where the rows in question were turned to NA
    m.mmf <- mmf.rle$lengths[1:i] # select elements from 1 to where the zero appears
    select.rows <- (sum(m.mmf[1:length(m.mmf) - 1])+1):sum(m.mmf) # magic
    mmf.sum <- colSums(mmf[select.rows, ]) # sum values column-wise for rows that have at least three zeros in z
    mmf[select.rows,] <- NA # now that we have a sum by columns, we turn those numbers into NAs...
    mmf[select.rows[1], ] <- mmf.sum # ... and insert summed result into the first NA row       
}

# remove any left over NA rows
mmf <- mmf[complete.cases(mmf),]
0 голосов
/ 02 июля 2011

DATA

ммф <- чтение 0 0 6 5 5 0 40 2 0 4 0 0 10 0 1 0 0 2 11 7 0 0 4 0 0 0 0 0 0 0 0 0 2 18 0 4 "), заголовок = ИСТИНА) </p>

код

agg_n <- function(dat=mmf,coln="z",n=3){
    agg <- function(.x) {
        # Sum values if first n=3 records in column coln="z" are 0 
        if(all(.x[[coln]][seq(n)] == 0)) {
            y <- rbind(colSums(.x[seq(n),]),.x[-1*seq(n),])
        } else y <- .x
        return(y)
    }
    # Groups of records starting with 0 in column coln="z"
    G <- cumsum(diff(c(0L,dat[[coln]] == 0))==1)
    new_dat <- do.call(rbind,lapply(split(dat,G),agg))
    return(new_dat)
}

OUTPUT

> agg_n()
      x  y z
0     0  0 6
1.1  49  7 0
1.5  10  0 1
1.6   0  0 2
2.1  11 11 0
2.10  0  0 0
2.11  0  0 2
2.12 18  0 4
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...