Małżeńskie korelacje

Diagnoza Społeczna to cykl badań, który zakończono niemal dziesięć lat temu, jednak publicznie udostępnione dane z przeprowadzonych w ramach Diagnozy ankiet wciąż pozwalają odkrywać ciekawe zależności i wzorce.

Przykładem takich zależności, które można przedstawić na przykładzie zbiorów danych zgromadzonych w ramach diagnozy są korelacje pomiędzy małżonkami. Sprawdźmy, jak wygląda korelacja miedzy żoną i mężem, jeżeli chodzi o wiek, wzrost, masę ciała i dochód.

Dane z ankiet można odnaleźć na githubie, prof. Przemysław Biecek przygotował pliki, które można od razu wciągnąć do R. Poniższe polecenie wciąga ramkę danych o nazwie osoby:

load(url("https://github.com/pbiecek/Diagnoza/raw/master/data/osoby.rda"))

Z danych wybieramy tylko te zmienne, które są nam potrzebne: identyfikatory, płeć, wiek, wzrost, masa ciała, dochód oraz wagi ankietowe. Z opisu danych przygotowanego przez prof. Biecka wiem, że zmienne dotyczące roku 2015 mają nazwy zaczynające się od litery h.

extract <- osoby[, c('numer_gd', 'numer_osoby', 'hc5', 'hc6', 'hc10', 
                     'hp65', 'hp52', 'hp53', 'waga_2015_ind', 'wiek2015')]
names(extract) <- c('household_id', 'person_id', 'family_no', 'family_role', 
                    'sex', 'income', 'height', 'weight', 'survey_weight', 'age')

Ponieważ źródłowa ramka danych obejmuje wszystkie lata badania, wiele rekordów zawiera wartości brakujące (NA). Po serii prób i inspekcji danych uznałem, że najskuteczniejsze będzie następujące podejście: tymczasowo zastąpić NA wartością -1 w kolumnie dochodu (ponieważ nie chcemy usuwać obserwacji z brakującym dochodem, np. emerytów), następnie usunąć wiersze zawierające inne braki danych, a na końcu ponownie przywrócić NA w zmiennej dochód.

extract$income[is.na(extract$income)] <- -1
extract <- na.omit(extract)
extract$income[extract$income == -1] <- NA

Następnie tworzymy identyfikator rodziny (family_id), aby połączyć dane o mężu i żonie.

extract$family_id <- paste(extract$household_id, extract$family_no)

Z danych wybieramy osobno mężów i żony.

extract_husband <- extract[(extract$family_role == 1 | extract$family_role == 2) &  extract$sex == 1, 
                           c('family_id', 'income', 'height', 'weight', 'survey_weight', 'age')]
names(extract_husband) <- c('family_id', 'husband_income', 'husband_height', 'husband_weight', 
                            'husband_survey_weight', 'husband_age')

extract_wife <- extract[(extract$family_role == 1 | extract$family_role == 2) & extract$sex == 2, 
                        c('family_id', 'income', 'height', 'weight', 'survey_weight', 'age')]
names(extract_wife) <- c('family_id', 'wife_income', 'wife_height', 'wife_weight', 
                         'wife_survey_weight', 'wife_age')

Po połączeniu danych o małżonkach otrzymujemy ramkę e, w której każdy wiersz odpowiada jednej parze.

e <- merge(extract_husband, extract_wife)

Autorzy badania dostarczyli wagi ankietowe, dzięki którym można skorygować otrzymane wyniki, żeby uwzględnić fakt, że nie każda osoba miała jednakowe szanse na znalezienie się w próbie. Przyjmuję, że waga ankietowa dla pary to średnia z wag ankietowych męża i żony. Przekształcam wagi tak, żeby ich suma była równa liczbie małżeństw w próbie.

e$avg_survey_weight <- (e$husband_survey_weight + e$wife_survey_weight)/2
e$avg_survey_weight <- e$avg_survey_weight / mean(e$avg_survey_weight)
head(e)
##   family_id husband_income husband_height husband_weight husband_survey_weight
## 1  100004 1           4000            176             79             0.5515697
## 2  100009 1           2400            182             90             0.5929627
## 3  100014 2           2800            181            120             1.4742120
## 4  100015 1           1800            170             87             0.9607670
## 5  100018 1           3000            175             82             0.7655140
## 6  100021 1           1400            185             92             0.3082680
##   husband_age wife_income wife_height wife_weight wife_survey_weight wife_age
## 1          66        1000         157          51          0.4846472       58
## 2          42        1400         168          57          0.6888809       39
## 3          43        1000         172          80          1.4206220       45
## 4          64        1300         160          68          0.8562090       62
## 5          47        2000         159          75          0.7330340       45
## 6          47        1000         170         104          0.2951890       47
##   avg_survey_weight
## 1         0.5390513
## 2         0.6668290
## 3         1.5059241
## 4         0.9452107
## 5         0.7795610
## 6         0.3139249

