整齊資料(tidy)搭配管線運算子(pipe operator)
- R 可以有不同寫作風格,不同套件也常可以做到同樣的事
- 近期趨勢是採用整齊資料(tidy)有關的資料整理套件與繪圖,並搭配管線運算子
整齊資料
- 整齊資料要求資料就是一個單純的長方形表格,橫邊對應分析單位(人或個體或事件),縱邊是變項
- 可以想成沒有亂加註解或是複雜表格的 EXCEL 或 SPSS 資料
- 大家講好整齊資料,程式就很好寫
- tidyverse 是個超級套件庫,包含了一堆以 tidy
規格設計的軟體,在資料處理與繪圖上非常方便,很多人使用
管線運算子
- 管線運算子就是水管,把資料導來導去
- 我們常常在資料加工再加工,會需要一堆臨時符號,搞到自己都看不懂
#整體設定,含載入套件
source("https://raw.githubusercontent.com/ChungPingCheng/R4BS2/main/R4BS_setup.R")
dta <- read.csv("https://raw.githubusercontent.com/ChungPingCheng/R4BS2/main/Data/HEXACO.csv", 
                na.strings='NA', stringsAsFactors = TRUE)
dta2 <- select(dta, where(is.factor)) 
head(dta2)
dta |> 
  dplyr::select(where(is.factor))|> 
  head()
 
資料整理範例
#整體設定,含載入套件
source("https://raw.githubusercontent.com/ChungPingCheng/R4BS2/main/R4BS_setup.R")
資料
資料來自於許功餘、張玉鈴(2015),討論性格向度與青少年問題間的關聯。性格模式包括六個向度(HEXACO):誠實/謙遜,情緒性,外向性,和悅性,嚴謹性與開放性。青少年問題則測量焦慮/憂鬱、社會退縮兩項內化問題行為,與違反規定以及攻擊行為兩類外化問題行為。
#讀檔案
dta <- read.csv("https://raw.githubusercontent.com/ChungPingCheng/R4BS2/main/Data/HEXACO.csv", na.strings='NA', stringsAsFactors = TRUE)
#檢視資料結構
#程式報表1.1
str(dta)
'data.frame':   1630 obs. of  14 variables:
 $ 國高中      : Factor w/ 2 levels "高中","國中": 1 1 1 1 1 1 1 1 1 1 ...
 $ 性別        : Factor w/ 2 levels "女","男": 2 1 2 2 NA 1 1 1 2 2 ...
 $ 父親教育程度: Factor w/ 5 levels "大學或專科","小學或不識字",..: 5 4 5 4 NA 2 4 4 2 1 ...
 $ 母親教育程度: Factor w/ 5 levels "大學或專科","小學或不識字",..: 5 5 4 4 NA 4 4 4 2 4 ...
 $ 誠實.謙遜   : int  48 60 53 48 56 61 53 66 55 58 ...
 $ 情緒性      : int  54 43 50 52 60 65 45 68 52 44 ...
 $ 外向性      : int  44 39 48 46 52 39 51 60 38 55 ...
 $ 和悅性      : int  50 55 47 50 49 47 51 48 55 54 ...
 $ 嚴謹性      : int  43 59 52 46 53 49 48 51 43 43 ...
 $ 開放性      : int  44 57 44 49 44 43 45 51 38 50 ...
 $ 攻擊行為    : int  13 2 1 12 4 NA 21 1 4 2 ...
 $ 焦慮.憂鬱   : int  11 2 0 9 2 6 14 6 5 1 ...
 $ 違反規定    : int  7 1 0 9 1 2 12 0 1 3 ...
 $ 社會退縮    : int  9 4 0 5 3 7 12 2 4 2 ...
| 國高中 | 性別 | 父親教育程度 | 母親教育程度 | 誠實.謙遜 | 情緒性 | 外向性 | 和悅性 | 嚴謹性 | 開放性 | 攻擊行為 | 焦慮.憂鬱 | 違反規定 | 社會退縮 | 
| 高中 | 男 | 國中 | 國中 | 48 | 54 | 44 | 50 | 43 | 44 | 13 | 11 | 7 | 9 | 
| 高中 | 女 | 高中 | 國中 | 60 | 43 | 39 | 55 | 59 | 57 | 2 | 2 | 1 | 4 | 
| 高中 | 男 | 國中 | 高中 | 53 | 50 | 48 | 47 | 52 | 44 | 1 | 0 | 0 | 0 | 
| 高中 | 男 | 高中 | 高中 | 48 | 52 | 46 | 50 | 46 | 49 | 12 | 9 | 9 | 5 | 
| 高中 | NA | NA | NA | 56 | 60 | 52 | 49 | 53 | 44 | 4 | 2 | 1 | 3 | 
| 高中 | 女 | 小學或不識字 | 高中 | 61 | 65 | 39 | 47 | 49 | 43 | NA | 6 | 2 | 7 | 
 
