[R語言圖表]用ggplot視覺化李克特量表資料 likert scale data

0

Last Updated on 2023-10-31

Home » R語言教學 » 資料視覺化 » [R語言圖表]用ggplot視覺化李克特量表資料 likert scale data

你想用圖表呈現李克特量表(likert scale)的資料嗎?用 ggplot2 帶你畫!


在問卷中使用李克特量表(likert scale)調查受試者態度或意見,但是不知道怎麼視覺化調查結果嗎?聽人家說堆疊發散長條圖(diverging stacked bar chart)可以派上用場,但不知道怎麼畫?

我會在這篇文章介紹如何活用R語言的套件ggplot2,配上實際程式碼,帶你畫出可以處理李克特量表資料的堆疊發散長條圖。

李克特量表 likert scale 是什麼?

李克特量表(likert scale)是一種常見於問卷調查中,用來評估填答者對特定觀點或者陳述態度的測量工具。

舉個簡單的例子,「你對執政黨過去 4 年的執政表現滿意度如何?選項共有 5 個:非常不滿意、不滿意、普通、滿意、非常滿意」,這種讓你從序列中選取選項的問題,就是李克特量表。

它的測量方法簡單而且直觀,可以讓填問卷的人表達自己對於特定語句的同意程度或喜好程度。

跟常見的二元對立(是/不是)比起來,它提供的資訊更加細緻,而且讓回答者從序列中挑選答案,可以蒐集到強度。

不過,如同上面所說,因為它是序列,所以概念類似於名次,沒辦法具體量化選項之間的差異。

舉例來說,有個人填了非常不滿意,他的內心可能給分是 40 分,另一個人給了普通,但其實他的普通是 80 分,這就是李克特量表的限制。

問卷填答者回答問卷的時候,根據自己對每句陳述的態度或意見,選擇最符合觀點的評分,那設計問卷的人要怎麼得到結果呢?

通常有兩種方式。

第一種是計算整體態度或意見的平均值,例如在 1 – 5 分,平均拿到了 3.5 分。

第二種則是查看分佈情況,例如有 20% 的人非常不滿意、40% 的人不滿意,剩下 20% 的人覺得普通。

不管是學術上的心理學量表,或是商業上的市場調查,還有學生寫報告的研究,都會用到李克特量表。

那麼,要怎麼視覺化李克特量表資料呢?

堆疊發散長條圖 diverging stacked bar chart 是什麼?

什麼是堆疊發散長條圖(diverging stacked bar chart)?「我也是看報紙才知道!」

堆疊發散長條圖,是一種常用於視覺化問卷調查中李克特量表(Likert scale)資料的圖表形式。

為了方便解釋,先給大家看堆疊發散長條圖的實際長相。

李克特量表範例 - 浪姐舞台

以堆疊發散長條圖呈現李克特量表的例子

先來拆解名字,它是一種長條圖,以堆疊的形式排列,而且不像一般的長條圖會從 y 軸出發,它是發散的

從圖中我們可以發現,堆疊發散長條圖能夠清楚展示出不同選項的回答分布,也能方便我們直接比較,這樣可以快速理解問卷填寫者對於選項(這邊是表演舞台)的態度。

你可以很容易想像,它不只能夠呈現上圖的排名,也能呈現像是不滿意到滿意的偏好,像是下圖。

李克特量表範例 - 網路範例

以堆疊發散長條圖呈現李克特量表的另一些例子

從這些圖,我們能觀察到什麼重點?

第一,它是分散的(divergent)。

為什麼不要都從 0 開始?因為像是上圖中中間下方的那個例子,你會發現,從 0 開始其實很難比較比例

第二,既然要分散,那要以什麼為標準當作中心呢?

以右邊的大圖來看,它是以「滿意序列」中的中間點 “normal” 為中心。

在我上面的浪姐圖表中,因為有 8 個名次,因此是以第 4 和 5 名的正中央為中心。

第三,找出中點之後,右邊放正向的選項,左邊則放負向的選項。

如果是排名,右邊放前面的名次,左邊則放後面的名次。

第四,要特別注意顏色。不滿意和滿意的顏色絕對不會一樣,第 1 名和第 8 名的顏色也會有差異。

從這兩個範例來看,我們可以看出堆疊發散長條圖的繪製重點:分散、有中點、有正負、用顏色呈現差異

繪製堆疊發散長條圖的時候,我們想檢視分布情形的變數,也就是排名或者選項的累積比例會映射(mapping,指的是想呈現的變量對應到圖表中的表示方法)到 x 軸,不同的組別則映射到 y 軸。

