Descriptive Statistics

บทเรียนนี้จะเป็นการทบทวนสถิติเชิงพรรณนา (descriptive statistics) ที่ใช้ในการสรุปภาพรวมของข้อมูลที่มักจะใช้กันบ่อย ๆ ในงานวิจัยทางด้านพฤกษศาสตร์ โดยเราจะใช้ตัวอย่างข้อมูลขนาดพื้นที่ (Area) และความหนา (Thickness) ของใบของพืชสองชนิดได้แก่ ใบกระเพรา (holy basil) และ ใบโหระพา (sweet basil) ในสองพื้นที่ (habitat) คือ พื้นที่ชื้น (wet) และ พื้นที่แห้ง (dry)

library(tidyverse)
── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
✔ dplyr     1.1.4     ✔ readr     2.1.5
✔ forcats   1.0.0     ✔ stringr   1.5.1
✔ ggplot2   3.5.2     ✔ tibble    3.2.1
✔ lubridate 1.9.3     ✔ tidyr     1.3.1
✔ purrr     1.0.2     
── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
✖ dplyr::filter() masks stats::filter()
✖ dplyr::lag()    masks stats::lag()
ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
library(knitr)
leaf <- read_csv(file = "leaf_data.csv")
Rows: 40 Columns: 5
── Column specification ────────────────────────────────────────────────────────
Delimiter: ","
chr (3): Species, Habitat, Leaf_ID
dbl (2): Thickness, Area

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
leaf
# A tibble: 40 × 5
   Species Habitat Leaf_ID       Thickness  Area
   <chr>   <chr>   <chr>             <dbl> <dbl>
 1 sweet   wet     sweet_wet_L1      0.36   22.9
 2 sweet   wet     sweet_wet_L2      0.347  22.9
 3 sweet   wet     sweet_wet_L3      0.363  26.1
 4 sweet   wet     sweet_wet_L4      0.38   16.4
 5 sweet   wet     sweet_wet_L5      0.345  17.2
 6 sweet   wet     sweet_wet_L6      0.345  22.5
 7 sweet   wet     sweet_wet_L7      0.382  20.4
 8 sweet   wet     sweet_wet_L8      0.365  26.4
 9 sweet   wet     sweet_wet_L9      0.341  20.9
10 sweet   wet     sweet_wet_L10     0.361  18.6
# ℹ 30 more rows

1. Summary statistics

สถิติพรรณาที่ควรรายงานเป็นเบื้องต้น ในชุดข้อมูลของเรามีดังต่อไปนี้

1) จำนวนตัวอย่าง (sample size, n)

จำนวนตัวอย่าง (sample size) มักจะแทนด้วยตัว n เป็นจำนวนนับของซ้ำ (replicates) หรือ จำนวนจุดของข้อมูล (data points) ควรจะรายงานทุกครั้ง โดยเฉพาะอย่างยิ่งถ้าในแต่ละกลุ่มมีจำนวนข้อมูลไม่เท่ากัน

2) ค่าเฉลี่ย (average หรือ mean)

ชื่อเต็มของค่านี้คือ “ค่าเฉลี่ยเลขคณิต” (arithmatic means) คือ ค่าที่คำนวณจากนำข้อมูลแต่ละค่า (\(x_i\)) มาบวกกัน (แทนด้วยเครื่องหมาย \(\Sigma\)) และหารด้วยจำนวนตัวอย่างในกลุ่มนั้น ๆ (n)

\[ \bar{x} = \frac{\Sigma{x_i}}{n}\]

3) ส่วนเบี่ยงเบนมาตรฐาน (standard deviation, SD)

ส่วนเบี่ยงเบนมาตรฐาน (SD) เป็นคำนวณที่แสดงว่าข้อมูลทั้งหมดนั้น กระจายห่างจากค่าเฉลี่ย มากน้อยเท่าไหร่ ยิ่งค่า SD สูงแปลว่า ข้อมูลแต่ละค่านั้นกระจายจากค่าเฉลี่ยมากขึ้นเท่านั้น ค่านี้คำนวณได้จากสูตรต่อไปนี้

