Start Date: 30 Dec 2025

Report Date: 31 December 2025

Source: Psi Chi R

Welcome to DnD December! Please check the file tab for the dataset and prompts. The contest entry form is available here: https://forms.gle/JhLUSixHoTkiSRqdA

We will accept entries until 12/31 - latest timezone on earth.

knitr::opts_chunk$set(echo = T,message = F,warning = F)

#setwd("C:/Users/alanh/Documents/R/Psi_Chi_R")

rm(list=ls())

setwd("~/R/Psi_Chi_R")

library(tidyverse)

#total for bottom row
sum_rows = function(x) {
  x = as.data.frame(x)
  sums = sapply(x,function(col) if (is.numeric(col)) sum(col, na.rm = T) else NA)
  sums = as.data.frame(t(sums))
  names(sums) = names(x)
  rbind(x, sums)
}

## right column for total
sum_cols = function(x) {
  x$Total = rowSums(x[sapply(x, is.numeric)], na.rm = T)
  x
}

#dollar format function
dollars = function(x) {
  paste0("$",format(x,big.mark= ",",scientific=F))
}

desc_stats = function(x){
  c(min = min(x,na.rm=T),
    median = median(x,na.rm=T),
    max = max(x,na.rm=T),
    mean = mean(x,na.rm=T),
    sd = sd(x,na.rm=T))
}

#numeric notations
options(scipen=9999)

Clean and EDA

data=read_csv('data.csv')

names(data) = make.names(colnames(data))

SmartEDA::ExpData(data,type=2) %>% 
  arrange(desc(Per_of_Missing))

1) Data processing (level 1)

1.Remove rows where there are missing values for speed or charisma

data1 = data |> 
  filter(!is.na(speed),!is.na(charisma))

#skimr::skim(data1)

2) Descriptive Statistics (level 2)

2.1.Create a descriptive statistics table that shows the average, SD, min, median, and max values for height, weight, speed, strength, dexterity, constitution, intelligence, wisdom, and charisma by race

#list_stuff = unique(colnames(data1))
#list_stuff = list_stuff[list_stuff != "race"]

list_stuff = c("height", "weight", 'speed', 'strength', 'dexterity', 'constitution', 'intelligence', 'wisdom', "charisma")

for (i in list_stuff){
  x = desc_stats(data1[[i]])
  print(i)
  print(x)
}
## [1] "height"
##      min   median      max     mean       sd 
## 33.00000 64.00000 82.00000 59.58644 13.28168 
## [1] "weight"
##       min    median       max      mean        sd 
##  39.00000 154.00000 367.00000 146.80927  68.27617 
## [1] "speed"
##       min    median       max      mean        sd 
## 25.000000 30.000000 30.000000 28.322464  2.360956 
## [1] "strength"
##       min    median       max      mean        sd 
##  3.000000 13.000000 20.000000 12.846393  2.966091 
## [1] "dexterity"
##       min    median       max      mean        sd 
##  3.000000 13.000000 20.000000 12.838467  2.944567 
## [1] "constitution"
##       min    median       max      mean        sd 
##  3.000000 13.000000 20.000000 12.753988  2.926053 
## [1] "intelligence"
##       min    median       max      mean        sd 
##  3.000000 13.000000 20.000000 12.756496  2.946306 
## [1] "wisdom"
##       min    median       max      mean        sd 
##  3.000000 13.000000 19.000000 12.418280  2.892536 
## [1] "charisma"
##      min   median      max     mean       sd 
##  3.00000 13.00000 20.00000 12.87258  2.97461

2.2 Identify the rows that have values for dexterity and constitution that are considered outliers

list_dex_con = c('dexterity','constitution')

for (i in list_dex_con){
  boxplot(data1[[i]],na.rm=T,main = i)
}

data2 = data1 |> 
  filter(dexterity >= 5, constitution >= 5)

3) Data visualization (level 3)

3.1 Create a visualization that compares the average charisma and intelligence values for elfs, half.elfs, and gnomes

#unique(data1$race)

list_elfs = c('elf','half.elf','gnome')

data3_elf = data1 |> 
  group_by(race) |> 
  filter(race %in% list_elfs) |> 
  summarise(AVG_Charisma = mean(charisma,na.rm=T),
            AVG_Intelligence = mean(intelligence,na.rm=T))

data3_elf |> 
  ggplot(aes(x=AVG_Intelligence,y=AVG_Charisma,fill=race))+
  geom_col()+
  theme_bw()

