---
# System prepended metadata

title: ' R Basic'
tags: [R]

---

---
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&amp;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() # 顯示可用所有字型
```
