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$FemaleBut 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.
02 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.3If 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.2Or using base R
with(sex_music_diff, avg_intl[sex == 'Male'] - avg_intl[sex == 'Female'])
#[1] 0.3Or as there is only two rows, it can be done with diff
with(sex_music_diff, diff(avg_intl))
#[1] -0.3Or 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