基本的資料型態在實際運用上,還是有些眉眉角角的,讓我們來看看各類型的資料型態功用及語法吧!
- 向量 Vectors
在 R 裡,一個範圍(如 1 – 10)的表示不像 Ruby 中使用 for a in 1..10,而是 a <- 1:10,把 1 – 10 這個範圍的數字 assign 給 A (等於 = 這個符號在 R 裡也是 assign,等於等於 == 是判斷左右兩邊是否相等)
> A <- 4:10
> A
[1] 4 5 6 7 8 9 10
想知道向量中第 N 個元素是什麼,此時用中括號 [] 作為索引,像我想知道 A 向量中第 2、5 個元素為何:
> A[c(2,5)]
[1] 5 8
也能用中括號 [] 去更新指定位置元素的數值,像我想指定 A 中第二個元素變成 5 倍
> A[2] <- 5 * A[2]
> A
[1] 4 25 6 7 8 9 10
中括號還能篩選特定的數值,假設學生名單有三個人 (Intern 實習醫師看得太走火入魔),StudentList == "George" 是指 R 會去比對名單中每位同學跟 George 是否相符,結果是「真 假 假」
> StudentList <- c("George", "Meredis", "Derick")
> StudentList == "George"
[1] TRUE FALSE FALSE
此時,用中括號去篩選哪個名單裡的人是 George
> StudentList[StudentList == "George"]
[1] "George"
2. 矩陣 Matrices
R 裡頭矩陣的元素優先填入 column (直的那排),填完第一個 column 再去填第二、三… 個。
> C <- matrix( c('1','3','5','5','3','1'), nrow = 2, ncol = 3)
> print(C)
[,1] [,2] [,3]
[1,] "1" "5" "3"
[2,] "3" "5" "1"
此時,如果希望改成先填 row (橫),可以加個 byrow = TRUE 就行~
> C <- matrix( c('1','3','5','5','3','1'), nrow = 2, ncol = 3, byrow = TRUE)
> print(C)
[,1] [,2] [,3]
[1,] "1" "3" "5"
[2,] "5" "3" "1"
前面有提過,如果要放的資料不只一個維度,可用陣列 array(不過好像不常用),裡面放的資料要是同一種屬性。如今我們來存 2 個 4×4 的矩陣 (4×4 的矩陣是二維,存 2 個這樣的矩陣,資料就變成三維) 吧!
> Fruit <- array(c('banana', 'lemon', 'mango', 'cherry', 'watermelon'), dim = c(4, 4, 2))
> print(Fruit)
, , 1
[,1] [,2] [,3] [,4]
[1,] "banana" "watermelon" "cherry" "mango"
[2,] "lemon" "banana" "watermelon" "cherry"
[3,] "mango" "lemon" "banana" "watermelon"
[4,] "cherry" "mango" "lemon" "banana"
, , 2
[,1] [,2] [,3] [,4]
[1,] "lemon" "banana" "watermelon" "cherry"
[2,] "mango" "lemon" "banana" "watermelon"
[3,] "cherry" "mango" "lemon" "banana"
[4,] "watermelon" "cherry" "mango" "lemon"
接下來是簡單的矩陣預算,先給出兩個矩陣 A、B:
> A <- matrix(c(1,3,5,7), nrow = 2, ncol = 2)
> B <- matrix(c(2,1,3,1), nrow = 2, ncol = 2)
> A
[,1] [,2]
[1,] 1 5
[2,] 3 7
> B
[,1] [,2]
[1,] 2 3
[2,] 1 1
(1) A * B:矩陣 A 與 矩陣 B 的元素間倆倆相乘,也就是很純粹的 Aij x Bij 後把它填到新的矩陣第 ij 個值,跟高中學的矩陣加法不一樣喔
> A * B
[,1] [,2]
[1,] 2 15
[2,] 3 7
(2) A %*% B:矩陣乘法 A⋅B,這才是我們以前學的矩陣乘法,新的矩陣第 ij 個值,是由 A 第 i 個 row 乘上 B 第 j 個 column 各自的值,並且加在一起
> A %*% B
[,1] [,2]
[1,] 7 8
[2,] 13 16
(3) t(A):轉置矩陣 AT
> t(A)
[,1] [,2]
[1,] 1 3
[2,] 5 7
(4) solve(A):矩陣 A 的反矩陣
> solve(A)
[,1] [,2]
[1,] -0.875 0.625
[2,] 0.375 -0.125
(5) solve(A, b):求聯立方程組 Ax=b 的解,就是 A 的反矩陣乘上 b(還是要花點腦袋想一下,隔太久了~)
假設 b 向量是 (2,10)
> b <- c(2,10)
> solve(A, b)
[1] 4.5 -0.5
就得到 b 了!如果拿 A 的反矩陣,直接乘上 b 也會得到一樣的結果
> solve(A) %*% b
[,1]
[1,] 4.5
[2,] -0.5
3. 列表 Lists
向量要放的是同類型的元素,比如數字、字串。不過列表可以存放任何我們想放的資料形式,要放向量、數字、函數都可以,還蠻常用的
> # Create a list.
> list1 <- list(c(1,2,3), 99.3, sin)
>
> # Print the list. 比如說這列表第一個位置就是個向量~
> print(list1)
[[1]]
[1] 1 2 3
[[2]]
[1] 99.3
[[3]]
function (x) .Primitive("sin")
也可以指定 List 裡每個位置要叫什麼名字,如第一個位置叫做 vector、第二個位置叫做 numeric… 再用 names() 指令叫出每個位置的名字
> # Create list and assign variable names.
> list2 <- list(vector = c(1,2,3),
+ numeric = 99.3,
+ func = sin)
>
> # Print names of list and list itself.
> names(list2)
[1] "vector" "numeric" "func"
>
> print(list2)
$vector
[1] 1 2 3
$numeric
[1] 99.3
$func
function (x) .Primitive("sin")
4. 因子 Factors
專門儲存類別資料的變數,比如說有 100 個男生、女生,「性別」就會變成一個因子,裡面包含兩種類型,男生 (male, 字串) 當成 1 (數字)、女生 (female, 字串) 當成 2 (數字) 來做標記。所以,因子可用向量來呈現,具有字串及整數的特性,會儲存 (1) 特定的 Labels 比如男、女生;(2) 每個對應到 Labels 的元素,可用向量表示,如男男女 -> 112。
好處是如果有很多不同的類別、Label 在儲存的時候會存成文字的方式,占比較多的空間;如果我們存成因子的話,會變成一個 unique list,它只要存成字串與整數的方式,較省記憶體。老師建議,因為 R 裡面很多的模型(如回歸等),遇到因子物件的時候會自動做處理,所以如果遇到類別變數,可以盡量把它存成因子的方式,建模很好用。
> # Create a vector. 蘋果的顏色有:green green yellow red red red green,原先是存成一個向量,內容存的都是一個個字串
> apple_colors <- c('green','green','yellow','red','red','red','green')
>
> # Create a factor object. 我們可以把它變成因子、轉化成 factor,用 factor (想轉換的東西) 把後面我們要的這個物件轉換成 factor
> factor_apple <- factor(apple_colors)
>
> # Print the factor. 把它印出來看看,會發現裡面有一個 levels:green red yellow,R 會把它存成 1 1 2 3 3 3 1 的形式,再把它跟 green red yellow 去 mapping,這樣存會比較節省空間,並可以用nlevels來知道因子裡面有多少個不同的level
> print(factor_apple)
[1] green green yellow red red red green
Levels: green red yellow
>
> print(nlevels(factor_apple))
[1] 3
5. 資料框架 Data Frames
這是 R 語言裡面為人津津樂道的一種資料結構,不過版本比較舊,現在新版叫做 tibble,之後二煎拌學了再跟大家分享~
上次有提過 Data Frames 有兩個原則,Rows 通常代表純個體 Individuals、或觀察對象 Observations,Columns 通常都是純變數 Variables
舉例:假設我們有三個變數,分別是名字、年齡、性別
> name <- c("George", "Dereck", "Ezi")
> age <- c("24", "35", "26")
> gender <- c("Male", "Male", "Female")
>
> # Create by variables 用 data.frame 把三個變數 name age gender 括號起來,再指派給 data1,並印出來看看 data1 裡面到底長什麼樣子?
> data1 <- data.frame(name, age, gender)
> data1
name age gender
1 George 24 Male
2 Dereck 35 Male
3 Ezi 26 Female
我們發現 print 出來的結果中,column 都是變數:第一個 column 是姓名、第二個 column 是年齡、第三個 column 是性別,而每一個 row 都是一個個體的資料。因此 dataframe 跟一般的資料集合是很相近的,這就是為什麼 R 的 dataframe 這麼好用;在 Python 的 Pandas 也是以 dataframe 為基礎的資料結構去做分析的~
當然我們也可以指派 dataframe 的名字,把 name age gender 等於後面的向量,就不用像前面打成三個地方,在裡面直接指派就好。
*記得這邊的等號不可以寫成指派符號,因為前面已經有一個指派符號了,所以後面只能寫等號!老師建議不要把等號跟指派符號混在一起寫。把 data2 印出來,會發現跟 data1 是一模一樣的!
> data2 <- data.frame(
+ name = c("George", "Dereck", "Ezi"),
+ age = c("24", "35", "26"),
+ gender = c("Male", "Male", "Female")
+ )
> data2
name age gender
1 George 24 Male
2 Dereck 35 Male
3 Ezi 26 Female
在 data frame 裡,還有一些常用的函數:
- head:取得資料框架前六比資料(預設是 6)。
- colnames:修改或查詢 column 名稱。
- rownames:設定 row 的名稱
- summary:顯示資料基本資訊。
想要知道 data2 的前六筆資料是什麼,我們就可以用 head(data2)。因為 data2 只有三筆資料,所以會直接看到所有的資料結果;但是如果一個 dataframe 有一萬個個體,用 head() 只會輸出前六個資料
> head(data2)
name age gender
1 George 24 Male
2 Dereck 35 Male
3 Ezi 26 Female
我們也可以把 data2 的 column name 指派成別的名稱,比如原本是 name age gender、想把它改成 Var_1 Var_2 Var_3,並把 data2 的 row names 做調整,再印出來看看,可以發現我們的 column name 真的被改成 Var_1, Var_2, Var_3 了~
> colnames(data2) <- c("Var_1", "Var_2","Var_3")
> rownames(data2) <- c("a", "b", "c")
> data2
Var_1 Var_2 Var_3
a George 24 Male
b Dereck 35 Male
c Ezi 26 Female
此外,還能看資料的統計,用 summary(data2) 來看看統計的結果。
> summary(data2)
Var_1 Var_2 Var_3
Length:3 Length:3 Length:3
Class :character Class :character Class :character
Mode :character Mode :character Mode :character
資料結構在 R 裡面很常用,不過因為它有些小缺點,老師還是建議大家用 tibbles,而不要用這種 dataframe 架構去存資料,程式的效能會好非常多。
6. 資料結構的常用函數
操作資料時的常用函數
- length(object) : 元素個素
- unique(object) : 該物件的獨立元素
- str(object) : 輸出該物件的基本架構
- class(object) : 該物件屬於哪種資料結構
- names(object) : 物件中元素的名稱
- c(object,object,…) : 將物件合併為一個向量
- object : 印出物件
- rm(object) : 從工作空間中移除物件
length(object) 抓出一個向量或資料結構的長度,比如把向量 c(1, 1, 2, 2, 3, 3, 4, 4, 5, 6, 7, 8) 指派給 x,總共有 12 個元素
> x <- c(1, 1, 2, 2, 3, 3, 4, 4, 5, 6, 7, 8)
> length(x)
[1] 12
unique(object) 把 x 裡面所有獨立不重複的值找出來
> unique(x)
[1] 1 2 3 4 5 6 7 8
先來建立一個 data3 來進行後續的操作
> data3 <- data.frame(
+ name = c("Ezi", "Meredith", "Dereck", "Ezi", "Meredith"),
+ age = c("24", "25", "36", "24", "30"),
+ gender = c("Female", "Female", "Male", "Female", "Female")
+ )
> data3
name age gender
1 Ezi 24 Female
2 Meredith 25 Female
3 Dereck 36 Male
4 Ezi 24 Female
5 Meredith 30 Female
我們會發現,Ezi 是重複的,因為第一、四個 Row 的內容完全一樣;而第二、五個 Row 的 Meredith 看似相同,但在年齡上有點不一樣,第五個 Row 是 Meredith 30 歲的時候(Grey Anatomy 不知第幾季了)~這時,如果用 unique() 操作會如何呢?
> unique(data3)
name age gender
1 Ezi 24 Female
2 Meredith 25 Female
3 Dereck 36 Male
5 Meredith 30 Female
第四個 Row Ezi 被去掉了,只剩下1 2 3 5 這四個人的 row 還留著~
> str(data3)
'data.frame': 5 obs. of 3 variables:
$ name : chr "Ezi" "Meredith" "Dereck" "Ezi" ...
$ age : chr "24" "25" "36" "24" ...
$ gender: chr "Female" "Female" "Male" "Female" ...
用 string(data3) 可以把 data3 的相關變數做統計,讓我們知道裡面存了什麼東西:三個 factor 分別是 name age gender
> class(data3)
[1] "data.frame"
想知道 data 3 是怎麼樣的資料結構,就可以用 class() 來看看它屬於哪一類,結果發現它在 R 裡面存的是data.frame的形式~
> names(data3)
[1] "name" "age" "gender"
想叫出變數的名字可用 names (),得到變數、也就是 Column 的名字
今天上了九小時的班,下班後吹著台北車站週遭的微風(果然微風是要開在北車的?),回家吃晚餐都已經晚上九點多了,但每天堅持學習非原本領域的知識,還是一件非常令我充滿能量的事。相信你也可以!
我自學程式有許多管道,身為一個超級廢新手,主要來源包含買書、大神們的部落格、線上課程(Hahow / Udemy / Coursera)… 等。
附上手邊的幾個部落格和線上課程網址:
- Hahow 好學校 – R語言和商業分析-洞悉商業世界中的資料科學 [寫這些學習筆記歷程最主要的來源之一]
http://tinyurl.com/y2hhr3vf - 資料科學與R語言 [曾意儒老師 Yi-Ju Tseng]
https://yijutseng.github.io/DataScienceRBook/index.html - 統計計算與程式語言 [林建甫老師]
https://web.ntpu.edu.tw/~cflin/ - 認識 R 的美好 [郭耀仁老師]
https://bookdown.org/tonykuoyj/eloquentr/ - R系列筆記 [skydome20 老師]
https://rpubs.com/skydome20/Table