\[ SD = \sqrt{\frac{\Sigma{(x_i - \bar{x})^2}}{n-1}}\]

\((x_i - \bar{x})^2\) เป็นการหาค่าความแตกต่างจากข้อมูลแต่จะค่า \(x_i\) จาก ค่าเฉลี่ย \(\bar{x}\) โดยที่ยกกำลัง 2 เพื่อไม่ให้เป็นค่าลบนั้นเอง

4) ความคาดเคลื่อนมาตรฐาน (standard error, SE)

เป็นค่าที่ใช้ประเมินว่าค่าเฉลี่ย (mean) ที่เราได้ประเมินมาได้นั้นมีความแม่นยำมาน้อยเพียงใด โดยสามารถคำนวณได้จากสูตรดังต่อนี้

\[SE = \frac{SD}{\sqrt{n}}\]

โดยที่ SD คือ standard deviation และ n คือจำนวนตัวอย่าง

จากสมการนี้เราจะเห็นได้ว่ายิ่งค่า n เยอะ (จำนวนตัวอย่างเยอะ ๆ ) ค่า SE ก็จะลดลง แสดงว่าค่าเฉลี่ยที่เราได้มาน่าจะคาดเคลื่อนน้อยลง

5) สัมประสิทธิ์ความแปรผัน (Coefficient of Variation, CV)

ข้อเสียอย่างหนึ่งของ SD และ SE ก็คือว่า ถ้าไม่มีตัวเทียบแล้ว เราจะไม่สามารถบอกได้ว่าค่าที่คำนวณนั้นถือว่าเยอะหรือน้อย ค่า Coefficient of Variation, CV จะช่วยประเมินได้ว่าค่าเบี่ยงเบน (SD) นั้นคิดเป็นกี่เปอร์เซนต์ของค่าเฉลี่ย โดยใช้สูตรนี้

\[CV = \frac{SD}{mean}\times 100\]

เราสามารถคำนวณทุกค่าเหล่านี้พร้อม ๆ กันได้ โดยใช้คำสั่ง summarize() โดยที่ใช้ format ดังนี้

summarize(ชื่อคอลัมน์ใหม่ = ฟังก์ชั่น(ชื่อคอลัมน์))

leaf %>%
  summarise(
    n = n(),
    mean = mean(Thickness),
    sd = sd(Thickness),
    se = sd / sqrt(n),
    cv = (sd / mean) * 100
  )
# A tibble: 1 × 5
      n  mean     sd     se    cv
  <int> <dbl>  <dbl>  <dbl> <dbl>
1    40 0.421 0.0906 0.0143  21.5

จากข้อมูลข้างต้น เราจะรายงานข้อมูลอย่างน้อย mean ± SD ดังตัวอย่างนี้

“ใบพืชที่ทำการสำรวจมีความหนาเฉลี่ย 0.42 ± 0.09 มิลลิเมตร (ค่าเฉลี่ย ± ส่วนเบี่ยงเบนมาตรฐาน)”

2. Summary statistics by group

leaf %>%
    group_by(Species) %>% 
    summarise(
    n = n(),
    mean = mean(Thickness),
    sd = sd(Thickness),
    se = sd / sqrt(n),
    cv = (sd / mean) * 100
  ) 
# A tibble: 2 × 6
  Species     n  mean     sd     se    cv
  <chr>   <int> <dbl>  <dbl>  <dbl> <dbl>
1 holy       20 0.415 0.108  0.0241  26.0
2 sweet      20 0.427 0.0716 0.0160  16.8

วิธีการรายงานผล “ใบกระเพรา (holy basil) มีความหนาเฉลี่ย 0.42 ± 0.11 มิลลิเมตร (ค่าเฉลี่ย ± ส่วนเบี่ยงเบนมาตรฐาน) ในขณะที่ ใบโหระพา (sweet basial) มีความหนาเฉลี่ย 0.43 ± 0.07 มิลลิเมตร”

3. Visualize summary statistics

1) วิธีง่ายที่สุด = Boxplot