選取變項
選取變項方式一:利用資料型態
#本章主要利用 tidyverse 中的 dplyr 和 tidyr 兩個套件做資料處理  
#程式報表1.2
dta |> 
  dplyr::select(where(is.factor)) |> 
  head()
| 國高中 | 性別 | 父親教育程度 | 母親教育程度 | 
| 高中 | 男 | 國中 | 國中 | 
| 高中 | 女 | 高中 | 國中 | 
| 高中 | 男 | 國中 | 高中 | 
| 高中 | 男 | 高中 | 高中 | 
| 高中 | NA | NA | NA | 
| 高中 | 女 | 小學或不識字 | 高中 | 
選取變項方式二:利用變項名稱(部份)文字
#高誠實/謙遜個體出現較少違反規定的行為嗎?
dta |> 
  dplyr::select(contains(c('誠', '規'))) |> 
  cor(use='pair') |> 
  round(3)
|  | 誠實.謙遜 | 違反規定 | 
| 誠實.謙遜 | 1.00 | -0.38 | 
| 違反規定 | -0.38 | 1.00 | 
選取變項方式三:利用變項位置
#焦慮/憂鬱、社會退縮屬於內化問題行為
#違反規定、攻擊行為屬於外化問題行為
#我們將類別相同變項重排在一起
#程式報表1.3
dta |> 
  dplyr::select(c(11, 13, 12, 14)) |>
  cor(use='pair') |> 
  round(3)
|  | 攻擊行為 | 違反規定 | 焦慮.憂鬱 | 社會退縮 | 
| 攻擊行為 | 1.000 | 0.696 | 0.610 | 0.417 | 
| 違反規定 | 0.696 | 1.000 | 0.423 | 0.351 | 
| 焦慮.憂鬱 | 0.610 | 0.423 | 1.000 | 0.623 | 
| 社會退縮 | 0.417 | 0.351 | 0.623 | 1.000 | 
 
選取觀察值
選取觀察值(slice)方式一:利用列的位置
#程式報表1.4
dta |> 
  dplyr::slice(11:12) |> 
  dplyr::select(1:4) 
| 國高中 | 性別 | 父親教育程度 | 母親教育程度 | 
| 高中 | 女 | 研究所以上 | 大學或專科 | 
| 高中 | 男 | 高中 | 國中 | 
選取觀察值(slice)方式二:利用列的位置(隨機若干位)
#程式報表1.5
dta |> 
  dplyr::slice_sample(n=3) |> 
  dplyr::select(contains(c('親'))) 
| 父親教育程度 | 母親教育程度 | 
| 高中 | 高中 | 
| 高中 | 高中 | 
| 國中 | 國中 | 
篩選觀察值(filter)方式:指定變項與條件
dta |> 
  dplyr::filter(性別 == '男') |>
  dplyr::select(contains(c('誠', '規'))) |> 
  cor(use='pair') |> 
  round(3)
|  | 誠實.謙遜 | 違反規定 | 
| 誠實.謙遜 | 1.000 | -0.318 | 
| 違反規定 | -0.318 | 1.000 | 
篩選觀察值(filter)方式:可以同時利用多個條件篩選
dta |> 
  dplyr::filter(母親教育程度=='研究所以上',
                父親教育程度=='研究所以上') |>
  dplyr::select(性別) |> 
  table()
 
轉換變項,轉換變項值
#類別變項水準預設排列順序對應編碼大小,常常需要重排
#程式報表1.7前
with(dta, levels(母親教育程度))
[1] "大學或專科"   "小學或不識字" "研究所以上"   "高中"         "國中"        
變項轉換一:製造新變項
#程式報表1.7後
dta |> 
  dplyr::mutate(母教育 = forcats::fct_relevel(母親教育程度,
                                              c("小學或不識字", 
                                                "國中", 
                                                "高中", 
                                                "大學或專科", 
                                                "研究所以上")),
                父教育 = forcats::fct_relevel(父親教育程度,
                                              c("小學或不識字", 
                                                "國中", 
                                                "高中", 
                                                "大學或專科", 
                                                "研究所以上")),
                .keep='none') |> table()
