[R] creating a quantile variable based on subsets of a dataframe

David Winsemius dwinsemius at comcast.net
Tue Aug 6 19:29:44 CEST 2013


On Aug 6, 2013, at 10:17 AM, Gavin Rudge wrote:

> #some sample data:
> library(Hmisc)
> set.seed(33)
> df<-data.frame(x=(sample(letters[1:10],1000,replace=TRUE)),y=rnorm(1000,mean=20,sd=15))
> 
> x is a category from a to J, say a geographical area, into which an observation y falls, y being a score.  Now if I want to put my score into quantiles (quintiles in this case) across the whole population of observations and then make a quintile variable I do the following:
> 
> #make a quintile variable
> df<- within(df,z<-as.integer(cut2(y,quantile(y,probs=seq(0,1,0.2)))))
> 
> I'm using cut2 here as I want the extremes of my ranges to be included in the upper and lower bins.
> 
> So far so good, but I would also like another variable to indicate the quintile of the score within the areas indicated by the x variable, so all of the scores where x=a, binned into quintiles for area a, the same for scores in areas b, c and so on.
> 
> I see that I could put my quintile variable code into a function and then split my data frame by x, apply the function in each of the ten groups and stitch the whole thing back together again (not sure I could write it though), but is there a much simpler solution?
> 

Generally questions involving the distribution of a single variate grouped within categories where the desired result is as long as the original variate are well handled with th `ave` function:

> df$c2.grp <- ave(df$y, df$x, FUN=function(z) cut2(z, quantile(z,probs=seq(0,1,0.2)) ) )
> str(df)
'data.frame':	1000 obs. of  3 variables:
 $ x     : Factor w/ 10 levels "a","b","c","d",..: 5 4 5 10 9 6 5 4 1 2 ...
 $ y     : num  15 45.3 29.9 45.2 23.3 ...
 $ c2.grp: num  2 5 4 5 3 4 2 4 3 2 ...

I was a bit surprised that the resulting column in df was numeric rather than factor, but I suspect it was the fact that the levels of the intra-groups splits could not be reconciled. You didn't apparently consider that issue in your problem specification. The result could be "cleaned up" with:

> df$c2.grp <- factor(df$c2.grp, labels=paste0("Q", 1:5) )
> with(df, table(x, c2.grp))
   c2.grp
x   Q1 Q2 Q3 Q4 Q5
  a 22 23 22 22 22
  b 19 19 18 19 19
  c 21 20 20 20 21
  d 20 19 19 19 20
  e 19 20 21 20 20
  f 21 21 21 21 22
  g 21 21 21 21 22
  h 19 19 19 19 19
  i 18 18 17 18 18
  j 20 20 19 20 20
-- 

David Winsemius
Alameda, CA, USA



More information about the R-help mailing list