leaf %>%
    ggplot(aes(x = Species, y = Thickness)) +
    geom_boxplot()

เวลาวาดกราฟแล้วจะนำไปใช้ในการเขียนเล่มรายงานวิจัย เราต้องใส่คำบรรยายใต้ภาพ (caption) ให้ครบถ้วนด้วย ตัวอย่างเช่น

ภาพที่ 1: กราฟแท่งเทียน (boxplot) แสดงความแตกต่างของความหนาใบระหว่างกระเพรา (holy basil) และโหระพา (Sweet basil)

2) วิธีที่นักชีววิทยา ชอบใช้ = Dynamite Plot

leaf %>%
    ggplot(aes(x = Species, y = Thickness)) +
    stat_summary(fun = mean, geom = "col") +
    stat_summary(fun.data = mean_sdl, fun.args = list(mult = 1), geom = "errorbar")

ทำให้สวยงามขึ้นมานิดนึง

leaf %>%
    ggplot(aes(x = Species, y = Thickness)) +
    stat_summary(fun = mean, geom = "col", fill = "lightgrey") +
    stat_summary(fun.data = mean_sdl, fun.args = list(mult = 1), geom = "errorbar",
               width = 0.1, linewidth = 1, color = "red") +
    theme_minimal(base_size = 14)

ภาพที่ 2: กราฟแท่งแสดงค่าเฉลี่ยของความหนาใบระหว่างกระเพรา (holy basil) และโหระพา (Sweet basil) error bars แสดงถึงค่าเฉลี่ย ± ส่วนเบี่ยงเบนมาตรฐาน (standard deviation)

4. สรุปหลาย ๆ ลักษณะพร้อม ๆ กัน

ขั้นตอนแรก จะต้องเปลี่ยนข้อมูลเป็น long format ก่อน

leaf_long <- leaf %>%
    pivot_longer(Thickness:Area, names_to = "character", values_to = "value") 

leaf_long
# A tibble: 80 × 5
   Species Habitat Leaf_ID      character  value
   <chr>   <chr>   <chr>        <chr>      <dbl>
 1 sweet   wet     sweet_wet_L1 Thickness  0.36 
 2 sweet   wet     sweet_wet_L1 Area      22.9  
 3 sweet   wet     sweet_wet_L2 Thickness  0.347
 4 sweet   wet     sweet_wet_L2 Area      22.9  
 5 sweet   wet     sweet_wet_L3 Thickness  0.363
 6 sweet   wet     sweet_wet_L3 Area      26.1  
 7 sweet   wet     sweet_wet_L4 Thickness  0.38 
 8 sweet   wet     sweet_wet_L4 Area      16.4  
 9 sweet   wet     sweet_wet_L5 Thickness  0.345
10 sweet   wet     sweet_wet_L5 Area      17.2  
# ℹ 70 more rows

ต่อมาจึงจะทำ group_by และ summarize ได้ แต่รอบนี้ต้อง group_by character และใช้ value แทนชื่อคอลัมน์

leaf_long %>% 
    group_by(Species, character) %>% 
    summarise(
    n = n(),
    mean = mean(value),
    sd = sd(value),
    se = sd / sqrt(n),
    cv = (sd / mean) * 100
  ) 
`summarise()` has grouped output by 'Species'. You can override using the
`.groups` argument.
# A tibble: 4 × 7
# Groups:   Species [2]
  Species character     n   mean     sd     se    cv
  <chr>   <chr>     <int>  <dbl>  <dbl>  <dbl> <dbl>
1 holy    Area         20 34.2   5.53   1.24    16.2
2 holy    Thickness    20  0.415 0.108  0.0241  26.0
3 sweet   Area         20 23.7   3.93   0.880   16.6
4 sweet   Thickness    20  0.427 0.0716 0.0160  16.8

เราสามารถใช้ long format วาดกราฟหลาย ๆ อันพร้อมกันได้

leaf_long %>%
    ggplot(aes(x = Species, y = value)) +
    geom_boxplot() +
    facet_wrap(~ character, scale = "free_y")