在 R 語言中,很遺憾地,使用 ggplot2 套件,沒辦法輕鬆簡單的畫出堆疊發散長條圖。

但我們沒有放棄,還是找到方法完成了。底下會一步一步帶大家實作。

實作篇

資料長相

我們先來匯入資料。

從底下的表格可以看到,這份資料有 98 個資料點。

第一個欄位 reply_id 代表著問卷回覆者的 ID。

後面的八個欄位分別代表《乘風2023》(或稱《浪姐4》)第二次公演的八個舞台。

這題的設定是讓填寫問卷者將八場表演排出第 1 到 8 名。

library(tidyverse)
df_stage_vote <- read_csv("data/df_stage_vote.csv")
df_stage_vote %>% head(5)
#> # A tibble: 5 × 9
#>   reply_id `《帶我去找夜生活》` `《我離開我自己》` `《一起吃苦的幸福》`
#>      <dbl>                <dbl>              <dbl>                <dbl>
#> 1        1                    7                  4                    5
#> 2        2                    4                  6                    5
#> 3        3                    7                  2                    1
#> 4        4                    4                  2                    6
#> 5        5                    8                  2                    4
#> # ℹ 5 more variables: `《面紗》` <dbl>, `《Levitating》` <dbl>,
#> #   `《迷迭香》` <dbl>, `《開往早晨的午夜》` <dbl>, `《從頭》` <dbl>

先從專門的 likert 套件開始

在使用強大的 library(ggplot) 之前,我們要先利用專用的 library(likert) 繪製圖表。

下方程式碼看起來很複雜,但其實我只是把 reply_id 拿掉,另外把欄位變成因素,為後面步驟鋪路而已。

我有展示 item_agg 的內容,其實它幾乎等同於 dataframe 版本的 df_stage_vote,只是因為 library(likert) 不接受 tibble 格式,才會出此下策。

library(likert)
rank_level <- rev(as.character(c(1:8)))
item_agg <- df_stage_vote %>%
  select(-reply_id) %>% mutate(across(everything(), ~as.factor(.))) %>%
  mutate(across(everything(), ~fct_expand(., rank_level))) %>%
  mutate(across(everything(), ~fct_relevel(., rank_level))) %>%
  as.data.frame()

item_agg %>% as_tibble() %>% head(5)
#> # A tibble: 5 × 8
#>   `《帶我去找夜生活》` `《我離開我自己》` `《一起吃苦的幸福》` `《面紗》`
#>   <fct>                <fct>              <fct>                <fct>     
#> 1 7                    4                  5                    8         
#> 2 4                    6                  5                    8         
#> 3 7                    2                  1                    8         
#> 4 4                    2                  6                    7         
#> 5 8                    2                  4                    7         
#> # ℹ 4 more variables: `《Levitating》` <fct>, `《迷迭香》` <fct>,
#> #   `《開往早晨的午夜》` <fct>, `《從頭》` <fct>

那我們就來看 likert(),會把 item_agg 變成什麼樣子吧!

利用 base R 的繪圖系統,我們用 plot() 畫出了結果。

p_agg <- likert(item_agg)

### base R plot
plot(p_agg, family = "Noto Sans TC Black")

使用 likert 套件和 base R 繪圖系統的成品

老實說這張圖非常清楚!

它完全做到我們先前所說,分散、有中點、有正負、用顏色呈現差異

而且更貼心的事情在於,這些全都是自動完成。

我們沒有自己喬分散位置、沒有找中點,沒有特別分正負,更沒有指定顏色。

而且 library(likert) 更貼心的幫忙計算正負各自的比例!

當然,我們不會滿意在止步於此。

作為 ggplot 愛好者的我,會在底下展示如何重繪這張圖。

利用 ggplot 視覺化李克特量表

因為 likert() 這個函數實際上幫我們做好轉換,所以我們從產出 p_agg 中抽出資料。

再把它從寬表格轉成 ggplot 友善的長表格。

不過,本來 p_agg 裡面的資料是百分比,所以 20% 會用 20 呈現,我們多做一個除法步驟,讓它變成真的 20%。

### 底下是 ggplot2
p_agg_long <- p_agg$results %>% as_tibble() %>%
  # 寬表格轉長表格
  pivot_longer(cols = -1, names_to = "variable", values_to = "value") %>%
  # 改名字
  rename(stage_order = 1) %>%
  # 為了比例
  mutate(value = value/100)

p_agg_long %>% sample_n(5)
#> # A tibble: 5 × 3
#>   stage_order        variable  value
#>   <chr>              <chr>     <dbl>
#> 1 《迷迭香》         3        0.194 
#> 2 《帶我去找夜生活》 3        0.122 
#> 3 《帶我去找夜生活》 4        0.173 
#> 4 《面紗》           2        0.0102
#> 5 《從頭》           1        0.255