|  | 小學或不識字 | 國中 | 高中 | 大學或專科 | 研究所以上 | 
| 小學或不識字 | 18 | 33 | 18 | 2 | 0 | 
| 國中 | 21 | 181 | 106 | 20 | 0 | 
| 高中 | 17 | 147 | 475 | 109 | 5 | 
| 大學或專科 | 2 | 15 | 60 | 245 | 31 | 
| 研究所以上 | 0 | 0 | 2 | 7 | 15 | 
變項轉換二:修改舊變項
dta <- dta |> 
  dplyr::mutate(母親教育程度 = forcats::fct_relevel(母親教育程度,
                                              c("小學或不識字", 
                                                "國中", 
                                                "高中", 
                                                "大學或專科", 
                                                "研究所以上")),
                父親教育程度 = forcats::fct_relevel(父親教育程度,
                                              c("小學或不識字", 
                                                "國中", 
                                                "高中", 
                                                "大學或專科", 
                                                "研究所以上")))
 
分組
分組,對各組做相同動作
tmp <- dta |> 
  dplyr::select(性別, 攻擊行為, 違反規定) |>
  dplyr::group_by(性別) |>
  dplyr::mutate(攻擊 = case_when(攻擊行為 < quantile(攻擊行為, prob=.33,
                                  na.rm = TRUE) ~ '1_低',
                         攻擊行為 > quantile(攻擊行為, prob=.67,
                                  na.rm = TRUE) ~ '3_高',
                         .default = '2_中'), 
                違規 = case_when(違反規定 < quantile(違反規定, prob=.33,
                                  na.rm = TRUE) ~ '1_低',
                          違反規定 > quantile(違反規定, prob=.67,
                                  na.rm = TRUE) ~ '3_高',
                         .default = '2_中'), .keep='unused') |> as.data.frame()
#剛剛資料作列聯表
#程式報表1.10
tmp |> ftable()
          違規 1_低 2_中 3_高
性別 攻擊                    
女   1_低        81  102   14
     2_中        30  237   72
     3_高         7   86  163
男   1_低       165   52   12
     2_中        72  199   81
     3_高        17   75  151
分組後合計
#合計:算相關
#reframe 會對每一組做同樣動作,並且存成資料框,以便後續利用方便
#剛剛為展示緣故,將連續變項轉成類別變項(通常不必要)做列聯表
#這邊直接針對連續變項求相關
#程式報表1.11
dta |> 
  dplyr::select(性別, 攻擊行為, 違反規定) |>
  dplyr::group_by(性別) |>
  dplyr::reframe(相關係數 = cor(攻擊行為, 違反規定, use='pair'),
                  合計 = n())
| 性別 | 相關係數 | 合計 | 
| 女 | 0.6711 | 792 | 
| 男 | 0.7097 | 824 | 
| NA | 0.6960 | 14 | 
#合計:算基本統計量
#程式報表1.12
dta |> 
  dplyr::group_by(性別) |>
  dplyr::reframe(違規平均 = mean(違反規定, na.rm = TRUE), 
                 違規標準差 = sd(違反規定, na.rm = TRUE),
                 違規中位數 = median(違反規定, na.rm=T), 
                 違規四分位距 = IQR(違反規定, na.rm=T),
                 合計 = n())  
| 性別 | 違規平均 | 違規標準差 | 違規中位數 | 違規四分位距 | 合計 | 
| 女 | 2.863 | 2.570 | 2.0 | 3.00 | 792 | 
| 男 | 4.335 | 3.211 | 4.0 | 4.00 | 824 | 
| NA | 5.214 | 4.475 | 4.5 | 4.75 | 14 | 
 
資料形式變換:寬形到長形
#為示範方便,先選出2筆、4個變項,總共8個數值
#程式報表1.13前
dta |> 
  dplyr::select(11:14) |> 
  dplyr::slice(1:2) |> 
  as_tibble(rownames="識別碼")
