Welteninsel
Welteninsel

Reputation: 39

Calculate mean based on first part of row.name() in R

I have a data frame that looks likes this:

structure(list(value1 = c(1, 2, 3, 4, 5), value2 = c(1, 2, 2, 
2, 2), value3 = c(1, 1, 2, 3, 4)), class = "data.frame", row.names = c("apple1", 
"apple2", "orange1", "orange2", "plum"))
value1 value2 value3
apple1 1 1 1
apple2 2 2 1
orange1 3 2 2
orange2 4 2 3
plum 5 2 4

now I want to run the mean function on every column based on the first part of the row names (for example I want to calculate the mean of value1 of the apple group independently from their apple number.) I figured out that something like this works:

 y<-x[grep("apple",row.names(x)),]
    mean(y$value1)    
    mean(y$value2)
    mean(y$vvalue3)
 y<-x[grep("orange",row.names(x)),]
    mean(y$value1)    
    mean(y$value2)
    mean(y$value2) 
 y<-x[grep("plum",row.names(x)),]
    mean(y$value1)    
    mean(y$value2)
    mean(y$value2) 

but for a bigger dataset, this is going to take ages, so I was wondering if there is a more efficient way to subset the data based on the first part of the row name and calculating the mean afterward.

Upvotes: 1

Views: 287

Answers (1)

LMc
LMc

Reputation: 18662

Using tidyverse:

library(tidyverse)

df %>% 
  tibble::rownames_to_column("row") %>% 
  dplyr::mutate(row = str_remove(row, "\\d+")) %>% 
  dplyr::group_by(row) %>% 
  dplyr::summarize(across(where(is.numeric), ~ mean(.), .groups = "drop"))

In base R you could do:

df$row <- gsub("\\d+", "", rownames(df))
data.frame(do.call(cbind, lapply(df[,1:3], function(x) by(x, df$row, mean))))

Output

  row    value1 value2 value3
* <chr>   <dbl>  <dbl>  <dbl>
1 apple     1.5    1.5    1  
2 orange    3.5    2      2.5
3 plum      5      2      4  

Data

df <- structure(list(value1 = 1:5, value2 = c(1, 2, 2, 2, 2), value3 = c(1, 
1, 2, 3, 4)), class = "data.frame", row.names = c("apple1", "apple2", 
"orange1", "orange2", "plum"))

Upvotes: 1

Related Questions