Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I create a list of classes including zero-counts from data?

Tags:

r

dplyr

Given some random data like x = 10.08506, 10.32809, ..., how can I create a classed list in an efficient way? The result (see reproducible example below) should look like

classes         n
(10,10.1]       3
(10.1,10.2]     1
(10.2,10.3]     0
(10.3,10.4]     2
(10.4,10.5]     3
(10.5,10.6]     0
(10.6,10.7]     0
(10.7,10.8]     1

Here's a reproducible example which shows the easiest way up to now: Can I get rid of the data.frame df and full_join? Maybe, I can also get rid of br, h?

library(dplyr)
set.seed(1)
number_of_observations <- 10
nbr <- 10

x <- rnorm(n = number_of_observations, mean = 10.273, sd = 0.3)
br <- seq(from = ceiling(min(nbr*x)-1)/nbr, 
          to = floor(max(nbr*x)+1)/nbr, by = 1/nbr)
h <- hist(x, breaks = br)

df <- tibble(
  classes = h$mids)
df <- df %>% 
  mutate(classes = cut(classes, breaks = br)) %>%
  group_by(classes) %>%
  mutate(n = n()) %>%
  ungroup() %>%
  mutate(freq = n / sum(n)) %>%
  arrange(classes)

df2 <- tibble(
  classes = x)
df2 <- df2 %>% 
  mutate(classes = cut(classes, breaks = br)) %>%
  group_by(classes) %>%
  mutate(n = n()) %>%
  ungroup() %>%
  mutate(freq = n / sum(n)) %>%
  arrange(classes) %>%
  distinct()

df <- df %>% full_join(df2, by = "classes")
df$n.y[is.na(df$n.y)] <- 0

result <- df[, c("classes", "n.y")]
colnames(result) <- c("classes", "n")
result
like image 244
Christoph Avatar asked Dec 07 '22 10:12

Christoph


2 Answers

You can do this in a one-liner using seq, cut, table, and as.data.frame:

setNames(as.data.frame(table(cut(x, seq(10, 10.8, 0.1)))), c("classes", "n"))
#>       classes n
#> 1   (10,10.1] 3
#> 2 (10.1,10.2] 1
#> 3 (10.2,10.3] 0
#> 4 (10.3,10.4] 2
#> 5 (10.4,10.5] 3
#> 6 (10.5,10.6] 0
#> 7 (10.6,10.7] 0
#> 8 (10.7,10.8] 1

like image 74
Allan Cameron Avatar answered Feb 02 '23 00:02

Allan Cameron


The approach of cut + table by @Allan Cameron is efficient. Here is another option via hist

> list2DF(hist(x,breaks = seq(10, 10.8, 0.1), plot = FALSE))
  breaks counts density  mids xname equidist
1   10.0      3       3 10.05     x     TRUE
2   10.1      1       1 10.15     x     TRUE
3   10.2      0       0 10.25     x     TRUE
4   10.3      2       2 10.35     x     TRUE
5   10.4      3       3 10.45     x     TRUE
6   10.5      0       0 10.55     x     TRUE
7   10.6      0       0 10.65     x     TRUE
8   10.7      1       1 10.75     x     TRUE
9   10.8      3       3 10.05     x     TRUE
like image 25
ThomasIsCoding Avatar answered Feb 01 '23 23:02

ThomasIsCoding