常用的資料結構包括向量(vector)、陣列/數組(array)、矩陣(matrix)、資料框(dataframe)、列表(list)、增強資料框(tibble)
向量為一維資料的表現和儲存方式,用c()函數可定義向量,如:
vec <- c(1,2,3,4,5,6,7)
vec
## [1] 1 2 3 4 5 6 7
class(vec)
## [1] "numeric"
vector是一維的資料。array是多維的資料。matrix是二維的資料,因此matrix是array的一種特殊情況。 本質上,矩陣和數組都是以向量的形式存儲的。它們只是額外地擁有dim(即“dimensions”,維度)屬性。我們可以用dim()函數從向量創建數組/矩陣:
# 先建立一個向量,然後用dim()加入維度,變為矩陣
vec2 <- c(1:48)
vec2
## [1] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
## [26] 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
dim(vec2) <- c(6,8)
vec2
## [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8]
## [1,] 1 7 13 19 25 31 37 43
## [2,] 2 8 14 20 26 32 38 44
## [3,] 3 9 15 21 27 33 39 45
## [4,] 4 10 16 22 28 34 40 46
## [5,] 5 11 17 23 29 35 41 47
## [6,] 6 12 18 24 30 36 42 48
# 我們可以檢查一下是不是已經將向量變為了矩陣
is.array(vec2)
## [1] TRUE
is.matrix(vec2)
## [1] TRUE
# 它多出來的dim屬性可以用attr()(即“attributes”,屬性)函數來查看:
attributes(vec2)
## $dim
## [1] 6 8
list(1, 2, 3)
## [[1]]
## [1] 1
##
## [[2]]
## [1] 2
##
## [[3]]
## [1] 3
| data | is.vector() | is.list() | is.atomic() | is.recursive() |
|---|---|---|---|---|
| list(1, 2, 3) | TRUE | TRUE | FALSE | TRUE |
| c(1 ,2 , 3) | TRUE | FALSE | TRUE | FALSE |
對列表和向量使用is.vector(), is.list(),is.atomic()和is.recursive()函數,會發現列表雖然也是“vector”,但我們一般說的“vector”都是指只能存儲一種數據類型的atomic vector;而lists是recursive vector.這意味著一個list能存儲多種類型的數據,且可以包含子列表。
# 這個列表有5個分量,其中第3個是一個有2個分量的子列表。
lists <- list(1, c("a","あ"), list(1+3i, logic = c(FALSE, NA, TRUE)),
data.frame(x = c("阿拉木图", "什切青"), y = c(2, 3)),
t.test)
lists
## [[1]]
## [1] 1
##
## [[2]]
## [1] "a" "あ"
##
## [[3]]
## [[3]][[1]]
## [1] 1+3i
##
## [[3]]$logic
## [1] FALSE NA TRUE
##
##
## [[4]]
## x y
## 1 阿拉木图 2
## 2 什切青 3
##
## [[5]]
## function (x, ...)
## UseMethod("t.test")
## <bytecode: 0x7fbc30cbc178>
## <environment: namespace:stats>
# 列表的索引
# 使用單方括號,得到的是一個只有一個分量的列表
lists[2]
## [[1]]
## [1] "a" "あ"
# 使用雙方括號,得到的是一個向量
lists[[2]]
## [1] "a" "あ"
# 得到的也是一個向量;父列表的索引在前,子列表的在後
lists[[3]][[2]]
## [1] FALSE NA TRUE
# 這個位置包含兩個子列表,因此得到一個有兩個分量的列表
lists[[3]]
## [[1]]
## [1] 1+3i
##
## $logic
## [1] FALSE NA TRUE
# 列表裡的分量可以有名字;被命名的元素可以通過$符號抓取:
lists[[3]]$logic
## [1] FALSE NA TRUE
Dataframe不是矩陣(雖然都是方的,且取子集方法和矩陣有近似之處。 矩陣是二維的,僅包含一種數據類型的數組。) Dataframe是一個二維的列表,不同列(即列表的分量)可以存儲不同的數據類型。 Dataframe具有list和matrix的雙重性質
data.frame會標註的資料類型: int 代表integer dbl 代表double chr 代表character向量或字符串 dttm 代表日期+時間(date+time) lgl 代表邏輯判斷TRUE或者FALSE fctr 代表因子類型factor date 代表日期dates
df <- data.frame(x = 1:4,
y = 4:1,
z = c("a", "b", "c", "d")
)
df
## x y z
## 1 1 4 a
## 2 2 3 b
## 3 3 2 c
## 4 4 1 d
# Like a list
df[c("x", "z")]
## x z
## 1 1 a
## 2 2 b
## 3 3 c
## 4 4 d
# Like a matrix
df[, c("x", "z")]
## x z
## 1 1 a
## 2 2 b
## 3 3 c
## 4 4 d
# 也可以透過位置來選取
# like a list
df[1:2]
## x y
## 1 1 4
## 2 2 3
## 3 3 2
## 4 4 1
# like a matrix
df[,1:2]
## x y
## 1 1 4
## 2 2 3
## 3 3 2
## 4 4 1
但是在dataframe被當成matrix做選取的時候會有降維的問題(list時不會)
df[,"x"]
## [1] 1 2 3 4
# 能用$符號來選取,或重新定義
df$x
## [1] 1 2 3 4
df$m <- as.integer(c(2,2,2,2)) # 默認是“numeric”型態,所以轉換為 integer
df
## x y z m
## 1 1 4 a 2
## 2 2 3 b 2
## 3 3 2 c 2
## 4 4 1 d 2
tibble 是 tidyverse 中的套件,tibble是增強型的data.frame,選取tibble的行或者列,即使遇到單行或者單列的時候,數據也不會降維,總是返回tibble,即仍然是數據框的形式。
library(tidyverse)
## ── Attaching packages ─────────────────────────────────────── tidyverse 1.3.0 ──
## ✓ ggplot2 3.3.3 ✓ purrr 0.3.4
## ✓ tibble 3.1.0 ✓ dplyr 1.0.5
## ✓ tidyr 1.1.3 ✓ stringr 1.4.0
## ✓ readr 1.4.0 ✓ forcats 0.5.1
## ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
## x dplyr::filter() masks stats::filter()
## x dplyr::lag() masks stats::lag()
tb <- tibble(
x = 1:4,
y = 4:1,
z = c("a", "b", "c", "d")
)
tb
## # A tibble: 4 x 3
## x y z
## <int> <int> <chr>
## 1 1 4 a
## 2 2 3 b
## 3 3 2 c
## 4 4 1 d
tb[,"x"]
## # A tibble: 4 x 1
## x
## <int>
## 1 1
## 2 2
## 3 3
## 4 4
# tibble還提供了一個非常快捷的方法,構建兩個有關聯的變量,如果用傳統的data.frame()來構建,會報錯
tb <- tibble(
x = 1:3,
y = x + 2
)
tb
## # A tibble: 3 x 2
## x y
## <int> <dbl>
## 1 1 3
## 2 2 4
## 3 3 5
# 為了讓每列更加直觀,也可以向下面這樣用tribble()創建一組資料集
tribble(
~x, ~y, ~z,
"a", 2, 3.6,
"b", 1, 8.5
)
## # A tibble: 2 x 3
## x y z
## <chr> <dbl> <dbl>
## 1 a 2 3.6
## 2 b 1 8.5
轉換成tibble類型意思就是說,剛開始不是tibble, 現在轉換成tibble, 包括:
data.frame轉換成tibble:as_tibble(t1)
vector轉換成tibble:as_tibble(t1)
list轉換成tibble:as_tibble(t1),as.list(df)
matrix轉換成tibble:as_tibble(t1),as.matrix(df)
# data.frame轉換成tibble
t1 <- iris[1:6, 1:4] # data.frame類型:
class(t1)
## [1] "data.frame"
as_tibble(t1)
## # A tibble: 6 x 4
## Sepal.Length Sepal.Width Petal.Length Petal.Width
## <dbl> <dbl> <dbl> <dbl>
## 1 5.1 3.5 1.4 0.2
## 2 4.9 3 1.4 0.2
## 3 4.7 3.2 1.3 0.2
## 4 4.6 3.1 1.5 0.2
## 5 5 3.6 1.4 0.2
## 6 5.4 3.9 1.7 0.4
# list轉換成tibble
# 就是產生均勻分佈(uniform distribution)隨機變數的函數,而 rnorm 函數則會產生常態分佈(normal distribution)的隨機變數。通常這類產生隨機變數的函數
df <- as_tibble(list(x = 1:6, y = runif(6), z = 6:1))
df
## # A tibble: 6 x 3
## x y z
## <int> <dbl> <int>
## 1 1 0.595 6
## 2 2 0.611 5
## 3 3 0.888 4
## 4 4 0.871 3
## 5 5 0.868 2
## 6 6 0.501 1
# 想要再轉為list可以用 as.list(df)
# vector,matrix也是同理
lst():創建一個list,具有tibble特性的list
lst(n = 5, x = runif(n), y = TRUE)
## $n
## [1] 5
##
## $x
## [1] 0.63972283 0.07227950 0.78231086 0.08158407 0.84389409
##
## $y
## [1] TRUE
enframe():快速創建tibble,,創建的tibble只有2個屬性: name和value
enframe(1:3)
## # A tibble: 3 x 2
## name value
## <int> <int>
## 1 1 1
## 2 2 2
## 3 3 3
enframe(c(a = 5, b = 7, c = 9))
## # A tibble: 3 x 2
## name value
## <chr> <dbl>
## 1 a 5
## 2 b 7
## 3 c 9
deframe():deframe()可以看做是enframe() 的反操作,把tibble反向轉成向量
df <- enframe(c(a = 5, b = 7))
deframe(df)
## a b
## 5 7
read_csv():讀取文件時,生成的直接就是tibble
data.frame是支持行名的,但tibble不支持row名字,這也是兩者不同的地方
# 創建data.frame
df <- data.frame(x = 1:3, y = 3:1)
# 給df增加行名
row.names(df) <- LETTERS[1:3]
df
## x y
## A 1 3
## B 2 2
## C 3 1
# 判断是否有行名
has_rownames(df)
## [1] TRUE
# 而試圖個tibble加入row的名,會報錯
tb <- tibble(x = 1:3, y = 3:1)
row.names(tb) <- LETTERS[1:3]
## Warning: Setting row names on a tibble is deprecated.
需要注意的:
有時候遇到含有行名的data.frame,轉換成tibble後,行名會被丟棄 如果想保留行名,就需要把行名轉換成單獨的一列
# 舉個例子
df <- mtcars[1:3, 1:3]
df
## mpg cyl disp
## Mazda RX4 21.0 6 160
## Mazda RX4 Wag 21.0 6 160
## Datsun 710 22.8 4 108
# 我們需要先把每row的名字先轉換為單獨的一個column
rownames_to_column(df, var = "rowname")
## rowname mpg cyl disp
## 1 Mazda RX4 21.0 6 160
## 2 Mazda RX4 Wag 21.0 6 160
## 3 Datsun 710 22.8 4 108
# 把行索引轉換為單獨的一個column
rowid_to_column(df, var = "rowid")
## rowid mpg cyl disp
## 1 1 21.0 6 160
## 2 2 21.0 6 160
## 3 3 22.8 4 108
資料屬性可透過下列函數查詢:
名稱 names()
各維度名稱 dimnames()
長度 length()
各維度長度 dim()
資料型態 class()
各類資料計數 table()
總覽資料 str()