向量
library(tidyverse)
1.1.1向量介紹
向量,vector,是R中最重要的一個概念,它是構成其他數據結構的基礎
用還函數c來創建向量,c代表concatenate連接欸,也可以理解為收集collect,或者合並combine
打印向量x
R中的字符串要加引號,單引號,雙引號都可以
邏輯型變量可以不加引號
用冒號:可以構建等差數列
調整等差數列的起始和終止值seq(from=2,to=34)
調整等差數列的起始和終止值seq(from=2,to=34,by=2)
控制輸出的個數length.out
rep()函數,重復出現的次數,重復5次2 ,重復5次x,必須是同一類型,因為同一類型方便計算
每個重復5次,用each
rep(x,each=5,times=2) #times是遍數
顯示變量的類型用mode()函數
如果變量中只有一個值,可以不使用c來賦值,此時稱為標量
向量化編程
向量化運算時要保證x,y的長度一致(重新定義了x<-(1,2,3,4,5))
x[x>3]輸出向量x中大於3的
控制x中每個向量出現的次數
1.1.2 向量的索引
length(x)返回向量x的長度
R中索引是從1開始,不是從0開始,x[1]這個是訪問x中的第一個向量
x[-19]不輸出x中的第19個元素,負號的意思相當於拋去
x[c(4:18)]輸出x中第4到第18個向量
x[c(1,23,45,67,89)]輸出x中索引值為1,23,45,67,89的元素,當然可以重復索引
中括號中不可以既有負數又有正數,因為這樣會邏輯不通順,此時可以曹勇邏輯值解決
若定義的邏輯值超過元素數,則會產生缺失值NA
還可以有復雜的邏輯表達式
對於字符型
可以判斷某字符是否在其中 %in%
嵌套使用
關於z的邏輯嵌套使用,訪問
使用names()函數給變量y中的每個元素取名字
可以通過名稱屬性訪問
如何修改向量,比如添加,刪除等操作
對向量x進行添加 x[101]<-101
先定義一個向量v,其值為1到3,通過索引4,5,6位置,對其進行批量賦值
若對其賦值中間沒有,則會出現缺失值NA
在第5個和第0個位置后面添加元素99,append(x=v,values = 99,after=5)
append(x=v,values = 99,after=0)
刪除整個向量用rm()函數
刪除某些元素用負號 -
修改指定位置上的元素,用索引y["four"]<-100,把4位置上的元素修改為100
1.1.3向量運算
定義兩個向量,分別為x,y,此時兩個向量元素個數相等
**這是冪運算
%%取余運算
%/%整除運算
若定義了一個比較短的向量,必須是整數倍才能運算
向量之間的邏輯運算
比較x和y是否相等,要用兩個等於號==,一個等於號是賦值
%in%包含運算符
向量中的函數
返回不大於x的最大整數 floor(),不小於x的最大整數ceiling()
對向量x的一些函數操作
trunc()函數返回整數部分
round()函數四舍五入,digits代表保留的小數位數
signif()函數與round()函數類似,保留小數部分有效數字
可以對向量進行三角函數的操作
一些統計函數
定義一個1到100的向量
sum()函數求和,max()函數求最大值,min()函數求求最小值,mean()函數求平均值,range()函數求最大和最小值,var()函數求方差,sd()函數求標准差,round()函數四舍五入,prod()函數返回連乘的積,median()函數求中位數,quantile()函數求分位數
計算vec的4分位數,5分位數,8分位數
返回最大(小)元素值位置的索引值,返回元素值為7(1)的索引值
which(t==7) #返回向量中元素7所在位置處的索引 which(t>5) #返回元素值大於5的索引值
方差var() 標准差 sd()
和 sum()
均值 mean()
最值 最大max() 最小 min()
連乘 prod()
函數seq(),按照指定的規律來產生向量
產生字母序列 letters()
函數which(),返回下標
函數rev(),sort(),一個是顛倒,一個是排序
函數matrix(),生成矩陣,
函數t(),矩陣的轉置,
矩陣相乘 a%*%b ,函數diag(),返回矩陣的對角線
產生單位矩陣diag(標量),例如diag(4)
矩陣求逆,函數rnorm()正太分布產生隨機數,函數solve()求逆矩陣
解線性方程組solve(a,b),a是一個矩陣,b是一個向量,這樣構成方程組
0.201 x1 + 1.427 x2 - 0.282 x3 + 0.930 x4 = 1
0.135 x1 - 1.389 x2 - 0.055 x3 - 0.026 x4= 2
1.2 向量基礎
向量的類型主要有兩種。
• 原子向量,其共有 6 種類型:邏輯型、整型、雙精度型、字符型、復數型和原始型。整
型和雙精度型向量又統稱為數值型向量。
• 列表,有時又稱為遞歸向量,因為列表中也可以包含其他列表。
原子向量與列表之間的主要區別是,原子向量中的各個值都是同種類型的,而列表中的各
個值可以是不同類型的。
每個向量都有兩個關鍵屬性:
• 類型。你可以使用 typeof() 函數來確定向量的類型:
typeof(letters)
typeof(1:10)
• 長度。你可以使用 length() 函數來確定向量的長度:
x <- list("a", "b", 1:10) length(x)
1.3 重要的原子向量
4 種最重要的原子向量類型是邏輯型、整型、雙精度型和字符型。
1.3.1 邏輯型
邏輯型向量是最簡單的一種原子向量,因為它們只有 3 個可能的取值:FALSE、TRUE 和 NA。
1:10 %% 3 == 0
c(TRUE, TRUE, FALSE, NA)
1.3.2 數值型
整型與雙精度型向量統稱為數值型向量。R 中默認數值是雙精度型的。如果想要創建整型
數值,可以在數字后面加一個 L:
typeof(1)
typeof(1L)
• 雙精度型是近似值。雙精度型表示的是浮點數,不能由固定數量的內存精確表示。
x <- sqrt(2) ^ 2 x
x - 2
在比較浮點數時,不能使用 ==,而應該使用 dplyr::near(),后者可以容忍一些數據誤差。
• 整型數據有 1 個特殊值 NA,而雙精度型數據則有 4 個特殊值:NA、NaN、Inf 和 -Inf。
其他 3 個特殊值都可以由除法產生。
c(-1, 0, 1) / 0
不要使用 == 來檢查這些特殊值,而應該使用輔助函數 is.finite()、is.infinite() 和is.nan()。
1.3.3 字符型
字符向量是最復雜的一種原子向量,因為其每個元素都是一個字符串,而字符串可以包含任意數量的數據。
R 使用的是全局字符串池。這意味着每個唯一的字符串在內存中只保存一次,每次對這個字符串的使用都指向這段內存,這樣可以減少復制字符串所需的內存空間。可以使用 pryr::object_size() 函數來查看這種處理的效果:
x <- "This is a reasonably long string." pryr::object_size(x)
y <- rep(x, 1000) pryr::object_size(y)
y 所占用的內存不是 x 的 1000 倍,因為 y 中的每個元素都只是指向一個字符串的指針。因為一個指針占 8 個字節,所以 1000 個指針以及一個 136 字節的字符串所占用的內存空間是 8 * 1000 + 136 = 8.13KB。
1.3.4 缺失值
注意,每種類型的原子向量都有自己的缺失值:
NA # 邏輯型
NA_integer_ # 整型
NA_real_ # 雙精度型
NA_character_ # 字符型
1.4 使用原子向量
1.4.1 強制轉換
• 顯式強制轉換:當調用 as.logical()、as.integer()、as.double() 或 as.character()
這樣的函數進行轉換時,使用的就是顯式強制轉換。
• 隱式強制轉換:當在特殊的上下文環境中使用向量,而這個環境又要求使用特定類型的
向量時,就會發生隱式強制轉換。
在數值環境中使用邏輯向量,TRUE 轉換為 1,FALSE 轉換為 0。這意味着對邏輯向量求和的結果就是其中真值的個數,邏輯向量的均值就是其中真值的比例:
x <- sample(20, 100, replace = TRUE) y <- x > 10
sum(y) # 大於10的數有多少個?
mean(y) # 大於10的數的比例是多少?
1.4.2 檢驗函數
有時我們需要根據向量的類型進行不同的操作,R 基礎包中提供了很多這樣的函數,如 is.vector() 和 is.atomic()。更可靠的方法是使用 purrr 包提供的 is_* 函數族,以下表格總結了它們的使用方式。
以上每個函數都配有一個“標量”版本,比如 is_scalar_atomic(),它們可以檢驗長度為1 的向量。
1.4.3 標量與循環規則
正因為沒有標量,所以 R 的多數內置函數都是向量化的,即可以在數值的一個向量上進行操作。
sample(10) + 100
runif(10) > 0.5
如果兩個長度不同的向量相加,那么會出現什么情況呢?此時 R 會擴展較短的向量,使其與較長的向量一樣長,這個過程就稱作向量循環。
1:10 + 1:2
如果確實想要執行向量循環,那么你需要使用 rep() 函數手工完成:
tibble(x = 1:4, y = 1:2)
tibble(x = 1:4, y = rep(1:2, 2))
tibble(x = 1:4, y = rep(1:2, each = 2))
1.4.4 向量命名
所有類型的向量都是可以命名的。你可以在使用 c() 函數創建向量時進行命名:
c(x = 1, y = 2, z = 4)
也可以在向量創建完成后,使用 purrr::set_names() 函數來命名:
set_names(1:3, c("a", "b", "c"))
1.4.5 向量取子集
我們可以使用 dplyr::filter() 函數在 tibble 中篩選行。但 filter() 函數只能篩選 tibble,因此要想篩選向量,我們需要使用一個新工具:[。[ 就是取子集函數,調用形式是 x[a]。
可以使用以下 4 種形式來完成向量取子集操作:
• 使用僅包含整數的數值向量。整數要么全部為正數,要么全部為負數,或者為 0。
x <- c("one", "two", "three", "four", "five") x[c(3, 2, 5)]
位置可以重復,這樣可以生成比輸入更長的輸出結果:
x[c(1, 1, 5, 5, 5, 2)]
使用負整數取子集時,會丟棄相應位置的元素:
x[c(-1, -3, -5)]
正數與負數混合使用則會引發一個錯誤:
x[c(1, -1)]
這條錯誤消息中提到了使用 0 來取子集,這樣不會返回任何值:
x[0]
• 使用邏輯向量取子集。這種方式可以提取出 TRUE 值對應的所有元素,一般與比較函數結合起來使用效果最佳:
x <- c(10, 3, NA, 5, 8, 1, NA)
# x中的所有非缺失值
x[!is.na(x)]
# x中的所有偶數值(或缺失值)
x[x %% 2 == 0]
• 如果是命名向量,那么可以使用字符向量來取子集:
x <- c(abc = 1, def = 2, xyz = 5) x[c("xyz", "def")]
• 取子集的最簡方式就是什么都不寫:x[],這樣就會返回 x 中的全部元素。如果 x 是
二維的,那么 x[1, ] 可以選取出第 1 行和所有列,x[, -1] 則可以選取出所有行和除第
1 列外的所有列。
1.5 遞歸向量(列表)
列表是建立在原子向量基礎上的一種復雜形式,因為列表中可以包含其他列表。可以使用 list() 函數創建列表:
x <- list(1, 2, 3) x
在處理列表時,str() 函數是一個非常有用的工具,因為其重點關注列表結構,而不是列
表內容:
str(x)
x_named <- list(a = 1, b = 2, c = 3) str(x_named)
與原子向量不同,list() 中可以包含不同類型的對象:
y <- list("a", 1L, 1.5, TRUE) str(y)
列表甚至可以包含其他列表:
z <- list(list(1, 2), list(3, 4)) str(z)
1.5.1 列表可視化
x1 <- list(c(1, 2), c(3, 4)) x2 <- list(list(1, 2), list(3, 4)) x3 <- list(1, list(2, list(3)))
這種可視化表示遵循以下 3 個原則:
• 列表用圓角矩形表示,原子向量用直角矩形表示。
• 子向量繪制在父向量中,而且背景要比父向量深一些,這樣更容易表示出層次結構。
• 子向量的方向(也就是其行和列)並不重要,我們只在示例中表示出一行或一列,有時是為了節省空間,有時是為了說明一個重要的屬性。
1.5.2 列表取子集
列表取子集有 3 種方式:
a <- list(a = 1:3, b = "a string", c = pi, d = list(-1, -5))
• 使用 [ 提取子列表。這種方式的結果總是一個列表:
str(a[1:2])
str(a[4])
• 使用 [[ 從列表中提取單個元素。這種方式會從列表中刪除一個層次等級:
str(a[[1]])
str(a[[4]])
• $ 是提取列表命名元素的簡單方式,其作用與 [[ 相同,只是不需要使用括號:
a$a
a[["a"]]
對於列表來說,[ 和 [[ 之間的區別是非常重要的,因為 [[ 會使列表降低一個層級,而[ 則會返回一個新的、更小的列表。
1.6 特性
可以使用 attr() 函數來讀取和設置單個特性值,也可以使用attributes() 函數同時查看所有特性值:
x <- 1:10 attr(x, "greeting")
attr(x, "greeting") <- "Hi!" attr(x, "farewell") <- "Bye!" attributes(x)
3 種特別重要的特性可以用來實現 R 中的基礎功能:
• 名稱:用於命名向量元素。
• 維度:使得向量可以像矩陣或數組那樣操作。
• 類:用於實現面向對象的 S3 系統。
泛型函數是 R 中實現面向對象編程的關鍵,因為它允許函數根據不同類型的輸入而進行不同的操作。
可以使用 methods()函數列舉出一個泛型函數的所有方法:
methods("as.Date")
1.7 擴展向量
4 種重要的擴展向量。
• 因子
• 日期
• 日期時間
• tibble
1.7.1 因子
因子是設計用來表示分類數據的,只能在固定集合中取值。因子是在整型向量的基礎上構
建的,添加了水平特性:
x <- factor(c("ab", "cd", "ab"), levels = c("ab", "cd", "ef")) typeof(x)
attributes(x)
1.7.2 日期和日期時間
R 中的日期是一種數值型向量,表示從 1970 年 1 月 1 日開始的天數:
x <- as.Date("1971-01-01") unclass(x)
typeof(x)
attributes(x)
日期時間是帶有 POSIXct 類的數值型向量,表示從 1970 年 1 月 1 日開始的秒數:
x <- lubridate::ymd_hm("1970-01-01 01:00") unclass(x)
typeof(x)
attributes(x)
tzone 特性是可選的。它控制的是時間的輸出方式,不是時間的值:
attr(x, "tzone") <- "US/Pacific" x
attr(x, "tzone") <- "US/Eastern" x
另一種日期時間類型稱為 POSIXlt,它是基於命名列表構建的:
y <- as.POSIXlt(x) typeof(y)
attributes(y)
1.7.3 tibble
tibble 是擴展的列表,有 3 個類:tbl_df、tbl 和 data.frame。它的特性有 2 個:(列)
names 和 row.names。
tb <- tibble::tibble(x = 1:5, y = 5:1) typeof(tb)
attributes(tb)
傳統 data.frames 具有非常相似的結構:
df <- data.frame(x = 1:5, y = 5:1) typeof(df)
attributes(df)