---
title: "soc_stat_demo"
author: "Eli Lin"
date: "2023-11-14"
output:
beamer_presentation: default
ioslides_presentation:
fig_width: 30
fig_height: 30
fig_caption: yes
slidy_presentation: default
---
```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = FALSE)
```
<iframe style="border-radius:12px" src="https://open.spotify.com/embed/playlist/37i9dQZF1DX5trt9i14X7j?utm_source=generator&theme=0" width="100%" height="352" frameBorder="0" allowfullscreen allow="autoplay; clipboard-write; encrypted-media; fullscreen; picture-in-picture" loading="lazy">
</iframe>
# R Basic
> 2023清大人社秋季社會統計 [name=Eli Lin]
## Why R
- 用途廣泛,可用於社會統計、資料科學、機器學習、自然語言處理......
- 開源社群的力量、學習、求助資源豐富
- 簡單、好懂
## Mindset
- 這是人寫出來給人用的,你一定能搞懂(大概啦)
- code海無涯,唯Google是岸,還能找copilot幫開船
- 寫自己的筆記
- 請練習
## Learning Resources
- **不要去什麼hahow之類的給人當韭菜割**
- [Stackoverflow](https://stackoverflow.com/)
- [Edx](https://www.edx.org/learn/r-programming/harvard-university-data-science-r-basics?index=product&queryID=e2a15d51e39a3dd02da1dc5ea276aaef&position=1&results_level=first-level-results&term=r+basic&objectID=course-91f52ef3-fa3f-4934-9d19-8d5a32635cd4&campaign=Data+Science%3A+R+Basics&source=edX&product_category=course&placement_url=https%3A%2F%2Fwww.edx.org%2Fsearchhttps://)
- [github上的學習資源整理](https://github.com/ujjwalkarn/DataScienceR)
- [隨便找的筆記](https://biocorecrg.github.io/CRG_RIntroduction/)
- [隨便找的筆記2](https://bookdown.org/b08302310/R_learning_notes/)
- [datacamp互動式練習](https://app.datacamp.com/learn/courses/free-introduction-to-r)
- [tidyverse](https://app.datacamp.com/learn/courses/introduction-to-the-tidyverse)
- [sjplot](https://strengejacke.github.io/sjPlot/)
- [台大郭耀仁教授](https://bookdown.org/tonykuoyj/eloquentr/) \# 注意nesting函式寫法不同
- [Descriptive statistics in R](https://statsandr.com/blog/descriptive-statistics-in-r/)
- [Quick list of useful R packages](https://support.posit.co/hc/en-us/articles/201057987-Quick-list-of-useful-R-packages)
- [Rstudio hot keys](https://support.rstudio.com/hc/en-us/articles/200711853-Keyboard-Shortcuts)
## Installation, Environment, and Settings
- R是程式語言, Rstudio是IDE
- 把CRAN mirror改成NTU
- [CRAN NTU mirror](https://cran.csie.ntu.edu.tw/)
- [Rstudio](https://posit.co/downloads/)
- environment: grid/ list
- 不建議保留.Rdata (global options \> general \> workspace \> uncheck "restore .Rdata..." and chose never save .Rdata)
- new project and setting directory
```{r eval=FALSE, include=FALSE}
getwd()
# setwd(dir = "") 要用"/",不要用"\"
```
## Panels
- console
- environment
- editor/ viewer
- packages/ help/ file viewer
## Hot Keys
- 不同版本或是安裝不同套件可能會改變快捷鍵的設定
- tools \> modify keyboard shortcuts
- ctrl + S save file
- ctrl + L clear console
- crtl + shift + enter run all
- tab 操作snippets
- ctrl + tab 切換分頁
- ctrl + w 關閉分頁
- alt + - 輸入賦值符號"\<-"
- ctrl + shift + F10 重啟R, detach套件, 並清除環境
## Style, Code Etiquette and Good Habit
- 易讀,減少錯誤
- [style](https://bookdown.org/tonykuoyj/eloquentr/styleguide.html)
- [style, code etiquette](https://style.tidyverse.org/syntax.html)
- 寫code好習慣,要保留的東西就要寫在script或是markdown裡面,不要留在console
## There are many ways to do things.
同樣是讀取spss檔案,有很多種方式可以做到,差別在於不同套件提供的功能跟方法可能不一樣
```{r eval=FALSE, include=FALSE}
foreign::read.spss() # 從foreign套件呼叫read.spss()函式
# v.s
haven::read_sav() #轉換成tibble的df格式
# v.s
sjlabelled::read_spss()
```
```{r eval=FALSE, include=FALSE}
utils::View()
# v.s
tibble::View()
```
## Packages
```{r eval=FALSE, include=FALSE}
# 安裝套件
install.packages("tidyverse") #記得引號
```
```{r eval=FALSE, include=FALSE}
# 載入套件
library(tidyverse)
```
- tidyverse 廣泛被使用的整合套件
- ggplot2 作圖
- dplyr 資料整理
- tidyr 表格轉換
- readr 資料載入
- tibble 另一種資料格式
- sjplot
- sjlabelled:讀取處理有標籤格式資料檔與變數
- sjPlot:製圖
- sjmisc:變數描述與編碼
- Sjstats:模型統計量的計算
- haven 讀取spss, stat檔案 (tibble格式)
- readrxl 讀取excle檔案
- foreign 讀取spss, stat檔案 (data.frame格式)
- [Quick list of useful R packages](https://support.posit.co/hc/en-us/articles/201057987-Quick-list-of-useful-R-packages)
## Basic Syntax
賦值 with "\<-"
"=" 也可以用來賦值,但是不建議使用,因為會跟函式的參數混淆
```{r eval=FALSE, include=FALSE}
# 這是註解,不會被執行
number_of_students <- 30 #將數值30,賦值給物件number_of_students
name <- "陳明祺" #將字串"陳明祺",賦值給物件name
# ==================================================
library(foreign) #載入foreign套件
w5_taiwan <- read.spss("W5_Taiwan_coreQrelease_20190805.sav", to.data.frame = TRUE)
#將W5_Taiwan_coreQrelease_20190805.sav檔案,賦值給物件w5_taiwan
```
連接行 "+"
```{r}
A <- 1 + 2 + 3 +
4 + 5
A
# 雖然結果正確,但這樣的寫法降低了易讀性
```
```{r}
B <- 1 + 2 + 3 #R以為計算結束了,所以不會一併執行下一行
+ 4 + 5
B
```
引號代表字串
```{r}
A <- 87
B <- "87"
```
```{r}
class(A)
```
```{r}
class(B)
```
## 存取符號(Accessors)
```{r}
data("airquality") #從內建資料集中載入airquality資料集
View(airquality) #查看airquality資料集
```
```{r}
temperature <- airquality$Temp #將airquality資料集中的Temp變數,賦值給物件temperature
```
```{r}
sequence <- c(0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144)
#將數值向量c(0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144),賦值給物件sequence
sequence[1] #存取sequence物件中的第一個元素
sequence[2:4] #存取sequence物件中的第二到四個元素
# 注意:與其他程式語言不同,R的索引值是從1開始,而不是0
```
## R reads your codes by "sentence"
R的console「大致上」會一行一行的執行你的程式碼,但更準確來說,R是「一句一句」的執行你的程式碼,而在R語言中,大多數的情況是以換行作為「句號」。
```{r}
A <- 1
B <- 2
print(A)
A <- 87
print(A)
```
```{r}
power_status <- FALSE
if (power_status == TRUE) {
print("清華大學")
} else {
print("清寒大學")
}
```
## Function
請養成閱讀說明文件的好習慣
```{r}
data("airquality") # 從內建資料集中載入airquality資料集
mean(airquality$Ozone, na.rm = TRUE) # 計算airquality資料集中的Ozone變數的平均值
```
```{r}
help("mean") #尋找mean函式的說明文件
```
```{r}
??mean
```
舉例mean()這個函式的使用方法
```{r}
example("mean")
```
```{r}
mean(airquality$Ozone, na.rm = TRUE) #計算airquality資料集中的Ozone變數的平均值,並忽略遺漏值
```
```{r}
mean(airquality$Ozone, trim = 0.1, na.rm = TRUE)
# 計算airquality資料集中的Ozone變數的平均值,並忽略遺漏值,且忽略最大與最小的10%數值(排除極端值)
```
## Data Types
| 資料類型 | 資料類型在R的英文 | 舉例 |
|----------|-------------------|------------|
| 字串 | character | "陳明祺" |
| 數值 | numeric | 2 |
| 整數 | integer | 2L |
| 邏輯值 | logical | TRUE |
| 日期 | Date | Sys.Date() |
| 時間 | POSIXct POSIXt | Sys.time() |
- 整數
```{r}
integer <- 87L
class(integer)
```
- coercion
```{r}
integer + 2L
x <- integer + 3
class(x)
```
- logical
```{r}
is.numeric("89") #判斷integer物件是否為數值
```
```{r}
date <- Sys.Date()
class(date)
```
```{r}
class(airquality)
typeof(airquality)
```
[mode跟class的差別](https://rpubs.com/kalipradeep/mode_vs_class) [mode, class and typeof](https://stackoverflow.com/questions/35445112/what-is-the-difference-between-mode-and-class-in-r)
## Data Structure
### 向量 vector
- 一個向量內必須是同一種資料類型
```{r}
height <- c(180, 170, 160)
print(height)
```
- 向量可以以索引值存取
```{r}
height[1]
```
- 向量可以有名字
```{r}
names(height) <- c("Armin", "Eren", "Mikasa")
```
- 向量可以用名字來當索引值
```{r}
height["Armin"]
```
### 矩陣 matrix
matrix是有維度的vector,也就是說,一個矩陣可以有多個row跟column,而且每個row跟column的資料類型必須相同(可以有例外,但會讓資料很難處裡)。
- 以matrix函式來建立矩陣,matrix函式的參數有以下幾個:
```{r}
num_matrix <- matrix(1:88,
nrow = 8,
byrow = TRUE,
dimnames = list(c("A","B","C","D","E","F","G","H"),
c("a","b","c","d","e","f","g","h","i","j","k")))
print(num_matrix)
```
- 從vector轉換成matrix
```{r}
survey_corps <- c("Eren", "Mikasa", "Armin","Levi", "Erwin", "Hange", "Jean", "Connie", "Sasha", "Historia")
dim(survey_corps) <- c(2, 5)
print(survey_corps)
```
- 從matrix轉換成vector
```{r}
as.vector(survey_corps) # by column
```
```{r}
as.vector(t(survey_corps)) # by row, t()是轉置矩陣的函式
```
### 陣列 array
array是有多個維度的matrix,統計中不好用也很少用,知道就好。
- 用array函式建立陣列,array函式的參數有以下幾個:
```{r}
num_array <- array(1:24,
dim = c(2, 5, 2),
dimnames = list(c("A","B"),
c("a","b","c","d","e"),
c("first","second")))
list(num_array)
```
- 修改matrix的dimension屬性,從matrix轉換成array
```{r}
dim(survey_corps) <- c(1, 5, 2)
list(survey_corps)
```
```{r}
class(survey_corps)
```
### 清單 list
list是一個可以儲存不同資料類型的向量,也就是說,list可以儲存向量、矩陣、陣列、資料框、函式等等。
```{r}
paradise_island <- list(names = survey_corps, height = height, matrix = num_matrix, array = num_array)
paradise_island[[1]]
paradise_island[[2]]
paradise_island
```
### 資料框 data.frame
- 從matrix轉換成data.frame
```{r}
survey_corps_df <- as.data.frame(survey_corps)
View(survey_corps_df)
```
```{r}
library(sjlabelled)
w5 <- read_spss("W5_Taiwan_coreQrelease_20190805.sav")
```
### 因子 factor
用於儲存類別(categorical)變項,可以設定level來表示順序(ordinal)別的變數
```{r}
likert_scale <- factor(c("Strongly disagree", "Disagree", "Neutral", "Agree", "Strongly agree"),
ordered = TRUE, # 有順序
levels = c("Strongly disagree", "Disagree", "Neutral", "Agree", "Strongly agree")) # level的順序
```
```{r}
likert_scale
```
## Data Processing
在社會科學統計裡面,我們經常需要進行標籤(labeled)資料的處理。因為一個變項的屬性通常相當複雜,例如婚姻狀況可能包含未婚、已婚、離婚、喪偶、分居、拒答、漏答等等不同的屬性;此時在資料處理上將不同的屬性(回答)編號,再透過標籤描述屬性會是最常見的做法。而R基本套件跟sjplot系列套件都可以處理標籤資料,我們接下來用台灣社會變遷調查2020q1的資料集來進行範例。
### 載入資料集
讀取.sav
```{r}
library(sjlabelled) #載入sjlabelled套件
tscs2020q1_sj <- read_spss("tscs2020q1.sav", en = "big-5") #載入tscs2020Q1.sav檔案,存入物件tscs2020q1
```
讀取.xls或是.xlsx
```{r}
library(readxl) #載入readxl套件
tscs2020q1_excel <- read_excel("test_excel.xlsx") #載入tscs2020Q1.xlsx檔案,存入物件tscs2020q1
```
讀取.dta
```{r}
library(sjlabelled) #載入sjlabelled套件
tscs2020q1_dta <- read_stata("tscs2020q1.dta") #載入tscs2020Q1.dta檔案,存入物件tscs2020q1
```
把資料集存成檔案
```{r}
library(sjlabelled)
write_spss(tscs2020q1_dta, "tscs2020q1_new.sav") #存成.sav檔案
```
或是
```{r}
save(tscs2020q1_sj, file = "tscs2020q1_new.rda") #存成R語言原生資料格式.rda檔案
```
### 怎麼弄清楚資料的標籤跟對應屬性?
- 查資料集的codebook
- 但可能沒有,或是資料集本身編碼不一致
- 此時就不建議對整個資料集做編碼/標籤的處理 (例如不同變項的遺漏值可能設定不同)
- 要單獨查特定變項中的標籤與對應的值
- 用attributes函式檢查物件的屬性
```{r}
x <- attributes(tscs2020q1_sj$v17) #檢查tscs2020q1是否有標籤
x # 輸出list
```
```{r}
View(x$labels)
```
- 用sjlabelled套件的方法
```{r}
lables_of_v7a <- get_labels(tscs2020q1_sj$v7a, values = "p") #注意是get_labels函式,不是get_label,後者只會給你變數的標籤
# 取得v7a變數值的標籤,然後存到物件lables_of_v7a
# value = "p or "n",來設定輸出的格式,p是標籤,n是數值
lables_of_v7a
```
```{r}
lables_of_v8 <- get_labels(tscs2020q1_sj$v8, values = "n")
# 取得v8變數值的標籤,然後存到物件lables_of_v8
View(lables_of_v8)
```
```{r}
lables_of_v17 <- get_labels(tscs2020q1_sj$v17, values = "n")
# 取得v17變數值的標籤,然後存到物件lables_of_v17
View(lables_of_v17)
```
- 用foreign套件的方法(直接把值轉換成標籤)
```{r}
tscs2020q1_foreign <- foreign::read.spss("tscs2020q1.sav", to.data.frame = TRUE, use.value.labels = TRUE)
# 載入tscs2020q1.sav檔案,存入物件tscs2020q1_foreign
```
- 用sjPlot::view_df()函式看全部變項
```{r}
library(sjPlot)
view_df(tscs2020q1_sj, max.len = 50, verbose = TRUE) # 如果每行沒有對齊,請修改瀏覽器字體,要找半形數字跟全形中文高度一樣的字體
```
### 遺漏值的處理
我們甚少直接透過原始的資料集進行統計的計算,通常會擷取需要使用的變項到獨立的物件中,而我們可以在擷取的過程中,同時進行遺漏值或其他資料處理。
- 婚姻狀態變項為例
```{r}
list(tscs2020q1_sj$v8) # 檢視tscs2020q1_sj資料集中的v8變數
```
```{r}
library(sjmisc)
marital_status <- set_na(tscs2020q1_sj$v8, na = c(9,98,99)) #擷取tscs2020q1_sj資料集中的v8變數,存入marital_status物件,並將98與99的值轉換成遺漏值
```
```{r}
attributes(marital_status) # 檢視marital_status物件
```
```{r}
marital_status
```
- 新聞偏好變項為例
```{r}
list(tscs2020q1_sj$v17) # 檢視tscs2020q1_sj資料集中的v17變數
```
```{r}
news_preference <- set_na(tscs2020q1_sj$v17, na = c(95:99)) #擷取tscs2020q1_sj資料集中的v17變數,存入news_preference物件,並將94到99的值轉換成遺漏值
```
```{r}
list(news_preference) # 檢視news_preference物件
```
### 把值轉換成標籤
```{r}
marital_status_label <- as_label(marital_status) # 將marital_status物件的值轉換成標籤,存入marital_status_label物件
```
```{r}
list(marital_status_label) # 檢視marital_status_label物件
```
### 重新編碼
- 用sjlabelled::replace_labels修改標籤
```{r}
marital_status_label_fixed <- replace_labels(marital_status,
labels = c("單身且沒結過婚" = 1,
"離婚" = 6)) # 將marital_status物件中的1與6的標籤修改
attributes(marital_status_label_fixed)
```
- 用sjmisc::rec重新編碼,編標籤
```{r}
marital_status_rec <- rec(marital_status,
rec = "2,3,4,5,7=1 [已婚];1,6,8=0 [未婚];9=NA;98=NA;99=NA")
# 將marital_status物件中的2,3,4,5,7的值轉換成1,1,6,8的值轉換成0,9,98,99的值轉換成遺漏值
```
```{r}
attributes(marital_status_rec) # 檢視marital_status_rec物件的屬性
list(marital_status_rec)
```
## 基礎圖、表格繪製
```{r}
library(sjPlot) # 載入sjPlot套件
library(sjmisc) # 載入sjmisc套件
library(sjlabelled) #載入sjlabelled套件
library(ggplot2) # 請注意函式衝突的警告訊息
```
```{r}
tscs2020q1_sj <- read_spss("tscs2020q1.sav", en = "big-5", verbose = TRUE) #載入tscs2020Q1.sav檔案,存入物件tscs2020q1
```
```{r}
marital_status <- set_na(tscs2020q1_sj$v8, na = c(9,98,99)) #擷取tscs2020q1_sj資料集中的v8變數,存入marital_status物件,並將98與99的值轉換成遺漏值
news_preference <- set_na(tscs2020q1_sj$v17, na = c(94:99)) #擷取tscs2020q1_sj資料集中的v17變數,存入news_preference物件,並將94到99的值轉換成遺漏值
```
### 次數分配表
- 用table函式
```{r}
table(marital_status, useNA = "always") # 計算marital_status物件的次數分配表,並顯示遺漏值
```
```{r}
table(sjlabelled::as_label(marital_status), useNA = "always")
# 太多層的nesting函式也會降低易讀性,可以透過建立物件來避免(但犧牲效率)
```
- gmodels套件的CrossTable函式
```{r}
library(gmodels)
CrossTable(sjlabelled::as_label(marital_status), useNA = "always") # 計算marital_status物件的次數分配表,並顯示遺漏值
```
- sjmisc套件的frq函式
```{r}
frq_marital_status <- as.data.frame(frq(marital_status)) # 計算marital_status物件的次數分配表,並存入frq_marital_status物件
```
輸出html排版,可以直接複製到word
```{r}
frq(marital_status, show.na = TRUE, out = "viewer") # 計算marital_status物件的次數分配表,並顯示遺漏值
```
- Hmisc::describe函式
```{r}
library(Hmisc)
birth_year <- tscs2020q1_sj$v2y # 擷取tscs2020q1_sj資料集中的v2y變數,存入birth_year物件
describe(birth_year) # 計算birth_year物件的次數分配表
```
- sjmisc::descr()函式
```{r eval=FALSE, include=FALSE}
descr(birth_year, out = "viewer") # 計算marital_status物件的次數分配表
```
- sjPlot::view_df()函式
```{r}
view_df(tscs2020q1_sj,
show.na = TRUE,
show.frq = TRUE,
show.prc = TRUE,
show.labels = TRUE) # 顯示frq_marital_status物件
```
### 次數分配長條圖
```{r}
set_theme(base = theme_blank(), # base argument 用來設定從ggplot2套件中設定好的既有主題
plot.backcol = "grey",
geom.label.color = "black",
geom.outline.color = "white",
theme.font = "jf-openhuninn-2.0") # 設定主題的背景顏色、標籤顏色、外框顏色
plot_frq(marital_status, # 繪製marital_status物件的長條圖
type = "bar", # 設定繪製長條圖
coord.flip = TRUE, # 設定xy軸翻轉
sort.frq = "asc", # or "desc"代表降冪排序
geom.colors = "pink") # 設定長條圖顏色
```
R studio的圖表瀏覽器會根據大小自動重新render圖片
- 分組長條圖
```{r}
gender <- tscs2020q1_sj$v1 # 擷取tscs2020q1_sj資料集中的v1變數,存入gender物件
plot_grpfrq(marital_status_label_fixed, gender, type = "bar") # 繪製marital_status_label_fixed與gender物件的分組長條圖
```
```{r}
plot_grpfrq(marital_status_label_fixed, gender,
type = "bar",
bar.pos = "stack", # 設定長條圖堆疊
show.n = TRUE, # 顯示次數
show.prc = FALSE,
title = "請問您目前的婚姻狀況是?")
```
### 我想要酷酷的字型怎麼辦
額外的字型需要透過extrafont套件來讀取
```{r}
install.packages("extrafont") # 安裝extrafont套件
library(extrafont) # 載入extrafont套件
font_import() # 讀取電腦中的字型,要花一段時間
loadfonts(device = "win") # 讀取字型
fonts() # 顯示可用所有字型
```