4) Inferential statistics (level 4)

4.1) If you wanted a character with high wisdom, which of the following would be your best choice and why: humans, dragonborns, or elfs?

Descriptive

data3_human = data2 |> 
  filter(race %in% c('human', 'dragonborn','elf')) |> 
  select(wisdom,race)

data3_human |> 
  group_by(race) |> 
  summarise(MAX_WISDOM = max(wisdom,na.rm = T),
            MEAN_WISDOM = mean(wisdom,na.rm=T),
            MEDIAN_WISDOM = median(wisdom,na.rm=T),
            SD_WISDOM = sd(wisdom,na.rm = T))

Plot

data3_human |> 
  ggplot(aes(x = race, y = wisdom,fill=race)) +
  geom_boxplot() +
  labs(y = "Wisdom") +
  theme_bw()+
  guides(fill='none')

data3_human |> 
  ggplot(aes(x= wisdom,col = race)) +
  geom_histogram(aes(y = ..density..), position = "identity", bins = 30,col='black') +
  geom_density(lwd=1) +
  theme_bw()

Test

result_ANOVA = aov(wisdom~race,data=data3_human)

result_ANOVA
## Call:
##    aov(formula = wisdom ~ race, data = data3_human)
## 
## Terms:
##                      race Residuals
## Sum of Squares    908.985 27347.445
## Deg. of Freedom         2      3355
## 
## Residual standard error: 2.855039
## Estimated effects may be unbalanced
summary(result_ANOVA)
##               Df Sum Sq Mean Sq F value              Pr(>F)    
## race           2    909   454.5   55.76 <0.0000000000000002 ***
## Residuals   3355  27347     8.2                                
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
TukeyHSD(result_ANOVA)
##   Tukey multiple comparisons of means
##     95% family-wise confidence level
## 
## Fit: aov(formula = wisdom ~ race, data = data3_human)
## 
## $race
##                       diff        lwr       upr     p adj
## elf-dragonborn   0.1112326 -0.1716187 0.3940838 0.6263415
## human-dragonborn 1.1548886  0.8728086 1.4369686 0.0000000
## human-elf        1.0436560  0.7596211 1.3276910 0.0000000

There is no significant difference in wisdom between dragonborns and elves, but humans have significantly higher wisdom scores compared to both dragonborns and elves. So humans are the best choice for a character that’s high in wisdom.

