5

Given a data_frame df <- data_frame(X = c('A', 'A', 'B', 'B', 'B'), Y = c('M', 'N', 'M', 'M', 'N')), I need to come up with a data_frame that tells us that 50% of A's are M, 50% of A's are N, 67% of B's are M, and 33% of B's are N.

I have a little routine that I use to do it, but it seems horrible.

library(tidyverse)
df <- data_frame(X = c('A', 'A', 'B', 'B', 'B'), Y = c('M', 'N', 'M', 'M', 'N')) 
# here we go...
df %>% 
  group_by(X) %>% 
  mutate(n_X = n()) %>% 
  group_by(X, Y) %>% 
  summarise(PERCENT = n() / first(n_X))

which outputs,

Source: local data frame [4 x 3]
Groups: X [?]

      X     Y   PERCENT
  <chr> <chr>     <dbl>
1     A     M 0.5000000
2     A     N 0.5000000
3     B     M 0.6666667
4     B     N 0.3333333

Is there not a better way to do this? Surely I'm missing something.

crf
  • 1,810
  • 3
  • 15
  • 23

3 Answers3

6

You can use prop.table:

df %>% 
  group_by(X, Y) %>%
  count() %>%
  mutate(PERCENT = prop.table(n))

The result:

      X     Y     n   PERCENT
  <chr> <chr> <int>     <dbl>
1     A     M     1 0.5000000
2     A     N     1 0.5000000
3     B     M     2 0.6666667
4     B     N     1 0.3333333
Sven Hohenstein
  • 80,497
  • 17
  • 145
  • 168
4

We can try in base R using table and rowSums

new_df <- table(df$X, df$Y)
new_df/rowSums(new_df)

#          M         N
#  A 0.5000000 0.5000000
#  B 0.6666667 0.3333333
Ronak Shah
  • 377,200
  • 20
  • 156
  • 213
2

May be this:

with dplyr

library(dplyr)
df %>%  count(X, Y) %>%
  mutate(prop = n / sum(n))

with base R

tbl <- xtabs(~X+Y, df)
as.data.frame(tbl/rowSums(tbl), responseName = "prop")

with data.table

library(data.table)
DT <- data.table(df)[, .N, by = .(X,Y)]
setDT(DT)[, prop := N/sum(N), by = 'X']
DT

#   X Y N      prop
#1: A M 1 0.5000000
#2: A N 1 0.5000000
#3: B M 2 0.6666667
#4: B N 1 0.3333333
Sandipan Dey
  • 21,482
  • 2
  • 51
  • 63