How to use group_by to compare averages between groups

I am using this hiphop data set (). I am attempting to compare the averages values of each music type (into, vocal, classical, folk, rock, country, pop, alternative, hiphop, and unclassifiable) between males and females. I am grouping by the sex variable to get the averages for each level and each variable using the following code.

music_diff <- hiphop %>% select(subj, sex, age, ethnic, ethnic_binary, intl:unclassifiable)
sex_music_diff <- music_diff %>% group_by(sex) %>% summarize(avg_intl=mean(intl), avg_vocal=mean(vocal), avg_classical =mean(classical), avg_folk=mean(folk), avg_rock=mean(rock), avg_country =mean(country), avg_pop=mean(pop), avg_alt = mean(alternative), avg_hiphop=mean(hiphop), avg_unclassifiable=mean(unclassifiable), .groups="keep")

This gives me the table of averages for male and female subjects inside each group. What I want to do now is use the output it gives me to find variables that are different between males and females. In other words, I want to subtract avg_intl for males and females, avg_vocal for males and females, etc, etc, and return a list of differences for each variable. I tried:

sex_music_diff %>%
+ avg_intl$Male - avg_intl$Female

But I get an error that says "3 arguments passed to '$' which requires 2". Not sure what's a better way to go about this. Ideally it would be one step for all variable differences that would return a data frames of all the differences. Thanks in advance.

0

2 Answers

If we need to do this in %>%, subset the 'avg_int' based on a logical vector

library(dplyr)# 1.0.0
sex_music_diff %>% ungroup %>% summarise(Diff = avg_intl[sex == 'Male'] - avg_intl[sex == 'Female'])
# Diff
#1 0.3

If we want to do this for all the 'avg' variables

sex_music_diff %>% ungroup %>% summarise(across(starts_with('avg'), ~ .[sex == 'Male'] - .[sex == 'Female']))
#avg_intl avg_vocal avg_classical avg_country avg_pop avg_hiphop avg_unclassifiable
#1 0.3 -1.4 -1.2 -0.2 -0.3 -1.1 -0.2

Or using base R

with(sex_music_diff, avg_intl[sex == 'Male'] - avg_intl[sex == 'Female'])
#[1] 0.3

Or as there is only two rows, it can be done with diff

with(sex_music_diff, diff(avg_intl))
#[1] -0.3

Or for all the 'avg' variables

nm1 <- startsWith(names(sex_music_diff), 'avg')
diff(as.matrix(sex_music_diff[nm1]))
# avg_intl avg_vocal avg_classical avg_country avg_pop avg_hiphop avg_unclassifiable
#[1,] -0.3 1.4 1.2 0.2 0.3 1.1 0.2 

Based on the OP's code, the 'avg_intl' is a separate column and 'Sex' is separate. So, we cannot extract $Male or $Female as if 'avg_intl' is an object created.

data

sex_music_diff <- data.frame(sex = c('Male', 'Female'),
avg_intl = c(5.2, 4.9), avg_vocal = c(6.5, 7.9),
avg_classical = c(1.2, 2.4), avg_country = c(2.3, 2.5),
avg_pop = c(3.2, 3.5), avg_hiphop= c(2.4, 3.5),
avg_unclassifiable = c(2.2, 2.4))
7

try it this way

library(tidyverse)
music_diff %>% group_by(sex) %>% summarise(across(intl:unclassifiable, mean, na.rm = T, .names = "avg_{col}")) %>% pivot_longer(-sex) %>% pivot_wider(name, names_from = sex, values_from = value) %>% mutate(Diff = Male - Female)
# A tibble: 10 x 4 name Female Male Diff <chr> <dbl> <dbl> <dbl> 1 avg_intl 0.444 0.255 -0.190 2 avg_vocal 0.880 1.57 0.688 3 avg_classical 0.752 0.941 0.189 4 avg_folk 0.402 0.392 -0.00955 5 avg_rock 1.93 3.06 1.13 6 avg_country 0.786 0.392 -0.394 7 avg_pop 1.30 1.10 -0.201 8 avg_alternative 2.21 2.16 -0.0568 9 avg_hiphop 1.62 1.53 -0.0945
10 avg_unclassifiable 0.0598 0.0392 -0.0206 

Your Answer

Sign up or log in

Sign up using Google Sign up using Facebook Sign up using Email and Password

Post as a guest

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

You Might Also Like