LS0tDQp0aXRsZTogIlBzaSBDaGkgUiAtIERlYyAyMDI1Ig0KI2RhdGU6ICJgciBTeXMuRGF0ZSgpYCINCm91dHB1dDoNCiAgaHRtbF9kb2N1bWVudDoNCiAgICBsaWdodGJveDogdHJ1ZQ0KICAgIHRoZW1lOiByZWFkYWJsZQ0KICAgIGFsd2F5c19hbGxvd19odG1sOiB5ZXMNCiAgICBkZl9wcmludDogcGFnZWQNCiAgICB0b2M6IHllcw0KICAgIHRvY19mbG9hdDogeWVzDQogICAgbnVtYmVyX3NlY3Rpb25zOiBubw0KICAgIGFuY2hvcl9zZWN0aW9uczogVFJVRQ0KICAgIGNvZGVfZm9sZGluZzogaGlkZQ0KICAgIGNvZGVfZG93bmxvYWQ6IHRydWUNCi0tLQ0KDQpTdGFydCBEYXRlOiAzMCBEZWMgMjAyNQ0KDQpSZXBvcnQgRGF0ZTogYHIgZm9ybWF0KFN5cy5EYXRlKCksICclZCAlQiAlWScpYA0KDQpbU291cmNlOiBQc2kgQ2hpIFJdKGh0dHBzOi8vb3NmLmlvL2h3a2M5L292ZXJ2aWV3KQ0KDQpXZWxjb21lIHRvIERuRCBEZWNlbWJlciEgUGxlYXNlIGNoZWNrIHRoZSBmaWxlIHRhYiBmb3IgdGhlIGRhdGFzZXQgYW5kIHByb21wdHMuIFRoZSBjb250ZXN0IGVudHJ5IGZvcm0gaXMgYXZhaWxhYmxlIGhlcmU6IGh0dHBzOi8vZm9ybXMuZ2xlL0poTFVTaXhIb1RraVNScWRBDQoNCldlIHdpbGwgYWNjZXB0IGVudHJpZXMgdW50aWwgMTIvMzEgLSBsYXRlc3QgdGltZXpvbmUgb24gZWFydGguDQoNCmBgYHtyIHdhcm5pbmc9RixtZXNzYWdlPUZ9DQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFQsbWVzc2FnZSA9IEYsd2FybmluZyA9IEYpDQoNCiNzZXR3ZCgiQzovVXNlcnMvYWxhbmgvRG9jdW1lbnRzL1IvUHNpX0NoaV9SIikNCg0Kcm0obGlzdD1scygpKQ0KDQpzZXR3ZCgifi9SL1BzaV9DaGlfUiIpDQoNCmxpYnJhcnkodGlkeXZlcnNlKQ0KDQojdG90YWwgZm9yIGJvdHRvbSByb3cNCnN1bV9yb3dzID0gZnVuY3Rpb24oeCkgew0KICB4ID0gYXMuZGF0YS5mcmFtZSh4KQ0KICBzdW1zID0gc2FwcGx5KHgsZnVuY3Rpb24oY29sKSBpZiAoaXMubnVtZXJpYyhjb2wpKSBzdW0oY29sLCBuYS5ybSA9IFQpIGVsc2UgTkEpDQogIHN1bXMgPSBhcy5kYXRhLmZyYW1lKHQoc3VtcykpDQogIG5hbWVzKHN1bXMpID0gbmFtZXMoeCkNCiAgcmJpbmQoeCwgc3VtcykNCn0NCg0KIyMgcmlnaHQgY29sdW1uIGZvciB0b3RhbA0Kc3VtX2NvbHMgPSBmdW5jdGlvbih4KSB7DQogIHgkVG90YWwgPSByb3dTdW1zKHhbc2FwcGx5KHgsIGlzLm51bWVyaWMpXSwgbmEucm0gPSBUKQ0KICB4DQp9DQoNCiNkb2xsYXIgZm9ybWF0IGZ1bmN0aW9uDQpkb2xsYXJzID0gZnVuY3Rpb24oeCkgew0KICBwYXN0ZTAoIiQiLGZvcm1hdCh4LGJpZy5tYXJrPSAiLCIsc2NpZW50aWZpYz1GKSkNCn0NCg0KZGVzY19zdGF0cyA9IGZ1bmN0aW9uKHgpew0KICBjKG1pbiA9IG1pbih4LG5hLnJtPVQpLA0KICAgIG1lZGlhbiA9IG1lZGlhbih4LG5hLnJtPVQpLA0KICAgIG1heCA9IG1heCh4LG5hLnJtPVQpLA0KICAgIG1lYW4gPSBtZWFuKHgsbmEucm09VCksDQogICAgc2QgPSBzZCh4LG5hLnJtPVQpKQ0KfQ0KDQojbnVtZXJpYyBub3RhdGlvbnMNCm9wdGlvbnMoc2NpcGVuPTk5OTkpDQpgYGANCg0KIyMgQ2xlYW4gYW5kIEVEQQ0KDQpgYGB7cn0NCmRhdGE9cmVhZF9jc3YoJ2RhdGEuY3N2JykNCg0KbmFtZXMoZGF0YSkgPSBtYWtlLm5hbWVzKGNvbG5hbWVzKGRhdGEpKQ0KDQpTbWFydEVEQTo6RXhwRGF0YShkYXRhLHR5cGU9MikgJT4lIA0KICBhcnJhbmdlKGRlc2MoUGVyX29mX01pc3NpbmcpKQ0KYGBgDQoNCiMjIDEpIERhdGEgcHJvY2Vzc2luZyAobGV2ZWwgMSkNCg0KIyMjIDEuUmVtb3ZlIHJvd3Mgd2hlcmUgdGhlcmUgYXJlIG1pc3NpbmcgdmFsdWVzIGZvciBzcGVlZCBvciBjaGFyaXNtYQ0KDQpgYGB7cn0NCmRhdGExID0gZGF0YSB8PiANCiAgZmlsdGVyKCFpcy5uYShzcGVlZCksIWlzLm5hKGNoYXJpc21hKSkNCg0KI3NraW1yOjpza2ltKGRhdGExKQ0KYGBgDQoNCg0KIyMgMikgRGVzY3JpcHRpdmUgU3RhdGlzdGljcyAobGV2ZWwgMikNCg0KIyMjIDIuMS5DcmVhdGUgYSBkZXNjcmlwdGl2ZSBzdGF0aXN0aWNzIHRhYmxlIHRoYXQgc2hvd3MgdGhlIGF2ZXJhZ2UsIFNELCBtaW4sIG1lZGlhbiwgYW5kIG1heCB2YWx1ZXMgZm9yIGhlaWdodCwgd2VpZ2h0LCBzcGVlZCwgc3RyZW5ndGgsIGRleHRlcml0eSwgY29uc3RpdHV0aW9uLCBpbnRlbGxpZ2VuY2UsIHdpc2RvbSwgYW5kIGNoYXJpc21hIGJ5IHJhY2UNCg0KYGBge3J9DQojbGlzdF9zdHVmZiA9IHVuaXF1ZShjb2xuYW1lcyhkYXRhMSkpDQojbGlzdF9zdHVmZiA9IGxpc3Rfc3R1ZmZbbGlzdF9zdHVmZiAhPSAicmFjZSJdDQoNCmxpc3Rfc3R1ZmYgPSBjKCJoZWlnaHQiLCAid2VpZ2h0IiwgJ3NwZWVkJywgJ3N0cmVuZ3RoJywgJ2RleHRlcml0eScsICdjb25zdGl0dXRpb24nLCAnaW50ZWxsaWdlbmNlJywgJ3dpc2RvbScsICJjaGFyaXNtYSIpDQoNCmZvciAoaSBpbiBsaXN0X3N0dWZmKXsNCiAgeCA9IGRlc2Nfc3RhdHMoZGF0YTFbW2ldXSkNCiAgcHJpbnQoaSkNCiAgcHJpbnQoeCkNCn0NCmBgYA0KDQojIyMgMi4yIElkZW50aWZ5IHRoZSByb3dzIHRoYXQgaGF2ZSB2YWx1ZXMgZm9yIGRleHRlcml0eSBhbmQgY29uc3RpdHV0aW9uIHRoYXQgYXJlIGNvbnNpZGVyZWQgb3V0bGllcnMNCg0KYGBge3J9DQpsaXN0X2RleF9jb24gPSBjKCdkZXh0ZXJpdHknLCdjb25zdGl0dXRpb24nKQ0KDQpmb3IgKGkgaW4gbGlzdF9kZXhfY29uKXsNCiAgYm94cGxvdChkYXRhMVtbaV1dLG5hLnJtPVQsbWFpbiA9IGkpDQp9DQoNCmRhdGEyID0gZGF0YTEgfD4gDQogIGZpbHRlcihkZXh0ZXJpdHkgPj0gNSwgY29uc3RpdHV0aW9uID49IDUpDQpgYGANCg0KIyMgMykgRGF0YSB2aXN1YWxpemF0aW9uIChsZXZlbCAzKQ0KDQojIyMgMy4xIENyZWF0ZSBhIHZpc3VhbGl6YXRpb24gdGhhdCBjb21wYXJlcyB0aGUgYXZlcmFnZSBjaGFyaXNtYSBhbmQgaW50ZWxsaWdlbmNlIHZhbHVlcyBmb3IgZWxmcywgaGFsZi5lbGZzLCBhbmQgZ25vbWVzDQoNCmBgYHtyfQ0KI3VuaXF1ZShkYXRhMSRyYWNlKQ0KDQpsaXN0X2VsZnMgPSBjKCdlbGYnLCdoYWxmLmVsZicsJ2dub21lJykNCg0KZGF0YTNfZWxmID0gZGF0YTEgfD4gDQogIGdyb3VwX2J5KHJhY2UpIHw+IA0KICBmaWx0ZXIocmFjZSAlaW4lIGxpc3RfZWxmcykgfD4gDQogIHN1bW1hcmlzZShBVkdfQ2hhcmlzbWEgPSBtZWFuKGNoYXJpc21hLG5hLnJtPVQpLA0KICAgICAgICAgICAgQVZHX0ludGVsbGlnZW5jZSA9IG1lYW4oaW50ZWxsaWdlbmNlLG5hLnJtPVQpKQ0KDQpkYXRhM19lbGYgfD4gDQogIGdncGxvdChhZXMoeD1BVkdfSW50ZWxsaWdlbmNlLHk9QVZHX0NoYXJpc21hLGZpbGw9cmFjZSkpKw0KICBnZW9tX2NvbCgpKw0KICB0aGVtZV9idygpDQpgYGANCg0KDQojIyA0KSBJbmZlcmVudGlhbCBzdGF0aXN0aWNzIChsZXZlbCA0KQ0KDQojIyMgNC4xKSBJZiB5b3Ugd2FudGVkIGEgY2hhcmFjdGVyIHdpdGggaGlnaCB3aXNkb20sIHdoaWNoIG9mIHRoZSBmb2xsb3dpbmcgd291bGQgYmUgeW91ciBiZXN0IGNob2ljZSBhbmQgd2h5OiBodW1hbnMsIGRyYWdvbmJvcm5zLCBvciBlbGZzPw0KDQojIyMjIERlc2NyaXB0aXZlDQpgYGB7cn0NCmRhdGEzX2h1bWFuID0gZGF0YTIgfD4gDQogIGZpbHRlcihyYWNlICVpbiUgYygnaHVtYW4nLCAnZHJhZ29uYm9ybicsJ2VsZicpKSB8PiANCiAgc2VsZWN0KHdpc2RvbSxyYWNlKQ0KDQpkYXRhM19odW1hbiB8PiANCiAgZ3JvdXBfYnkocmFjZSkgfD4gDQogIHN1bW1hcmlzZShNQVhfV0lTRE9NID0gbWF4KHdpc2RvbSxuYS5ybSA9IFQpLA0KICAgICAgICAgICAgTUVBTl9XSVNET00gPSBtZWFuKHdpc2RvbSxuYS5ybT1UKSwNCiAgICAgICAgICAgIE1FRElBTl9XSVNET00gPSBtZWRpYW4od2lzZG9tLG5hLnJtPVQpLA0KICAgICAgICAgICAgU0RfV0lTRE9NID0gc2Qod2lzZG9tLG5hLnJtID0gVCkpDQpgYGANCg0KIyMjIyBQbG90DQpgYGB7cn0NCmRhdGEzX2h1bWFuIHw+IA0KICBnZ3Bsb3QoYWVzKHggPSByYWNlLCB5ID0gd2lzZG9tLGZpbGw9cmFjZSkpICsNCiAgZ2VvbV9ib3hwbG90KCkgKw0KICBsYWJzKHkgPSAiV2lzZG9tIikgKw0KICB0aGVtZV9idygpKw0KICBndWlkZXMoZmlsbD0nbm9uZScpDQoNCmRhdGEzX2h1bWFuIHw+IA0KICBnZ3Bsb3QoYWVzKHg9IHdpc2RvbSxjb2wgPSByYWNlKSkgKw0KICBnZW9tX2hpc3RvZ3JhbShhZXMoeSA9IC4uZGVuc2l0eS4uKSwgcG9zaXRpb24gPSAiaWRlbnRpdHkiLCBiaW5zID0gMzAsY29sPSdibGFjaycpICsNCiAgZ2VvbV9kZW5zaXR5KGx3ZD0xKSArDQogIHRoZW1lX2J3KCkNCmBgYA0KDQojIyMjIFRlc3QNCmBgYHtyfQ0KcmVzdWx0X0FOT1ZBID0gYW92KHdpc2RvbX5yYWNlLGRhdGE9ZGF0YTNfaHVtYW4pDQoNCnJlc3VsdF9BTk9WQQ0KDQpzdW1tYXJ5KHJlc3VsdF9BTk9WQSkNCmBgYA0KDQpgYGB7cn0NClR1a2V5SFNEKHJlc3VsdF9BTk9WQSkNCmBgYA0KDQpUaGVyZSBpcyBubyBzaWduaWZpY2FudCBkaWZmZXJlbmNlIGluIHdpc2RvbSBiZXR3ZWVuIGRyYWdvbmJvcm5zIGFuZCBlbHZlcywgYnV0IGh1bWFucyBoYXZlIHNpZ25pZmljYW50bHkgaGlnaGVyIHdpc2RvbSBzY29yZXMgY29tcGFyZWQgdG8gYm90aCBkcmFnb25ib3JucyBhbmQgZWx2ZXMuIFNvIGh1bWFucyBhcmUgdGhlIGJlc3QgY2hvaWNlIGZvciBhIGNoYXJhY3RlciB0aGF0J3MgaGlnaCBpbiB3aXNkb20uDQoNCmBgYHtyIGluY2x1ZGU9Rn0NCiNiZWVwIHdoZW4gZG9uZQ0KaWYgKHJlcXVpcmUoImJlZXByIikpDQogIGJlZXByOjpiZWVwKDIpDQpgYGA=