| 識別碼 | 攻擊行為 | 焦慮.憂鬱 | 違反規定 | 社會退縮 | 
| 1 | 13 | 11 | 7 | 9 | 
| 2 | 2 | 2 | 1 | 4 | 
#將剛剛資料轉成長形
#請上下對照並注意 id,看看剛剛8個數值現在如何排列
#程式報表1.13後
dta |> dplyr::select(攻擊行為:社會退縮) |> 
  dplyr::slice(1:2) |>
  as_tibble(rownames="識別碼") |>
  tidyr::pivot_longer(cols = -識別碼, 
                      names_to = '行為問題', values_to = '分數')
| 識別碼 | 行為問題 | 分數 | 
| 1 | 攻擊行為 | 13 | 
| 1 | 焦慮.憂鬱 | 11 | 
| 1 | 違反規定 | 7 | 
| 1 | 社會退縮 | 9 | 
| 2 | 攻擊行為 | 2 | 
| 2 | 焦慮.憂鬱 | 2 | 
| 2 | 違反規定 | 1 | 
| 2 | 社會退縮 | 4 | 
#利用 arrange指令,依性別排序
#程式報表1.14
dta |> dplyr::select(2, 11:14) |> 
  as_tibble(rownames="識別碼") |>
  tidyr::pivot_longer(cols = -c(識別碼, 性別),
                      names_to = '行為問題', values_to = '分數') |>
  dplyr::group_by(行為問題, 性別) |>
  dplyr::reframe(平均分數 = mean(分數, na.rm=T)) |> 
  dplyr::arrange(性別) |>
  dplyr::filter(性別 != 'NA')
| 行為問題 | 性別 | 平均分數 | 
| 攻擊行為 | 女 | 7.991 | 
| 焦慮.憂鬱 | 女 | 7.014 | 
| 社會退縮 | 女 | 4.589 | 
| 違反規定 | 女 | 2.863 | 
| 攻擊行為 | 男 | 9.166 | 
| 焦慮.憂鬱 | 男 | 6.128 | 
| 社會退縮 | 男 | 4.545 | 
| 違反規定 | 男 | 4.335 | 
#綜合應用,最後面將資料由長形變成寬形
#程式報表1.15
dta |> dplyr::select(2, c(11:14)) |> 
  as_tibble(rownames="id") |>
  tidyr::pivot_longer(cols = -c(id, 性別),
                      names_to = '行為問題', values_to = '分數') |>
  dplyr::group_by(行為問題, 性別) |>
  dplyr::reframe(平均分數 = mean(分數, na.rm=T)) |> 
  dplyr::filter(性別 != 'NA') |>
  tidyr::pivot_wider(names_from = '行為問題',
                     values_from = '平均分數')
| 性別 | 攻擊行為 | 焦慮.憂鬱 | 社會退縮 | 違反規定 | 
| 女 | 7.991 | 7.014 | 4.589 | 2.863 | 
| 男 | 9.166 | 6.128 | 4.545 | 4.335 | 
#綜合應用,計算以違反規定PR90分類學生時,女生所佔各類比率
dta |>
 dplyr::mutate(違規九 = 違反規定 > quantile(違反規定, prob = 0.9, na.rm=T)) |>
 dplyr::group_by(違規九, 性別) |>
 dplyr::reframe(合計 = n()) |>  
 pivot_wider(names_from=性別, 
             values_from=合計) |>
 dplyr::mutate(違規九分位 = 違規九, 
               女性百分率 = 100*(女 / (女+男)), .keep='none')  |>
 dplyr::filter(違規九分位 != 'NA')
| 違規九分位 | 女性百分率 | 
| FALSE | 51.36 | 
| TRUE | 27.39 | 
 
資料形式變換:長形到寬形
#綜合應用,不同母親教育程度、性別下,內化問題的平均
#程式報表1.16
dta |> 
  dplyr::select(性別, 母親教育程度, 社會退縮, 焦慮.憂鬱) |>
  tidyr::pivot_wider(names_from = '性別',
                     values_from = c('社會退縮', '焦慮.憂鬱'),
                     values_fn = ~ mean(.x, na.rm = TRUE)) |>
  dplyr::filter(母親教育程度 != 'NA') |>
  dplyr::select(-contains('NA')) |>
  dplyr::arrange(社會退縮_女)
