p <-with(mtcars,tapply(carb,list(cyl,vs),length)) prop.table(p,2) # by column p <- with(mtcars,tapply(carb,list(cyl,vs,gear),length)) test <- 1:8 dim(test) <- c(2,2,2) test , , 1 [,1] [,2] [1,] 1 3 [2,] 2 4 , , 2 [,1] [,2] [1,] 5 7 [2,] 6 8 # % of all values in each stratum/sub-table prop.table(test,3) # row % within each stratum/sub-table prop.table(test,c(3,1)) # column % within each stratum/sub-table prop.table(test,c(3,2)) # set one of the values to NA as an example test[7] <- NA # do the procedure nas <- is.na(test) test[nas] <- 0 result <- prop.table(test,c(3,2)) result[nas] <- NA result , , 1 [,1] [,2] [1,] 0.3333333 0.4285714 [2,] 0.6666667 0.5714286 , , 2 [,1] [,2] [1,] 0.4545455 NA [2,] 0.5454545 1 library(reshape2) tables <- acast(mtcars, cyl~vs~gear,value.var = 'carb', fun.aggregate = 'length') tables , , 3 0 1 4 0 1 6 0 2 8 12 0 , , 4 0 1 4 0 8 6 2 2 8 0 0 , , 5 0 1 4 1 1 6 1 0 8 2 0 prop.table(tables, 2:3) , , 3 0 1 4 0 0.3333333 6 0 0.6666667 8 1 0.0000000 , , 4 0 1 4 0 0.8 6 1 0.2 8 0 0.0 , , 5 0 1 4 0.25 1 6 0.25 0 8 0.50 0 with(mtcars,table(cyl, vs ,gear)) , , gear = 3 vs cyl 0 1 4 0 1 6 0 2 8 12 0 , , gear = 4 vs cyl 0 1 4 0 8 6 2 2 8 0 0 , , gear = 5 vs cyl 0 1 4 1 1 6 1 0 8 2 0