Zbadajmy cztery wymiary podobieństwa par:

  • wzrost,

  • masa ciała,

  • wiek,

  • dochód.

Dla każdego obliczymy współczynnik korelacji Pearsona z uwzględnieniem wag ankietowych.

cor_height <- cov.wt(data.frame(e$husband_height, e$wife_height),
                     wt = e$avg_survey_weight, cor = TRUE)$cor[2,1]

library(ggplot2)

min_val <- min(e$husband_height, e$wife_height, na.rm = TRUE)
max_val <- max(e$husband_height, e$wife_height, na.rm = TRUE)

G1 <- ggplot(e, aes(x = husband_height, y = wife_height)) +
  geom_jitter(alpha = 0.2, width = .5, height = .5, shape = 16) +
  geom_abline(intercept = 0, slope = 1, linetype = "dashed", color = "grey50") +
  scale_x_continuous(limits = c(min_val, max_val)) +
  scale_y_continuous(limits = c(min_val, max_val)) +
  labs(
    x = "wzrost męża",
    y = "wzrost żony",
    title = paste0("WZROST małżonków \n", "Wsp. korelacji = ", round(cor_height, 3))
  ) +
  theme_minimal()
G1
cor_weight <- cov.wt(data.frame(e$husband_weight, e$wife_weight),
                     wt = e$avg_survey_weight, cor = TRUE)$cor[2,1]

library(ggplot2)

min_val <- min(e$husband_weight, e$wife_weight, na.rm = TRUE)
max_val <- max(e$husband_weight, e$wife_weight, na.rm = TRUE)

G2 <- ggplot(e, aes(x = husband_weight, y = wife_weight)) +
  geom_jitter(alpha = 0.2, width = .5, height = .5, shape = 16) +
  geom_abline(intercept = 0, slope = 1, linetype = "dashed", color = "grey50") +
  scale_x_continuous(limits = c(min_val, max_val)) +
  scale_y_continuous(limits = c(min_val, max_val)) +
  labs(
    x = "masa ciała męża",
    y = "masa ciała żony",
    title = paste0("MASA CIAŁA małżonków \n", "Wsp. korelacji = ", round(cor_weight, 3))
  ) +
  theme_minimal()
G2
cor_age <- cov.wt(data.frame(e$husband_age, e$wife_age),
                     wt = e$avg_survey_weight, cor = TRUE)$cor[2,1]

library(ggplot2)

min_val <- min(e$husband_age, e$wife_age, na.rm = TRUE)
max_val <- max(e$husband_age, e$wife_age, na.rm = TRUE)

G3 <- ggplot(e, aes(x = husband_age, y = wife_age)) +
  geom_jitter(alpha = 0.2, width = .5, height = .5, shape = 16) +
  geom_abline(intercept = 0, slope = 1, linetype = "dashed", color = "grey50") +
  scale_x_continuous(limits = c(min_val, max_val)) +
  scale_y_continuous(limits = c(min_val, max_val)) +
  labs(
    x = "wiek męża",
    y = "wiek żony",
    title = paste0("WIEK małżonków \n", "Wsp. korelacji = ", round(cor_age, 3))
  ) +
  theme_minimal()
G3
e2 <- na.omit(e[, c('husband_income', 'wife_income', 'avg_survey_weight')])

cor_income <- cov.wt(data.frame(e2$husband_income, e2$wife_income), 
                     wt = e2$avg_survey_weight, cor = TRUE)$cor[2,1]

library(ggplot2)

min_val <- min(e2$husband_income, e2$wife_income, na.rm = TRUE)
max_val <- max(e2$husband_income, e2$wife_income, na.rm = TRUE)

G4 <- ggplot(e2, aes(x = husband_income, y = wife_income)) +
  geom_jitter(alpha = 0.2, width = .01, height = .01, shape = 16) +
  geom_abline(intercept = 0, slope = 1, linetype = "dashed", color = "grey50") +
  scale_x_log10(limits = c(min_val, max_val)) +
  scale_y_log10(limits = c(min_val, max_val)) +
  labs(
    x = "dochód męża (skala logarytmiczna)",
    y = "dochód żony (skala logarytmiczna)",
    title = paste0("DOCHÓD małżonków \n", "Wsp. korelacji = ", round(cor_income, 3))
  ) +
  theme_minimal()
G4
Błażej Kochański
Błażej Kochański
ekspert ds. ryzyka bankowego, naukowiec, menedżer i konsultant