資料結構

常用的資料結構包括向量(vector)、陣列/數組(array)、矩陣(matrix)、資料框(dataframe)、列表(list)、增強資料框(tibble)

向量 vector

向量為一維資料的表現和儲存方式,用c()函數可定義向量,如:

vec <- c(1,2,3,4,5,6,7)
vec
## [1] 1 2 3 4 5 6 7
class(vec)
## [1] "numeric"

數組(array)矩陣(matrix)

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)

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是一個二維的列表,不同列(即列表的分量)可以存儲不同的數據類型。 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 )

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, 現在轉換成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也是同理

tibble相關的一些函數

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不同

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()