How to do a for loop of a count() function for a datatable in R?

Viewed 68

I need to count the number of occurrences of specific values in each column, and then do a for loop for that to run that count() function for the entire dataframe (consisting of several thousand columns).

For instance, if I have a column consisting of: [0,0,0,1,1,0,0,0,0,0,0,0]. I want it to count the column and return for me the information of: 1 -> 2 counts 0 -> 10 counts The dataframe that I have consists entirely of only 0s and 1s. I just need to count how many of them are in each column, but that dataframe has over a few thousand columns.

Currently, my for loop code doesnt work, it seems to only register the first column and keep printing that same first column result over and over again. Thanks everyone!!

    s <- 0
yes_filt_high_mutation <- data.frame(); 
for(c in colnames(high_mutations)[2:ncol(high_mutations)]){   #high_mutations = my dataframe
  mutation_results = high_mutations %>% count(high_mutations$c);   #Count the # of 0s and 1s in each column
  print(c) 
  print(mutation_results) 
  s <- s + 1  
  add_column <- c(c,mutation_results[1,2],mutation_results[2,2])   
  yes_filt_high_mutation <- rbind(data.frame(yes_filt_high_mutation), add_column)  
}
names(yes_filt_high_mutation)[1] <- "Samples"   
names(yes_filt_high_mutation)[2] <- "Number of 0's"
names(yes_filt_high_mutation)[3] <- "Number of 1's"

I want my result to be something like this, for each loop result: So essentially tell me that there are 134 counts of 0 and 2 counts of 1 in Column 1.

  high_mutations$Column1   n
1                      0 134
2                      1   2
1 Answers

I would suggest that you reflect on the desired final format. If your intention is get a count of observations within a column you can obtain that by using common verbs available in tidyverse.

library(tidyverse)
select(mtcars, cyl, vs, gear) %>%
  pivot_longer(cols = everything()) %>%
  group_by(name, value) %>%
  summarise(ndist = n())
#> `summarise()` has grouped output by 'name'. You can override using the
#> `.groups` argument.
#> # A tibble: 8 × 3
#> # Groups:   name [3]
#>   name  value ndist
#>   <chr> <dbl> <int>
#> 1 cyl       4    11
#> 2 cyl       6     7
#> 3 cyl       8    14
#> 4 gear      3    15
#> 5 gear      4    12
#> 6 gear      5     5
#> 7 vs        0    18
#> 8 vs        1    14

Created on 2022-04-16 by the reprex package (v2.0.1)

Explanation

  1. For sake of simplicity a set of columns is reduced to only include vs, cyl and gear via the select verb.
  2. Data is transformed to a long format to make grouping easier via pivot_longer available through tidyr
  3. The key element is counting occurrences of each combination, if I understood your request, this is your goal. So in this case for column cyl we get 11 instances of value 4, 7 instances of value 6 and so on

Optional

  1. You can transform that data into a wide format using pivot_wider but I wouldn't rush that as nicely formatted long data is frequently easier to work with

Wider remarks

  • Looping over columns in a data frame is generally not advisable practice. R offers a number of optimised, robust and mature approaches to achieve similar objectives. apply functions available in base R or across verb offered via tidyverse are a good starting points
  • You may wish to reflect on refining your requirements. As it was observed in the comments, are you in effect looking for an output similar to table(mtcars$cyl) plus some additional embellishments?

Alternative solution

If you are not too fussed about the output format you could also leverage map.

library(tidyverse)
select(mtcars, cyl, vs, gear) %>%
  map(~ table(.x))
#> $cyl
#> .x
#>  4  6  8 
#> 11  7 14 
#> 
#> $vs
#> .x
#>  0  1 
#> 18 14 
#> 
#> $gear
#> .x
#>  3  4  5 
#> 15 12  5

Created on 2022-04-16 by the reprex package (v2.0.1)

You will arrive at identical result but as a list, you may wish to pack those in a data frame but if you will intend to do that staying with group_by is probably a more straightforward.

Related