下一步最關鍵。

因為 likert() 幫我們完成分散、有中點、有正負、用顏色呈現差異這幾件事情,但現在得要靠自己了。

為了做到這幾點,我們要搞定幾件事情。

如果要在 ggplot 的邏輯之下繪圖,我們可以試著把堆疊發散長條圖分成兩塊

以這張圖來說,就是把 4 和 5 名當成中點,右邊一塊,左邊一塊。

因此,我們也要把資料分成兩半,右邊一半是前 4 名,左邊一半是後 4 名。

底下就是實作的過程。你可以注意到,使用了 fct_relevel() 相關的函數,這是為了繪圖的排序用。

### 比誰前3名票數最多
stage_level <- p_agg_long %>% filter(variable <= 3) %>%
  group_by(stage_order) %>% summarise(value = sum(value)) %>% 
  pull(stage_order) %>% rev()

df_high <- p_agg_long %>%
  filter(variable <= 4) %>%
  mutate(variable = fct_relevel(variable, c("1","2","3","4"))) %>%
  arrange(variable) %>%
  mutate(stage_order = fct_relevel(stage_order, stage_level))

df_low <- p_agg_long %>%
  filter(variable >= 5) %>%
  mutate(value = -value) %>%
  mutate(variable = fct_relevel(variable, c("8","7","6","5"))) %>%
  arrange(variable) %>%
  mutate(stage_order = fct_relevel(stage_order, stage_level))

接下來就可以真的開始畫圖了,不過在那之前我們先指定一下顏色。

legend.pal <- c("8" = "#440154FF",
                "7" = "#46337EFF",
                "6" = "#365C8DFF",
                "5" = "#277F8EFF",
                "4" = "#1FA187FF",
                "3" = "#4AC16DFF",
                "2" = "#9FDA3AFF",
                "1" = "#FDE725FF")

從下方的程式碼中,我們重複利用了 geom_bar(),疊加了 2 次的資料。

另外,geom_hline()則幫助我們在中間點畫下白線,作為中間點的分界,但這步並非必要。

顏色部分,我們利用前面看過的 variable 函數,也就是排名變數,呈現 8 個名次的顏色。

ggplot() + 
  geom_bar(data=df_high, aes(x = stage_order, y=value, fill=variable), position="stack", stat="identity", width = 0.75) +
  geom_bar(data=df_low, aes(x = stage_order, y=value, fill=variable), position="stack", stat="identity", width = 0.75) +
  geom_hline(yintercept = 0, color =c("white")) +
  scale_y_continuous(labels = scales::label_percent(accuracy = 1), breaks = seq(-0.75,0.75,0.25)) +
  scale_fill_manual("order", values = legend.pal, guide="legend") +
  coord_flip() +
  labs(x= "",y= "", 
       fill = "排名",
       title = "眾舞台中《面紗》明顯落後",
       subtitle = "《浪姐4》各舞台排序票數占比, 按前後半票數占比由高到低排") +
  guides(fill=guide_legend(title="",nrow=1,byrow=TRUE)) +
  theme() +
  theme(text = element_text(family = "Noto Sans TC Medium"),
        plot.title = element_text(family = "Noto Sans TC Medium", face = "plain", size = 16), 
        legend.position = "bottom",
        legend.title = element_text(family = "Noto Sans TC Medium"),
        legend.text = element_text(family = "Noto Sans TC Medium", face = "plain"), 
        axis.title = element_text(family = "Noto Sans TC Medium", face = "plain", size = 12),
        axis.text.y = element_text(family = "Noto Sans TC Medium", face = "plain", size=10))

使用 likert 套件和 ggplot 繪圖系統的成品

這張圖表是不是能夠精準地呈現了排名呢?

同樣的,如果是有 7 個、9 個名次或者態度,也能用同種方式處理。

小結

在這篇文章中,我們嘗試畫了一張堆疊發散長條圖(diverging stacked bar chart)。

在文章中展示了 likertggplot,兩種繪圖方式,要選哪一種都可以。

因為問卷中實在太常出現李克特量表(likert scale),才會在此展示繪圖手段。

記得在學校時同學問我怎麼視覺化李克特量表的時候,開始研究具體解法。

一開始也是利用 likert,後來花了一些時間想辦法用 ggplot 拼出來,有很大的成就感!

因此,希望你會喜歡這篇文章,也能夠增添對於 ggplot2 的認識,並且學到東西!

No Comments

Leave a Reply