| 母親教育程度 | 社會退縮_男 | 社會退縮_女 | 焦慮.憂鬱_男 | 焦慮.憂鬱_女 | 
| 研究所以上 | 4.846 | 3.800 | 7.000 | 7.100 | 
| 大學或專科 | 4.611 | 4.390 | 6.378 | 6.622 | 
| 高中 | 4.486 | 4.509 | 5.942 | 6.931 | 
| 國中 | 4.680 | 4.647 | 6.189 | 6.822 | 
| 小學或不識字 | 4.938 | 5.575 | 7.613 | 9.053 | 
 
繪圖範例
資料與管理
#讀檔案
dta <- read.csv(file = "https://raw.githubusercontent.com/ChungPingCheng/R4BS2/main/Data/HEXACO_HS.csv",header = TRUE, stringsAsFactors = TRUE)
#檢視資料結構
#程式報表2.1
str(dta)
'data.frame':   897 obs. of  13 variables:
 $ 性別        : Factor w/ 2 levels "女","男": 2 1 2 2 1 1 2 2 1 1 ...
 $ 父親教育程度: Factor w/ 5 levels "大學或專科","小學或不識字",..: 5 4 5 4 4 4 2 1 3 1 ...
 $ 母親教育程度: Factor w/ 5 levels "大學或專科","小學或不識字",..: 5 5 4 4 4 4 2 4 1 4 ...
 $ 誠實.謙遜   : int  48 60 53 48 53 66 55 58 51 58 ...
 $ 情緒性      : int  54 43 50 52 45 68 52 44 57 62 ...
 $ 外向性      : int  44 39 48 46 51 60 38 55 54 67 ...
 $ 和悅性      : int  50 55 47 50 51 48 55 54 51 61 ...
 $ 嚴謹性      : int  43 59 52 46 48 51 43 43 50 53 ...
 $ 開放性      : int  44 57 44 49 45 51 38 50 50 52 ...
 $ 攻擊行為    : int  13 2 1 12 21 1 4 2 8 4 ...
 $ 焦慮.憂鬱   : int  11 2 0 9 14 6 5 1 6 4 ...
 $ 違反規定    : int  7 1 0 9 12 0 1 3 4 3 ...
 $ 社會退縮    : int  9 4 0 5 12 2 4 2 5 0 ...
#設定類別變項的順序
dta <- dta |> 
  dplyr::mutate(母親教育程度 = forcats::fct_relevel(母親教育程度, 
                                              c("小學或不識字", 
                                                "國中", 
                                                "高中", 
                                                "大學或專科", 
                                                "研究所以上")),
                父親教育程度 = forcats::fct_relevel(父親教育程度, 
                                              c("小學或不識字", 
                                                "國中", 
                                                "高中", 
                                                "大學或專科", 
                                                "研究所以上")))
 
一步一步填滿圖層
#ggplot 是一個一個圖層(layer)疊上去
#底下以散佈圖為例,呈現每一步驟的結果
#第一步驟設定圖的框架,注意圖的X軸與Y軸
#圖2.1
g0 <- ggplot(data = dta, 
             aes(x=社會退縮, y=攻擊行為)) 
g0

#在前一步驟結果(圖的框架)上加入點
#圖2.2
g1 <- g0 + geom_point(alpha=.2) 
g1

#在前一步驟結果上加入橢圓(資料的95%區間)與局部迴歸線
#圖2.3
g2 <- g1 + stat_smooth(method='lm', 
                       formula = y ~ x,
                       se=FALSE, 
                       linewidth = 0.5) 
g2

#在前一步驟結果上要求以變項(性別)區分顏色
#圖2.4
g3 <- g2 + aes(color=性別) 
g3

#在前一步驟結果上設定 x 軸與 y 軸刻度
#圖2.5
g4 <- g3 + 
  scale_y_continuous(breaks=seq(0, 25, by=5)) +
  scale_x_continuous(breaks=seq(0, 12, by=2))
g4

#在前一步驟結果上要求以變項(父母教育)分面(facet)
#圖2.6
g5 <- g4 + facet_wrap(vars(母親教育程度),nrow=1)
g5

#在前一步驟結果上加上X軸、Y軸的標示,以及整個圖形的標題
#圖2.7
g6 <- g5 + labs(x='社會退縮分數',
                y='攻擊行為分數',
                title='散布圖:攻擊行為與社會退縮')
g6

#在前一步驟結果上改變主題,並要求圖示位置
#圖2.8
g7 <- g6 + theme_minimal() + 
  theme(legend.position='top')
g7

