# Getting aggregated share in R

I have a data set that I need to analyze in R. A simplified version of it would be like this

SessionNo.  Objects       OtherColumns
A          2               .
A          3
B          4
C          1
D          2
D          1
D          2
D          3
E          5


here each sessionno. represents one session of a broswer but due to the relation with other columns in the data it is aggregated like shown. So, Session 1 is now fragmented into two rows etc. What I need to find is the avg. number of objects downloaded per session (or any other statistics for no. of rows in each session). So, how do I count the no of objects for each session in R. Here, 5 objects in session A, 4 in session B, 8 in session D etc.

I guess one way would be to sum the whole Objects column and count the no. of unique session numbers in SessionNo. But I guess it would be more of a general solution if I could group the unique session number with the total number of objects aggregated in it? Any suggestions on how to accomplish that in R?

-

Perhaps this might help:

tapply(df$Objects, df$SessionNo., sum)

-
+1 since aggregate is an overshoot here and plyr is slow. –  mbq Nov 24 '10 at 18:15
-1 That can't possibly work unless you make the components of the data frame visible (using say with(), or refer to the explicitly via, e.g., df$Objects where df is the op's data frame. – Gavin Simpson Nov 25 '10 at 7:30 @mbq: why is aggregate() an "overshoot here"? It seems very natural as it returns for you a DF with the unique SessionNo. plus the sum for each. tapply() just gives the sums. – Gavin Simpson Nov 25 '10 at 7:32 @Gavin: You´re right, i´ve edited my post. – EDi Nov 25 '10 at 10:36 @EDi +1 following edit – Gavin Simpson Nov 25 '10 at 11:31 show 3 more comments The function that is specifically designed for this task is ave(). By default it returned the mean within a group and returns a vector of the same length as the two input arguments. It is designed to fill in columns of either means or deviations from means. If this is in a dataframe with name "tst": > tst$tmn <- with(tst, ave(Objects, SessionNo.))
> tst$devmn <- tst$Objects- with(tst, ave(Objects, SessionNo.))
> tst
SessionNo. Objects tmn devmn
1          A       2 2.5  -0.5
2          A       3 2.5   0.5
3          B       4 4.0   0.0
4          C       1 1.0   0.0
5          D       2 2.0   0.0
6          D       1 2.0  -1.0
7          D       2 2.0   0.0
8          D       3 2.0   1.0
9          E       5 5.0   0.0

-
if you are using with(), then go the whole hog and use within() here --- gets rid of more $. Your first line could be, tst <- within(tst, tmn <- ave(Objects, SessionNo.)) whilst your second line could be tst <- within(tst, devmn <- Objects - ave(Objects, SessionNo.)). Note that the second line contains two modifications as the whole thing can be inside with() or within(). – Gavin Simpson Nov 25 '10 at 7:39 add comment If I am reading your question correctly, something like the following should do it: aggregate(x$Objects,by=list(x$SessionNo.),sum) where x is the data frame containing your data. This will give you, for each unique session number, the sum of the object counts. You can of course substitute other functions (including your own) on place of the sum. - add comment I personally like using the plyr and or reshape packages for tasks like this. If you're just starting with R, I would highly recommend getting to know them well. They've solved nearly all of my data manipulation tasks. ddply(df, .(sessionNo.) function(x) data.frame( obj.count=sum(Objects) ))  OR, cast colnames(df[1:2]) <- c("variable","value") cast(df[1:2], variable ~ value, sum)  - I think the colnames line above needs to be rewritten as colnames(df)[1:2] <- c("variable","value")? – Chase Nov 30 '10 at 22:53 add comment I often use by, which is a wrapper around tapply. Result is a list with a weee different print method compared to tapply. df <- data.frame(SessionNo. = sample(x = c("A", "B", "C", "D", "E"), size = 20, replace = TRUE, prob = c(0.05, 0.1, 0.4, 0.4, 0.05)), Objects = sample(x = 1:5, size = 20, replace = TRUE)) df.out <- by(data = df$Objects, INDICES = df$SessionNo., FUN = mean, simplify = FALSE) head(df.out)$A
[1] 3

$B [1] 1$C
[1] 3.222222

$D [1] 3.833333$E
[1] 1

-
Is there a difference if i give the argument "simplify = FALSE" to tapply()? –  EDi Nov 25 '10 at 15:22
Try it, I've provided a full working example. :) You will see the difference if you use str(df.out) on both instances. –  Roman Luštrik Nov 26 '10 at 8:55