Loading the data from the MASS package

# Getting the data
cats <- MASS::cats

Examining the data:

Let’s start by looking at the data using slice_sample(data). Why slice_sample() instead of another function like head()? It’s not uncommon for the data sets available in R or online to have the data sorted in some way, so the first 6 rows might all be similar. In fact, the cats are sorted by sex, then Bwt, then Hwt.

# first six sorted rows
head(cats)
##   Sex Bwt Hwt
## 1   F 2.0 7.0
## 2   F 2.0 7.4
## 3   F 2.0 9.5
## 4   F 2.1 7.2
## 5   F 2.1 7.3
## 6   F 2.1 7.6
# six random rows
slice_sample(cats, n = 6)
##   Sex Bwt  Hwt
## 1   F 2.1  7.6
## 2   F 2.9 10.1
## 3   M 2.5 11.0
## 4   M 3.6 15.0
## 5   M 2.9 11.8
## 6   M 3.2 12.3

We can use summary(data) to summarize each column individually, including see the number of missing values by column (if any).

# Summary of each column
summary(cats)
##  Sex         Bwt             Hwt       
##  F:47   Min.   :2.000   Min.   : 6.30  
##  M:97   1st Qu.:2.300   1st Qu.: 8.95  
##         Median :2.700   Median :10.10  
##         Mean   :2.724   Mean   :10.63  
##         3rd Qu.:3.025   3rd Qu.:12.12  
##         Max.   :3.900   Max.   :20.50

There are 47 female cats (‘F’) and 97 male cats (‘M’). summary() also gives the mean and 5 number summary for each numeric (quantitative) column.

A better way is to visualize the data with either a histogram or density plot. I prefer density plots since there isn’t a need to specify the bin width or bin number, but either one works:

# Stacking both Bwt and Hwt into one column called cats_long
cats_long <- 
  cats |>
  dplyr::select(
    sex = Sex,
    `body weight (kg)` = Bwt,
    `heart weight (g)` = Hwt
  ) |>
  # adding an id column
  mutate(
    .before = 1,
    cat_id = row_number()
  ) |>
  pivot_longer(
    cols = c(-sex, -cat_id),
    names_to = 'feature',
    values_to = 'weight'
  )

# Creating the density plots
  ggplot(
    data = cats_long,
    mapping = aes(x = weight)
  ) +
  geom_density(
    fill = 'orange'
  ) + 
  facet_wrap(
    facets = vars(feature),
    nrow = 2,
    scales = 'free'
  ) + 
  labs(
    title = 'Body and heart weight of 144 cats',
    x = NULL
  ) + 
  theme_bw() +
  # Making the density plot 'sit' on the x-axis
  scale_y_continuous(
    expand = c(0, 0, 0.05, 0)
  )

Both heart and body weight of the cats are unimodal and right skewed. Body weight has a min of 2 kg, max of about 4 kg, and a mode of around 2.3 kgs

Heart weight has a min of about 6 g, max of about 10 g, and a mode of 10 g.

Summary stats

When using probability distributions, we often need to estimate the parameters. For numeric data, common probability distributions used have a mean parameter, \(\mu\), and a variance parameter, \(\sigma^2\), or standard deviation, \(\sigma\).

We estimate the parameters from the data using sample statistics:

\[\hat{\mu} = \bar{y} = \frac{1}{n}\sum_{i = 1}^n y_i\]

\[\hat{\sigma}^2 = s^2 = \frac{1}{n-1}\sum_{i = 1}^n (y_i-\bar{y})^2\]

\[\hat{\sigma} = s = \sqrt{\frac{1}{n-1}\sum_{i = 1}^n (y_i-\bar{y})^2}\]

To speed up the calculating the mean and standard deviation, we’ll use the cats_long data set created in the previous code chunk:

slice_sample(cats_long, n = 10)
## # A tibble: 10 × 4
##    cat_id sex   feature          weight
##     <int> <fct> <chr>             <dbl>
##  1    135 M     heart weight (g)   17.2
##  2     34 F     heart weight (g)   10.2
##  3      9 F     heart weight (g)    8.3
##  4     56 M     body weight (kg)    2.2
##  5     24 F     body weight (kg)    2.3
##  6     45 F     heart weight (g)   10.1
##  7     30 F     body weight (kg)    2.3
##  8    132 M     body weight (kg)    3.5
##  9     84 M     body weight (kg)    2.7
## 10    114 M     heart weight (g)   14.3