#前面步驟可以一次執行
ggplot(data = dta, aes(x=社會退縮, y=攻擊行為)) +
   geom_point(alpha=.2) +
 stat_smooth(method='lm', formula = y ~ x,
       se=FALSE, linewidth = 0.5)+
 aes(color=性別) +
 scale_y_continuous(breaks=seq(0, 25, by=5)) +
 scale_x_continuous(breaks=seq(0, 12, by=2)) +
 facet_wrap(vars(母親教育程度),nrow=1)+
 labs(x='社會退縮分數', y='攻擊行為分數',
     title='散布圖:攻擊行為與社會退縮') +
 theme_minimal() + 
 theme(legend.position='top')

 
繪製統計摘要
以 ggplot
直接繪製統計摘要結果(連續資料平均數與標準誤)
#圖2.9
ggplot(data=dta, 
     aes(x=母親教育程度, y=誠實.謙遜, color=性別)) +
  stat_summary(fun.data = "mean_cl_boot", 
               position=position_dodge(.2)) +
  stat_summary(aes(group=性別), fun = mean, 
               geom="line",
               position=position_dodge(.2))+
  scale_color_grey(end=.7)+
  labs(y='誠實.謙遜平均分數',
       x='母親教育程度',
       title='不同性別的誠實.謙遜平均跟母親教育程度的關係',
       caption="來源: 許功餘")+
  theme(legend.position='top')

以 ggplot
直接繪製統計摘要結果(類別資料的百分比)
#圖2.10
ggplot(dta, 
       aes(x=母親教育程度, group=父親教育程度)) + 
  geom_bar(aes(y=after_stat(prop), 
          fill = factor(after_stat(x))),
          width = .2) + 
  scale_y_continuous(labels=scales::percent) +
  scale_fill_grey()+
  coord_flip()+
  labs(y="百分比",
       title="門當戶對:父母親教育程度") +
  facet_wrap(vars(父親教育程度), ncol=1)+
  theme(legend.position="none")

以
ggplot 直接繪製統計摘要結果(連續資料平均數與標準誤)
#圖2.11
ggplot(data=dta, 
     aes(x=母親教育程度, y=誠實.謙遜)) +
  stat_summary(fun.data = "mean_cl_boot") +
  scale_color_grey(end=.7)+
  facet_wrap(vars(父親教育程度), nrow=1)+
  labs(y='誠實.謙遜平均分數',
       x='母親教育程度',
       title='不同父親教育程度的誠實.謙遜平均跟母親教育程度的關係',
       caption="來源: 許功餘")+
  theme(legend.position='top',
        axis.text.x = element_text(angle = 90, vjust = 0.5, hjust=1))
Warning: Removed 1 rows containing missing values (`geom_segment()`).
Removed 1 rows containing missing values (`geom_segment()`).
Removed 1 rows containing missing values (`geom_segment()`).

 
多變量圖形,利用寬轉長
#多變量圖形 
#圖2.12,dpi=300
dta |> tidyr::pivot_longer(cols=4:9, 
                           names_to = '人格維度',
                           values_to = '分數') |>
  ggplot()+
  aes(x=違反規定, y=分數, color=性別)+
  geom_point(size=rel(.5))+
  stat_smooth(method='lm', 
              formula = y ~ x,
              se=F, linewidth=.5)+
  facet_grid(人格維度 ~ 母親教育程度) +
  scale_color_grey(start=.1, end=.6)+
  labs(x="違反規定分數",
       y="人格維度分數")+
  theme(legend.position='top')

 
延伸
#同時繪製兩個變項的散布圖,以及各自的邊際分布
#圖2.13
p <- ggplot(dta, 
            aes(x=誠實.謙遜, y=違反規定)) +
  geom_point(shape=21, alpha=.5) +
  stat_ellipse() +
  geom_vline(xintercept=mean(dta$誠實.謙遜), col="gray") +
  geom_hline(yintercept=mean(dta$違反規定), col="gray") +
  stat_smooth(method="lm", 
              formula = y ~ x,
              linewidth=.7,
              linetype="dotted",
              se=FALSE,
              alpha=.5,
              col=1) +
  labs(y="違反規定分數", 
       x="誠實.謙遜分數") 
pacman::p_load(ggExtra, KernSmooth)
ggMarginal(p, 
           type="histogram",
           xparams=list(binwidth=dpih(dta$誠實.謙遜),
                          fill="gray90"),
           yparams=list(binwidth=dpih(dta$違反規定),
                          fill="gray90"))
