R語言基礎系列:
tidyr包的應用
- tidyr主要提供了一個類似Excel中數據透視表(pivot table)的功能。
gather()
和spread()
函數將數據在長格式和寬格式之間相互轉化,應用在比如稀疏矩陣和稠密矩陣之間的轉化。(用于數據框 )separate()
和union()
方法提供了數據分組拆分、合并的功能,應用在nominal數據的轉化上。(用于數據框 )- tidyr還提供一些簡單的缺失值處理方法。
# 查看這個包的網頁說明書
browseVignettes('tidyr')
1. gather實現wide 到 long 轉換
類似reshape2包中melt函數的功能
- 語法
gather(data, key = "key", value = "value",..., na.rm = FALSE, convert = FALSE, factor_key = FALSE)
- 參數
參數 | 含義 |
---|---|
data | 需要被轉換的寬形數據框 |
key | 將原數據框中的所有列賦給一個新變量key |
value | 將原數據框中的所有值賦給一個新變量value |
… | 可以指定哪些列聚到同一列中,可用于選擇兩列之間的所有列col1:coln, 排除列-coln |
na.rm | 是否刪除缺失值,默認為FALSE |
convert | 為TRUE時會自動在key列上使用type.convert函數,默認值為FALSE |
factor_key | FALSE時key值為字符向量,TRUE時key值為factor類型 |
- 使用
library(tidyr)
library(dplyr)
stocks <- tibble(
time = as.Date('2009-01-01') + 0:9,
X = rnorm(10, 0, 1),
Y = rnorm(10, 0, 2),
Z = rnorm(10, 0, 4)
)
stocks
# A tibble: 10 x 4
# time X Y Z
# <date> <dbl> <dbl> <dbl>
# 1 2009-01-01 -0.326 3.32 5.84
# 2 2009-01-02 0.410 3.99 -1.97
# 3 2009-01-03 -0.344 -0.394 4.09
# 4 2009-01-04 -1.11 1.12 -5.43
# 5 2009-01-05 -0.374 0.303 0.336
# 6 2009-01-06 2.72 1.38 -4.86
# 7 2009-01-07 0.416 3.39 -1.27
# 8 2009-01-08 2.31 1.25 -2.13
# 9 2009-01-09 -0.0643 4.87 1.37
# 10 2009-01-10 -0.0232 2.73 1.38
gather(stocks, "stock", "price", -time)
stocks %>% gather("stock", "price", -time)
# A tibble: 30 x 3
# time stock price
# <date> <chr> <dbl>
# 1 2009-01-01 X -0.326
# 2 2009-01-02 X 0.410
# 3 2009-01-03 X -0.344
# 4 2009-01-04 X -1.11
# 5 2009-01-05 X -0.374
# 6 2009-01-06 X 2.72
# 7 2009-01-07 X 0.416
# 8 2009-01-08 X 2.31
# 9 2009-01-09 X -0.0643
# 10 2009-01-10 X -0.0232
# … with 20 more rows
2. spread實現long 到wide轉換(類似reshape2包中cast函數的功能)
- 語法
spread(data, key, value, fill = NA, convert = FALSE, drop = TRUE, sep = NULL)
- 參數
參數 | 含義 |
---|---|
data | 為需要轉換的長形data.frame |
key | 設置需要擴寬的類別變量 |
value | 設置需要擴寬的變量的度量值 |
fill | 對于缺失值,可將fill的值賦值給被轉型后的缺失值 |
convert | 為TRUE時會自動在新列上使用type.convert函數,其中as.is = TRUE,默認值為FALSE |
drop | 為FALSE保留factor的level,使用fill的值填充missing的值 |
sep | 為默認值NULL時,新列名使用key中的值,非NULL時,新列名為<key_name><sep><key_value> |
- 使用
library(dplyr)
stocks <- data.frame(
time = as.Date('2009-01-01') + 0:9,
X = rnorm(10, 0, 1),
Y = rnorm(10, 0, 2),
Z = rnorm(10, 0, 4)
)
stocks
# A tibble: 10 x 4
# time X Y Z
# <date> <dbl> <dbl> <dbl>
# 1 2009-01-01 -0.326 3.32 5.84
# 2 2009-01-02 0.410 3.99 -1.97
# 3 2009-01-03 -0.344 -0.394 4.09
# 4 2009-01-04 -1.11 1.12 -5.43
# 5 2009-01-05 -0.374 0.303 0.336
# 6 2009-01-06 2.72 1.38 -4.86
# 7 2009-01-07 0.416 3.39 -1.27
# 8 2009-01-08 2.31 1.25 -2.13
# 9 2009-01-09 -0.0643 4.87 1.37
# 10 2009-01-10 -0.0232 2.73 1.38
stocksm <- stocks %>% gather(stock, price, -time)
head(stocksm)
# time stock price
# 1 2009-01-01 X 0.8126651
# 2 2009-01-02 X -0.3387208
# 3 2009-01-03 X -0.6778238
# 4 2009-01-04 X 0.3713640
# 5 2009-01-05 X -1.5019406
# 6 2009-01-06 X -0.8858434
stocksm %>% spread(stock, price)
# time X Y Z
# 1 2009-01-01 0.81266513 -2.21316283 7.9265756
# 2 2009-01-02 -0.33872080 3.52921094 -1.2218472
# 3 2009-01-03 -0.67782385 -1.82005963 1.2567876
# 4 2009-01-04 0.37136402 -1.22181178 -0.2963697
# 5 2009-01-05 -1.50194061 -1.56952607 3.1274926
# 6 2009-01-06 -0.88584341 5.17005476 -10.9974695
# 7 2009-01-07 0.22308469 0.07021010 -3.2228298
# 8 2009-01-08 0.08303945 -5.20103460 -0.1731917
# 9 2009-01-09 -0.58188891 -0.47327216 0.7320103
# 10 2009-01-10 -0.33931690 0.01911578 -7.2114319
stocksm %>% spread(time, price)
# stock 2009-01-01 2009-01-02 2009-01-03 2009-01-04 2009-01-05 2009-01-06
# 1 X 0.8126651 -0.3387208 -0.6778238 0.3713640 -1.501941 -0.8858434
# 2 Y -2.2131628 3.5292109 -1.8200596 -1.2218118 -1.569526 5.1700548
# 3 Z 7.9265756 -1.2218472 1.2567876 -0.2963697 3.127493 -10.9974695
# 2009-01-07 2009-01-08 2009-01-09 2009-01-10
# 1 0.2230847 0.08303945 -0.5818889 -0.33931690
# 2 0.0702101 -5.20103460 -0.4732722 0.01911578
# 3 -3.2228298 -0.17319172 0.7320103 -7.21143190
3. unite 可將多列按指定分隔符合并為一列
- 語法
unite(data, col, ..., sep = "_", remove = TRUE)
- 參數
參數 | 含義 |
---|---|
data | 為數據框 |
col | 被組合的新列名稱 |
… | 指定哪些列需要被組合, 可用于選擇兩列之間的所有列col1:coln, 排除列-coln |
sep | 組合列之間的連接符,默認為下劃線 |
remove | 是否刪除被組合的列 |
- 使用
df <- expand_grid(x = c("a", NA), y = c("b", NA))
df
# A tibble: 4 x 2
# x y
# <chr> <chr>
# 1 a b
# 2 a NA
# 3 NA b
# 4 NA NA
df %>% unite("z", x:y, remove = FALSE) #若remove = TRUE,則不保留x和y列
# A tibble: 4 x 3
# z x y
# <chr> <chr> <chr>
# 1 a_b a b
# 2 a_NA a NA
# 3 NA_b NA b
# 4 NA_NA NA NA
df %>% unite("z", x:y, na.rm = TRUE, remove = FALSE)
# A tibble: 4 x 3
# z x y
# <chr> <chr> <chr>
# 1 "a_b" a b
# 2 "a" a NA
# 3 "b" NA b
# 4 "" NA NA
4. separate分割一列為多列
類似于reshape2中的colsplit函數
- 語法
separate(data, col, into, sep = "[^[:alnum:]]+", remove = TRUE, convert = FALSE, extra = "warn", fill = "warn", ...)
- 參數
參數 | 含義 |
---|---|
data | 為數據框 |
col | 需要被拆分的列 |
into | 新建的列名,為字符串向量 |
sep | 被拆分列的分隔符 |
remove | 是否刪除被分割的列 |
convert | 為TRUE時會自動在新列上使用type.convert函數,其中as.is = TRUE,默認值為FALSE |
extra | 當分割成的列多于length(into)時,"warn"(默認值) 發出警告并刪除多余值,"drop"直接刪除多余值,"merge"僅分割length(into)次 |
fill | 當分割成的列少于length(into)時,"warn"(默認值) 發出警告并從右側填充缺失值,"right"直接從右側填充缺失值,"left"直接從左側填充缺失值 |
- 使用
library(dplyr)
df <- data.frame(x = c(NA, "a.b", "a.d", "b.c"))
#分割為兩列,保留NA值
df %>% separate(x, c("A", "B"))
df <- data.frame(x = c("a", "a b", "a b c", NA))
#分割為兩列,發出warning并刪除多余的列,缺失的列從右以NA填充
df %>% separate(x, c("a", "b"))
#分割為兩列,直接刪除多余的列,缺失的列從右以NA填充
df %>% separate(x, c("a", "b"), extra = "drop", fill = "right")
#分割兩次(設置的列為兩列),缺失的列從左以NA填充
df %>% separate(x, c("a", "b"), extra = "merge", fill = "left")
df <- data.frame(date = c("2017-03-08 01:20:20", "2017-03-09 02:30:30", "2017-03-10 03:40:40"))
#分割為year,month,day,hour,minute,second六列
df %>%
separate(date, c("day", "time"), sep = " ") %>%
separate(day, c("year", "month", "day"), sep = "-") %>%
separate(time, c("hour", "minute", "second"), sep = ":")
與separate不同的是extract使用正則表達式regex提取需要分割的列,當輸入為NA或者不能匹配regex時,輸出為NA。
extract(data, col, into, regex = "([[:alnum:]]+)", remove = TRUE, convert = FALSE, ...)
library(dplyr)
df <- data.frame(x = c(NA, "a.b", "a.d", "b.c"))
#分割為兩列,regex匹配要分割的列
df %>% extract(x, c("a", "b"), regex = "([a-d]+).([a-d]+)")
df %>% extract(x, c("A", "B"), "([[:alnum:]]+).([[:alnum:]]+)")
#分割為兩列,regex匹配要分割的列,不能匹配列的輸出為NA
df %>% extract(x, c("a", "b"), regex = "([a-d]+).([a-c]+)")
#分割為一列
df %>% extract(x, c("a"), regex = "([a-d]+)")
df %>% extract(x, c("a"))
separate_rows用于將列分割為多行,”... ”用于設置需要分割的列,sep用于設置分隔符,需要注意的是分割多個列時,每個列分割成的行數必須要一致。
separate_rows(data, ..., sep = "[^[:alnum:].]+", convert = FALSE)
library(dplyr)
df <- data.frame(
x = 1:3,
y = c("a", "d,e,f", "g,h"),
z = c("1", "2,3,4", "5,6"),
stringsAsFactors = FALSE
)
#分割y和z列,轉換為行
separate_rows(df, y, z, convert = TRUE)
5. 缺失值處理
tidyr包提供了簡單的缺失值處理方法,包括替換,填充,刪除等
- 使用給定值替換每列的缺失值
replace_na(data, replace = list(), ...)
# data:為數據框
# replace:替換值用于替換每個列中NA
library(dplyr)
df <- tibble(x = c(1, 2, NA), y = c("a", NA, "b"))
#以0替換x中的NA,以unknown替換y中的NA
df %>% replace_na(list(x = 0, y = "unknown"))
- 以前一個值填充缺失值,默認自上向下填充
fill(data, ..., .direction = c("down", "up"))
# data:為數據框
# …:指定需要被填充的列, 可用于選擇兩列之間的所有列col1:coln, 排除列-coln
# .direction :填充的方向,默認為down,自上向下填充
df <- data.frame(x = 1:5, y = c(10, NA, 15, NA, 20))
#自上向下替換NA值
df %>% fill(y)
df %>% fill(y, .direction = "down")
#自下向上替換NA值
df %>% fill(y, .direction = "up")
- 填充以創建完整的序列值向量
full_seq(x, period, tol = 1e-06)
# x:數值向量
# period:觀測值間的間隔,并檢測現有數據是否與這個間隔匹配,,不匹配時報錯
#返回序列1:6
full_seq(c(1, 2, 4, 6), 1)
#period值與原數據間隔不匹配,報錯Error: `x` is not a regular sequence.
full_seq(c(1, 2, 4, 6), 2)
#返回序列1:13,間隔為2
full_seq(c(1, 5, 9, 13), 2)
- 刪除包含缺失值的行
drop_na(data, ...)
# data:為數據框
# …:指定需要被填充的列, 可用于選擇兩列之間的所有列col1:coln, 排除列-coln
df <- data_frame(x = c(1, 2, NA), y = c("a", NA, "b"))
#刪除變量x中NA對應的行
df %>% drop_na(x)
#刪除變量y中NA對應的行
df %>% drop_na(y)
#未設置列,刪除變量x和y中NA對應的行
df %>% drop_na()
- 轉換隱式的缺失值為顯式的
complete(data, ..., fill = list())
# data:為數據框
# …:指定需要擴展的列,每個輸入列都作為一個獨立的參數用于擴展數據框。其中使用crossing或者直接輸入列作為參數時,會使用每個列中的元素進行擴展,即使生成的組合在原數據框中不存在;而使用nesting函數時,返回的每個列元素的組合必須在原數據框中存在。
# fill:用于設置填充值以替換NA
df <- data_frame(
group = c(1:2, 1),
item_id = c(1:2, 2),
item_name = c("a", "b", "b"),
value1 = 1:3,
value2 = 4:6
)
#以item_id和item_name中的每個元素擴展原數據框, 組合后的缺失值以NA代替
df %>% complete(item_id, item_name)
df %>% complete(crossing(item_id, item_name))
#以item_id和item_name中的每個元素擴展原數據框, 并以給定值替換缺失值
df %>% complete(item_id, item_name, fill = list(group = 0, value1 = 0, value2 = 0))
#以item_id和item_name中的每個元素擴展原數據框,只返回原數據框中存在的組合
df %>% complete(nesting(item_id, item_name))
#保留group,以item_id和item_name中的每個元素擴展原數據框,只返回原數據框
#中item_id和item_name存在的組合
df %>% complete(group, nesting(item_id, item_name))
df %>% complete(group, nesting(item_id, item_name), fill = list(value1 = 0, value2 = 0))
#保留group,以item_id和item_name中的每個元素擴展原數據框,返回所有item_id
#和item_name存在的組合
df %>% complete(group, crossing(item_id, item_name))
df %>% complete(group, crossing(item_id, item_name), fill = list(value1 = 0, value2 = 0))
參考:https://blog.csdn.net/wltom1985/article/details/107902563