Now we’ll calculate the parameter estimates using the summarize() function in the dplyr package:

cats_long |>
  summarize(
    .by = feature,            # separate parameters for each RV
    avg = sum(weight) / n(),  # n() counts the number of rows used in the subset
    avg2 = mean(weight),      # or we can use the mean() function
    
    # Calculating the variability parameters
    variance = (sum((weight - mean(weight))^2)/(n() - 1)),
    variance2 = var(weight),
    stdev = sqrt(variance),
    stdev2 = sd(weight)
  )
## # A tibble: 2 × 7
##   feature            avg  avg2 variance variance2 stdev stdev2
##   <chr>            <dbl> <dbl>    <dbl>     <dbl> <dbl>  <dbl>
## 1 body weight (kg)  2.72  2.72    0.236     0.236 0.485  0.485
## 2 heart weight (g) 10.6  10.6     5.93      5.93  2.43   2.43

We can estimate the covariance and correlation:

\[\widehat{cov}(X,Y) = \hat{\sigma}_{xy} = \frac{1}{n-1} \sum_{i = 1}^n(x_i - \bar{x})(y_i -\bar{y}) \]

\[r = \frac{\hat{\sigma}_{xy}}{s_x s_y} = \frac{\sum_{i = 1}^n(x_i - \bar{x})(y_i -\bar{y})}{\sqrt{\sum_{i = 1}^n(x_i - \bar{x})^2}\sqrt{\sum_{i = 1}^n(y_i - \bar{y})^2}}\]

cats |>
  summarize(
    # Calculating the covariance by "hand" and using the R function
    covariance  = sum((Bwt - mean(Bwt)) * (Hwt - mean(Hwt)))/(n() - 1),
    covariance2 = cov(Bwt, Hwt),
    
    # Calculating the correlation 'by hand' and using the R function
    correlation  = sum((Bwt - mean(Bwt)) * (Hwt - mean(Hwt))) / 
                   sqrt(sum((Bwt - mean(Bwt))^2) * sum((Hwt - mean(Hwt))^2)),
    correlation2 = covariance / (sd(Bwt) * sd(Hwt)),
    correlation3 = cor(Bwt, Hwt)
  )
