Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Averaging over continuous blocks

Tags:

r

I have a data like this:

f  x 
A 1.1
A 2.2
A 3.3
B 3.5
B 3.7
B 3.9
B 4.1
B 4.5
A 5.1
A 5.2
C 5.4
C 5.5
C 6.1
B 6.2
B 6.3

I would like to average x over continuous blocks of f, to get this, similar to tapply(...,mean), but aware of the fact that it shouldn't mix separated blocks and in original order:

f  x
A 2.2
B 3.94
A 5.15 
C 5.67
B 6.25
like image 969
mbq Avatar asked Mar 30 '11 10:03

mbq


1 Answers

Here's one way:

## reproducible code for example
dat <- read.table(foo <- textConnection("f  x 
A 1.1
A 2.2
A 3.3
B 3.5
B 3.7
B 3.9
B 4.1
B 4.5
A 5.1
A 5.2
C 5.4
C 5.5
C 6.1
B 6.2
B 6.3
"), header = TRUE)
close(foo)

We use rle() to compute the run lengths of f and the create a new factor fac that indexes the changes, for want of a better word, in f. We then aggregate on f and fac:

lens <- with(dat, rle(as.character(f)))
dat$fac <- with(lens, factor(rep(seq_along(lengths), times = lengths)))
aggregate(x ~ f + fac, data = dat, FUN = mean)

Giving:

> aggregate(x ~ f + fac, data = dat, FUN = mean)
  f fac        x
1 A   1 2.200000
2 B   2 3.940000
3 A   3 5.150000
4 C   4 5.666667
5 B   5 6.250000

We can easily drop the second column fac in the result if that is undesirable:

> aggregate(x ~ f + fac, data = dat, FUN = mean)[,-2]
  f        x
1 A 2.200000
2 B 3.940000
3 A 5.150000
4 C 5.666667
5 B 6.250000
like image 167
Gavin Simpson Avatar answered Sep 28 '22 08:09

Gavin Simpson