Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.
I ought to be spending this weekend working on a risk intelligence thing for work, but I’ve stumbled across something that brings my inner child immense joy and such things cannot be ignored. It is this 2019 paper “An Older and Exceptionally Large Adult Specimen of Tyrannosaurus rex” by Persons et al. First it’s cool to see paleontology in action, instead of filtered through talking head documentaries. Second, the diligent authors have personally measured 12 T. rex specimens, which is a decent chunk of the 29 or-so specimens discovered to-date, and so we have a cool dataset to play with.
library(tidyverse) library(knitr) t.rex <- read_tsv("t.rex-persons.tsv", col_types = "ccnnnnnnnnnnnnnnn") |> rename(Specimen = Specimens) |> mutate(Morph = factor(Morph, levels = c("Robust", "Gracile"))) kable(t.rex, format.args = list(decimal.mark = ".", big.mark = ","))
Specimen | Morph | Dentary tooth row length | Scapula blade width | Manual p. I-1 length | Ilium length | Femur length | Femur circumference | Proximal femur width | Tibia length | Tibia shaft width | Fibula length | Fibula shaft width | Astragalus height | Astragalus width | Pedal p. IV-1 length | Body mass (kg) |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
RSM P2523.8 | Robust | 595 | 74.8 | 98.5 | 1,545 | 1,333 | 590 | 426 | 1,140 | 184 | 995 | 62 | 328 | 310 | 184 | 8,870 |
CM 9380 (AMNH 973) | Robust | 508 | 73.0 | NA | 1,540 | 1,269 | 534 | 399 | 1,166 | 150 | 1,025 | NA | NA | NA | 145 | 6,740 |
FMNH PR2081 | Robust | 585 | 68.0 | 78.0 | 1,525 | 1,321 | 580 | 380 | 1,140 | 160 | 1,030 | 59 | NA | NA | 154 | 8,462 |
MOR 1125 | Robust | 492 | 65.7 | NA | NA | 1,150 | 515 | 370 | 1,060 | 150 | 915 | 53 | 280 | 295 | 170 | 6,100 |
RTMP 81.12.1, NMC 9950 | Robust | NA | NA | NA | NA | NA | 495 | NA | 1,095 | 155 | 985 | 65 | NA | NA | 140 | 5,469 |
BHI 3033 | Gracile | 575 | NA | NA | 1,540 | 1,350 | 505 | 350 | 1,065 | 158 | 945 | 55 | 325 | 280 | NA | 5,779 |
MOR 555 | Gracile | 635 | 65.0 | 89.0 | 1,470 | 1,280 | 520 | 370 | 1,150 | 170 | 1,035 | 56 | NA | 235 | 176 | 6,264 |
MOR 980 | Gracile | 546 | NA | NA | 1,397 | 1,232 | 483 | NA | NA | NA | NA | NA | NA | NA | NA | 5,112 |
RTMP 81.6.1 | Gracile | 530 | NA | NA | NA | 1,210 | 460 | 270 | 1,030 | 160 | NA | 52 | NA | NA | 107 | 4,469 |
BM R8040 (AMNH 5881) | NA | NA | NA | NA | NA | NA | 480 | 330 | NA | NA | NA | NA | NA | NA | 124 | 5,025 |
MOR 009 | NA | NA | NA | 90.0 | 1,180 | 1,100 | 469 | NA | 1,105 | 140 | 930 | NA | NA | NA | NA | 4,714 |
USNM 6183 | NA | NA | NA | NA | NA | 1,040 | 426 | NA | 910 | NA | NA | NA | NA | NA | NA | 3,617 |
We can also add “Goliath”, the exciting 2024 specimen. Bear in mind that Persons didn’t personally measure this fossil, so that’s a source of potential error. I took the measurements from the few social media posts about the fossil. The lack of information on this specimen seems strange to me, I even wonder if it’s a hoax. It wouldn’t be the first time.
campione.body.mass.kg <- function(min.femoral.circ.mm) 10**((2.754 * log10(min.femoral.circ.mm) - 0.683) - 3) goliath <- read_tsv("t.rex-goliath.tsv", col_types = "ccnnnnnnnnnnnnnnn") |> mutate( Morph = factor(Morph, levels = c("Robust", "Gracile")), `Body mass (kg)` = campione.body.mass.kg(`Femur circumference`) ) t.rex <- bind_rows(t.rex, goliath) kable(select(goliath, Specimen, `Femur length`, `Femur circumference`, `Body mass (kg)`))
Specimen | Femur length | Femur circumference | Body mass (kg) |
---|---|---|---|
Goliath | 1371 | 648 | 11483.59 |
The most interesting bone is the femur, being as it’s more likely to be present and is used to estimate body mass. The equation used is from Campione et al 2014. Bear in mind they suggest a 25% prediction error.
An interesting thing about T. rex is that there are two morphs, gracile and robust, which I understand to be layman’s terms for “elven” and “chonky”. Let’s see if that’s visible in the femur measurements.
ggplot(t.rex) + aes(x = `Femur length`, y = `Femur circumference`, colour = Morph, label = Specimen) + geom_label(nudge_y = 10, na.rm = TRUE) + geom_point(na.rm = TRUE) + scale_x_continuous(limits = c(1000, 1400)) + scale_y_continuous(limits = c(400, 700)) + theme_minimal()
Looking at this scatterplot, there’s a linear relationship between length and circumference, and Goliath sits neatly on it. (Too neatly? Hmm. Should it even be linear? Wouldn’t the square-cube law suggest femurs should get thicker faster than they get longer?) However it’s not obvious if Goliath should be gracile or robust. In fact, it’s not particularly clear from the femurs alone why some are gracile and some robust; CM 9380 (Holotype) and MOR 555 (Wankel) are very close, for example. We need more features. Unfortunately, the T. rex data are very sparse, so we need to impute missing values.
Tibia length is relatively complete, can we use that?
ggplot(t.rex) + aes(x = `Femur length`, y = `Tibia length`, colour = Morph) + geom_point() + scale_x_continuous(limits = c(1000, 1400)) + scale_y_continuous(limits = c(900, 1200)) + theme_minimal()
The relationship between fibia length and tibia length is surprisingly not very informative.
ggplot(t.rex) + aes(x = `Femur circumference`, y = `Tibia length`, colour = Morph) + geom_point() + scale_x_continuous(limits = c(400, 700)) + scale_y_continuous(limits = c(900, 1200)) + theme_minimal()
Femur circumference relates a little better. Let’s try a dead simple linear model to predict the missing femur lengths. We can include body mass, which is a function of femur circumference, to try and capture some of the knowledge from that model.
reg <- lm(`Femur length` ~ `Femur circumference` * `Body mass (kg)` + `Tibia length`, data = t.rex, subset = !is.na(t.rex$`Tibia length`) & !is.na(`Femur length`)) summary(reg)
Call: lm(formula = `Femur length` ~ `Femur circumference` * `Body mass (kg)` + `Tibia length`, data = t.rex, subset = !is.na(t.rex$`Tibia length`) & !is.na(`Femur length`)) Residuals: 1 2 3 4 6 7 9 11 -2.758 10.381 3.116 -116.353 97.051 30.241 49.109 -69.132 12 -1.655 Coefficients: Estimate Std. Error t value Pr(>|t|) (Intercept) -1.136e+04 2.430e+04 -0.467 0.665 `Femur circumference` 5.020e+01 1.037e+02 0.484 0.654 `Body mass (kg)` -3.832e+00 8.868e+00 -0.432 0.688 `Tibia length` -2.585e-01 8.777e-01 -0.294 0.783 `Femur circumference`:`Body mass (kg)` 3.317e-03 8.054e-03 0.412 0.702 Residual standard error: 88.3 on 4 degrees of freedom Multiple R-squared: 0.6787, Adjusted R-squared: 0.3574 F-statistic: 2.112 on 4 and 4 DF, p-value: 0.2433
It’s not great, though slightly better than the other combinations I tried and probably the best we could do with such a small dataset. The additional imputed femur length (RTMP 81.12.1) is feasible enough.
preds <- predict(reg, newdata = t.rex) t.rex |> mutate(`Femur length` = coalesce(`Femur length`, preds)) |> select(`Specimen`, `Morph`, `Femur length`, `Femur circumference`, `Tibia length`, `Body mass (kg)`) |> kable()
Specimen | Morph | Femur length | Femur circumference | Tibia length | Body mass (kg) |
---|---|---|---|---|---|
RSM P2523.8 | Robust | 1333.000 | 590 | 1140 | 8870.00 |
CM 9380 (AMNH 973) | Robust | 1269.000 | 534 | 1166 | 6740.00 |
FMNH PR2081 | Robust | 1321.000 | 580 | 1140 | 8462.00 |
MOR 1125 | Robust | 1150.000 | 515 | 1060 | 6100.00 |
RTMP 81.12.1, NMC 9950 | Robust | 1230.292 | 495 | 1095 | 5469.00 |
BHI 3033 | Gracile | 1350.000 | 505 | 1065 | 5779.00 |
MOR 555 | Gracile | 1280.000 | 520 | 1150 | 6264.00 |
MOR 980 | Gracile | 1232.000 | 483 | NA | 5112.00 |
RTMP 81.6.1 | Gracile | 1210.000 | 460 | 1030 | 4469.00 |
BM R8040 (AMNH 5881) | NA | NA | 480 | NA | 5025.00 |
MOR 009 | NA | 1100.000 | 469 | 1105 | 4714.00 |
USNM 6183 | NA | 1040.000 | 426 | 910 | 3617.00 |
Goliath | NA | 1371.000 | 648 | NA | 11483.59 |
I’m not sure what else to do with this. Must be tough being a paleontologist, working with so little direct data!
R-bloggers.com offers daily e-mail updates about R news and tutorials about learning R and many other topics. Click here if you're looking to post or find an R/data-science job.
Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.