##   covariance covariance2 correlation correlation2 correlation3
## 1  0.9501127   0.9501127   0.8041274    0.8041274    0.8041274
LS0tDQp0aXRsZTogJ0ludHJvZHVjdGlvbjogUmFuZG9tIFZhcmlhYmxlcyAtIENhdHMgZXhhbXBsZScNCmF1dGhvcjogIkNoYXB0ZXIgMSINCmRhdGU6ICJTVEEgNDIxMCINCm91dHB1dDoNCiAgaHRtbF9kb2N1bWVudDoNCiAgICBmaWdfd2lkdGg6IDYNCiAgICBmaWdfaGVpZ2h0OiA2DQogICAgZmlnX2NhcHRpb246IHllcw0KICAgIG51bWJlcl9zZWN0aW9uczogbm8NCiAgICBjb2RlX2ZvbGRpbmc6IGhpZGUNCiAgICBjb2RlX2Rvd25sb2FkOiB5ZXMNCiAgICBzbW9vdGhfc2Nyb2xsOiB5ZXMNCiAgICB0aGVtZTogbHVtZW4NCi0tLQ0KDQpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0NCmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gVFJVRSwNCiAgICAgICAgICAgICAgICAgICAgICBmaWcuYWxpZ24gPSAnY2VudGVyJykNCnNldC5zZWVkKDQyMTApDQojIExvYWRpbmcgcGFja2FnZXMNCmxpYnJhcnkodGlkeXZlcnNlKQ0KYGBgDQoNCkxvYWRpbmcgdGhlIGRhdGEgZnJvbSB0aGUgYE1BU1NgIHBhY2thZ2UNCg0KYGBge3J9DQojIEdldHRpbmcgdGhlIGRhdGENCmNhdHMgPC0gTUFTUzo6Y2F0cw0KYGBgDQoNCiMjIEV4YW1pbmluZyB0aGUgZGF0YToNCg0KTGV0J3Mgc3RhcnQgYnkgbG9va2luZyBhdCB0aGUgZGF0YSB1c2luZyBgc2xpY2Vfc2FtcGxlKGRhdGEpYC4gV2h5IGBzbGljZV9zYW1wbGUoKWAgaW5zdGVhZCBvZiBhbm90aGVyIGZ1bmN0aW9uIGxpa2UgYGhlYWQoKWA/IEl0J3Mgbm90IHVuY29tbW9uIGZvciB0aGUgZGF0YSBzZXRzIGF2YWlsYWJsZSBpbiBSIG9yIG9ubGluZSB0byBoYXZlIHRoZSBkYXRhIHNvcnRlZCBpbiBzb21lIHdheSwgc28gdGhlIGZpcnN0IDYgcm93cyBtaWdodCBhbGwgYmUgc2ltaWxhci4gSW4gZmFjdCwgdGhlIGNhdHMgYXJlIHNvcnRlZCBieSBgc2V4YCwgdGhlbiBgQnd0YCwgdGhlbiBgSHd0YC4NCg0KYGBge3J9DQojIGZpcnN0IHNpeCBzb3J0ZWQgcm93cw0KaGVhZChjYXRzKQ0KDQojIHNpeCByYW5kb20gcm93cw0Kc2xpY2Vfc2FtcGxlKGNhdHMsIG4gPSA2KQ0KDQpgYGANCg0KV2UgY2FuIHVzZSBgc3VtbWFyeShkYXRhKWAgdG8gc3VtbWFyaXplIGVhY2ggY29sdW1uIGluZGl2aWR1YWxseSwgaW5jbHVkaW5nIHNlZSB0aGUgbnVtYmVyIG9mIG1pc3NpbmcgdmFsdWVzIGJ5IGNvbHVtbiAoaWYgYW55KS4NCg0KYGBge3J9DQojIFN1bW1hcnkgb2YgZWFjaCBjb2x1bW4NCnN1bW1hcnkoY2F0cykNCmBgYA0KDQpUaGVyZSBhcmUgNDcgZmVtYWxlIGNhdHMgKCdGJykgYW5kIDk3IG1hbGUgY2F0cyAoJ00nKS4gYHN1bW1hcnkoKWAgYWxzbyBnaXZlcyB0aGUgbWVhbiBhbmQgNSBudW1iZXIgc3VtbWFyeSBmb3IgZWFjaCBudW1lcmljIChxdWFudGl0YXRpdmUpIGNvbHVtbi4NCg0KQSBiZXR0ZXIgd2F5IGlzIHRvIHZpc3VhbGl6ZSB0aGUgZGF0YSB3aXRoIGVpdGhlciBhICoqaGlzdG9ncmFtKiogb3IgKipkZW5zaXR5IHBsb3QqKi4gSSBwcmVmZXIgZGVuc2l0eSBwbG90cyBzaW5jZSB0aGVyZSBpc24ndCBhIG5lZWQgdG8gc3BlY2lmeSB0aGUgYmluIHdpZHRoIG9yIGJpbiBudW1iZXIsIGJ1dCBlaXRoZXIgb25lIHdvcmtzOg0KDQpgYGB7ciBkZW5zaXR5X3Bsb3R9DQojIFN0YWNraW5nIGJvdGggQnd0IGFuZCBId3QgaW50byBvbmUgY29sdW1uIGNhbGxlZCBjYXRzX2xvbmcNCmNhdHNfbG9uZyA8LSANCiAgY2F0cyB8Pg0KICBkcGx5cjo6c2VsZWN0KA0KICAgIHNleCA9IFNleCwNCiAgICBgYm9keSB3ZWlnaHQgKGtnKWAgPSBCd3QsDQogICAgYGhlYXJ0IHdlaWdodCAoZylgID0gSHd0DQogICkgfD4NCiAgIyBhZGRpbmcgYW4gaWQgY29sdW1uDQogIG11dGF0ZSgNCiAgICAuYmVmb3JlID0gMSwNCiAgICBjYXRfaWQgPSByb3dfbnVtYmVyKCkNCiAgKSB8Pg0KICBwaXZvdF9sb25nZXIoDQogICAgY29scyA9IGMoLXNleCwgLWNhdF9pZCksDQogICAgbmFtZXNfdG8gPSAnZmVhdHVyZScsDQogICAgdmFsdWVzX3RvID0gJ3dlaWdodCcNCiAgKQ0KDQojIENyZWF0aW5nIHRoZSBkZW5zaXR5IHBsb3RzDQogIGdncGxvdCgNCiAgICBkYXRhID0gY2F0c19sb25nLA0KICAgIG1hcHBpbmcgPSBhZXMoeCA9IHdlaWdodCkNCiAgKSArDQogIGdlb21fZGVuc2l0eSgNCiAgICBmaWxsID0gJ29yYW5nZScNCiAgKSArIA0KICBmYWNldF93cmFwKA0KICAgIGZhY2V0cyA9IHZhcnMoZmVhdHVyZSksDQogICAgbnJvdyA9IDIsDQogICAgc2NhbGVzID0gJ2ZyZWUnDQogICkgKyANCiAgbGFicygNCiAgICB0aXRsZSA9ICdCb2R5IGFuZCBoZWFydCB3ZWlnaHQgb2YgMTQ0IGNhdHMnLA0KICAgIHggPSBOVUxMDQogICkgKyANCiAgdGhlbWVfYncoKSArDQogICMgTWFraW5nIHRoZSBkZW5zaXR5IHBsb3QgJ3NpdCcgb24gdGhlIHgtYXhpcw0KICBzY2FsZV95X2NvbnRpbnVvdXMoDQogICAgZXhwYW5kID0gYygwLCAwLCAwLjA1LCAwKQ0KICApDQpgYGANCg0KQm90aCBoZWFydCBhbmQgYm9keSB3ZWlnaHQgb2YgdGhlIGNhdHMgYXJlIHVuaW1vZGFsIGFuZCByaWdodCBza2V3ZWQuIEJvZHkgd2VpZ2h0IGhhcyBhIG1pbiBvZiAyIGtnLCBtYXggb2YgYWJvdXQgNCBrZywgYW5kIGEgbW9kZSBvZiBhcm91bmQgMi4zIGtncw0KDQpIZWFydCB3ZWlnaHQgaGFzIGEgbWluIG9mIGFib3V0IDYgZywgbWF4IG9mIGFib3V0IDEwIGcsIGFuZCBhIG1vZGUgb2YgMTAgZy4NCg0KIyMjIFN1bW1hcnkgc3RhdHMNCg0KV2hlbiB1c2luZyBwcm9iYWJpbGl0eSBkaXN0cmlidXRpb25zLCB3ZSBvZnRlbiBuZWVkIHRvIGVzdGltYXRlIHRoZSBwYXJhbWV0ZXJzLiBGb3IgbnVtZXJpYyBkYXRhLCBjb21tb24gcHJvYmFiaWxpdHkgZGlzdHJpYnV0aW9ucyB1c2VkIGhhdmUgYSBtZWFuIHBhcmFtZXRlciwgJFxtdSQsIGFuZCBhIHZhcmlhbmNlIHBhcmFtZXRlciwgJFxzaWdtYV4yJCwgb3Igc3RhbmRhcmQgZGV2aWF0aW9uLCAkXHNpZ21hJC4NCg0KV2UgZXN0aW1hdGUgdGhlIHBhcmFtZXRlcnMgZnJvbSB0aGUgZGF0YSB1c2luZyBzYW1wbGUgc3RhdGlzdGljczoNCg0KJCRcaGF0e1xtdX0gPSBcYmFye3l9ID0gXGZyYWN7MX17bn1cc3VtX3tpID0gMX1ebiB5X2kkJA0KDQokJFxoYXR7XHNpZ21hfV4yID0gc14yID0gXGZyYWN7MX17bi0xfVxzdW1fe2kgPSAxfV5uICh5X2ktXGJhcnt5fSleMiQkDQoNCiQkXGhhdHtcc2lnbWF9ID0gcyA9IFxzcXJ0e1xmcmFjezF9e24tMX1cc3VtX3tpID0gMX1ebiAoeV9pLVxiYXJ7eX0pXjJ9JCQNCg0KVG8gc3BlZWQgdXAgdGhlIGNhbGN1bGF0aW5nIHRoZSBtZWFuIGFuZCBzdGFuZGFyZCBkZXZpYXRpb24sIHdlJ2xsIHVzZSB0aGUgYGNhdHNfbG9uZ2AgZGF0YSBzZXQgY3JlYXRlZCBpbiB0aGUgcHJldmlvdXMgY29kZSBjaHVuazoNCg0KYGBge3J9DQpzbGljZV9zYW1wbGUoY2F0c19sb25nLCBuID0gMTApDQpgYGANCg0KTm93IHdlJ2xsIGNhbGN1bGF0ZSB0aGUgcGFyYW1ldGVyIGVzdGltYXRlcyB1c2luZyB0aGUgYHN1bW1hcml6ZSgpYCBmdW5jdGlvbiBpbiB0aGUgYGRwbHlyYCBwYWNrYWdlOg0KDQpgYGB7cn0NCmNhdHNfbG9uZyB8Pg0KICBzdW1tYXJpemUoDQogICAgLmJ5ID0gZmVhdHVyZSwgICAgICAgICAgICAjIHNlcGFyYXRlIHBhcmFtZXRlcnMgZm9yIGVhY2ggUlYNCiAgICBhdmcgPSBzdW0od2VpZ2h0KSAvIG4oKSwgICMgbigpIGNvdW50cyB0aGUgbnVtYmVyIG9mIHJvd3MgdXNlZCBpbiB0aGUgc3Vic2V0DQogICAgYXZnMiA9IG1lYW4od2VpZ2h0KSwgICAgICAjIG9yIHdlIGNhbiB1c2UgdGhlIG1lYW4oKSBmdW5jdGlvbg0KICAgIA0KICAgICMgQ2FsY3VsYXRpbmcgdGhlIHZhcmlhYmlsaXR5IHBhcmFtZXRlcnMNCiAgICB2YXJpYW5jZSA9IChzdW0oKHdlaWdodCAtIG1lYW4od2VpZ2h0KSleMikvKG4oKSAtIDEpKSwNCiAgICB2YXJpYW5jZTIgPSB2YXIod2VpZ2h0KSwNCiAgICBzdGRldiA9IHNxcnQodmFyaWFuY2UpLA0KICAgIHN0ZGV2MiA9IHNkKHdlaWdodCkNCiAgKQ0KYGBgDQoNCldlIGNhbiBlc3RpbWF0ZSB0aGUgY292YXJpYW5jZSBhbmQgY29ycmVsYXRpb246DQoNCiQkXHdpZGVoYXR7Y292fShYLFkpID0gXGhhdHtcc2lnbWF9X3t4eX0gPSBcZnJhY3sxfXtuLTF9IFxzdW1fe2kgPSAxfV5uKHhfaSAtIFxiYXJ7eH0pKHlfaSAtXGJhcnt5fSkgJCQNCg0KJCRyID0gXGZyYWN7XGhhdHtcc2lnbWF9X3t4eX19e3NfeCBzX3l9ID0gXGZyYWN7XHN1bV97aSA9IDF9Xm4oeF9pIC0gXGJhcnt4fSkoeV9pIC1cYmFye3l9KX17XHNxcnR7XHN1bV97aSA9IDF9Xm4oeF9pIC0gXGJhcnt4fSleMn1cc3FydHtcc3VtX3tpID0gMX1ebih5X2kgLSBcYmFye3l9KV4yfX0kJA0KDQpgYGB7cn0NCmNhdHMgfD4NCiAgc3VtbWFyaXplKA0KICAgICMgQ2FsY3VsYXRpbmcgdGhlIGNvdmFyaWFuY2UgYnkgImhhbmQiIGFuZCB1c2luZyB0aGUgUiBmdW5jdGlvbg0KICAgIGNvdmFyaWFuY2UgID0gc3VtKChCd3QgLSBtZWFuKEJ3dCkpICogKEh3dCAtIG1lYW4oSHd0KSkpLyhuKCkgLSAxKSwNCiAgICBjb3ZhcmlhbmNlMiA9IGNvdihCd3QsIEh3dCksDQogICAgDQogICAgIyBDYWxjdWxhdGluZyB0aGUgY29ycmVsYXRpb24gJ2J5IGhhbmQnIGFuZCB1c2luZyB0aGUgUiBmdW5jdGlvbg0KICAgIGNvcnJlbGF0aW9uICA9IHN1bSgoQnd0IC0gbWVhbihCd3QpKSAqIChId3QgLSBtZWFuKEh3dCkpKSAvIA0KICAgICAgICAgICAgICAgICAgIHNxcnQoc3VtKChCd3QgLSBtZWFuKEJ3dCkpXjIpICogc3VtKChId3QgLSBtZWFuKEh3dCkpXjIpKSwNCiAgICBjb3JyZWxhdGlvbjIgPSBjb3ZhcmlhbmNlIC8gKHNkKEJ3dCkgKiBzZChId3QpKSwNCiAgICBjb3JyZWxhdGlvbjMgPSBjb3IoQnd0LCBId3QpDQogICkNCmBgYA0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0K