表操作基礎多表操作列操作基本操作多種函數功能當前列行操作構造數據集行匯總統計分組操作添加分組刪除分組變量動詞
前文:
R語言筆記-dplyr-1-基礎篇
表操作指像sql中的left join,inner join等表格之間的操作,或者是Excel中Power Piovt建模的建立關係,從而實現不同表格間的關聯
表格中的列操作,如列求和,均值等
行操作指不同欄位間的計算,如Excle的列與列之間計算,Excle中的函數對行列不敏感,沒有明顯區別,但是R中tidyverse裡列計算簡單,行間計算依賴rowwise()函數實現
基礎left_join(),full_join,inner_join()等動詞關聯兩個表。詳情請查看:vignette("two-table"),在R中執行。
left_join()實現類似Excel中VLOOKUP函數功能或資料庫中left join功能,將「右表」的欄位依據「主鍵」關聯到「左表」上。
left_join(),right_join(),full_join(),inner_join(),第一個以左表為主,第二個右表為主,第三個全連接,第四個內連接(只返回兩表中都有的記錄),和資料庫中連接方式一致。
默認會自動尋找兩表中相同的欄位名作為關聯的條件
library("nycflights13")
# Drop unimportant variables so it's easier to understand the join results.
flights2 <- flights %>% select(year:day, hour, origin, dest, tailnum, carrier)
flights2 %>%
left_join(airlines)指定關聯條件列,類似資料庫中on a.column = b.column
flights2 %>% left_join(planes, by = "tailnum")left_join(x,y,by = c("a" = "b", "c" = "d")) 將會匹配 x$a to y$b 和 x$c to y$d 作為關聯條件
#出發機場和目的機場信息
flights2 %>% left_join(airports, by = c("dest" = "faa"))
#flights2 %>% left_join(airports, c("origin" = "faa"))
# 組合條件 多條件時用向量包裹即可c("dest" = "faa","cola" = "colb"))anti_join() 刪除所有左表中在右表中匹配到的行
semi_join()保留所有左表在右表中匹配到的行
df1 <- tibble(a=letters[1:20],b=1:20)
df2 <- tibble(a=letters,b=1:26)
df1 %>% semi_join(df2)
df2 %>% anti_join(df1)intersect(x,y)返回x,y交集
union(x,y)返回x,y中唯一的值
setdiff(x,y)返回存在x中但是不存在y中的記錄
(df1 <- tibble(x = 1:2, y = c(1L, 1L)))
(df2 <- tibble(x = 1:2, y = 1:2))
intersect(df1, df2)
union(df1, df2)
setdiff(df1, df2)
setdiff(df2, df1)多表操作多表操作請使用purrr::reduce(),當需要合併多個表格時,可用以下方式減少合併代碼量。
dt1 <- data.frame(x = letters)
dt2 <- data.frame(x = letters,cola = 1:26)
dt3 <- data.frame(x = letters,colb = 1:26)
dt4 <- data.frame(x = letters,cold = 1:26)
dt5 <- data.frame(x = letters,cole = 1:26)
dtlist <- list(dt1,dt2,dt3,dt4,dt5)
purrr::reduce(dtlist,left_join,by='x')
列操作在多列上執行相同的操作是常用的操作,但是通過複製和粘貼代碼,麻煩不說還容易錯:
df %>%
group_by(g1, g2) %>%
summarise(a = mean(a), b = mean(b), c = mean(c), d = mean(d))通過across()函數可以更簡潔地重寫上面代碼:
df %>%
group_by(g1, g2) %>%
summarise(across(a:d, mean))基本操作across() 有兩個主要參數:
starwars %>%
summarise(across(where(is.character), ~ length(unique(.x))))
# 列屬性是字符的列求唯一值數
# starwars %>%
# summarise(length(unique(name)))
# starwars %>%
# summarise(length(unique(hair_color)))
starwars %>%
group_by(species) %>%
filter(n() > 1) %>%
summarise(across(c(sex, gender, homeworld), ~ length(unique(.x))))
starwars %>%
group_by(homeworld) %>%
filter(n() > 1) %>%
summarise(across(where(is.numeric), ~ mean(.x, na.rm = TRUE)))across() 不會選擇分組變量:
df <- data.frame(g = c(1, 1, 2), x = c(-1, 1, 3), y = c(-1, -4, -9))
df %>%
group_by(g) %>%
summarise(across(where(is.numeric), sum))多種函數功能通過在第二個參數提供函數或lambda函數的命名列表,可是使用多個函數轉換每個變量:
min_max <- list(
min = ~min(.x, na.rm = TRUE),
max = ~max(.x, na.rm = TRUE)
)
starwars %>% summarise(across(where(is.numeric), min_max))通過.names參數控制名稱:
NB:該參數的機制沒有特別理解,需多練習體會。主要是運用到匿名函數時
以下是官方圖冊中的案例,但是報錯:
starwars %>% summarise(across(where(is.numeric), min_max, .names = "{.fn}.{.col}"))修改後正常運行:
starwars %>% summarise(across(where(is.numeric), min_max, .names = "{fn}.{col}"))區別主要是.names參數的使用方式問題,.加不加的問題。
starwars %>% summarise(across(where(is.numeric), min_max, .names = "{fn}——{col}"))
當前列如果需要,可以通過調用訪問內部的「當前」列的名稱cur_column()。
該函數不是特別容易理解,需要多嘗試使用加深認識。
df <- tibble(x = 1:3, y = 3:5, z = 5:7)
mult <- list(x = 1, y = 10, z = 100)
df %>% mutate(across(all_of(names(mult)), ~ .x * mult[[cur_column()]]))
行操作在操縱數據框中,dplyr等工具讓我們對列操作相對簡單,但是對行操作則困難些。
構造數據集df <- tibble(x = 1:2, y = 3:4, z = 5:6)
df %>% rowwise()像group_by(),rowwise()並沒有做任何事情,它的作用是改變其他動詞的工作方式:比較以下代碼
df %>% mutate(m = mean(c(x, y, z)))
df %>% rowwise() %>% mutate(m = mean(c(x, y, z)))data.table中的操作:
library(data.table)
dt <- data.table(x = 1:2, y = 3:4, z = 5:6)
dt[,m:=mean(c(x,y,z))][]
dt[,m:=mean(c(x,y,z)),by=.(x)][]您可以選擇在調用中提供「標識符」變量rowwise()。這些變量在您調用時被保留summarise(),因此它們的行為與傳遞給的分組變量有些相似group_by():
df <- tibble(name = c("Mara", "Hadley"), x = 1:2, y = 3:4, z = 5:6)
df %>%
rowwise() %>%
summarise(m = mean(c(x, y, z)))
df %>%
rowwise(name) %>%
summarise(m = mean(c(x, y, z)))行匯總統計dplyr::summarise()使得匯總一列中各行的值非常容易。當與之結合使用時rowwise(),還可以輕鬆匯總一行中各列的值:
df <- tibble(id = 1:6, w = 10:15, x = 20:25, y = 30:35, z = 40:45)
rf <- df %>% rowwise(id)
rf %>% mutate(total = sum(c(w, x, y, z)))
rf %>% summarise(total = sum(c(w, x, y, z)))鍵入每個變量名稱很繁瑣,通過c_across()使更簡單
rf %>% mutate(total = sum(c_across(w:z)))
rf %>% mutate(total = sum(c_across(where(is.numeric))))
rf %>%
mutate(total = sum(c_across(w:z))) %>%
ungroup() %>%
mutate(across(w:z, ~ . / total))
分組操作詳情: https://cloud.r-project.org/web/packages/dplyr/vignettes/grouping.html
group_by()最重要的分組動詞,需要一個數據框和一個或多個變量進行分組:
添加分組by_species <- starwars %>% group_by(species)
by_sex_gender <- starwars %>% group_by(sex, gender)除了按照現有變量分組外,還可以按照函數處理後的變量分組,等效在mutate()之後執行group_by:
bmi_breaks <- c(0, 18.5, 25, 30, Inf)
starwars %>%
group_by(bmi_cat = cut(mass/(height/100)^2, breaks=bmi_breaks)) %>%
tally()刪除分組變量要刪除所有分組變量,使用ungroup():
by_species %>%
ungroup() %>%
tally()動詞summarise() 計算每個組的匯總,表示從group_keys開始右側添加匯總變量
by_species %>%
summarise(
n = n(),
height = mean(height, na.rm = TRUE)
)該.groups=參數控制輸出的分組結構。刪除右側分組變量的歷史行為對應於.groups = "drop_last"沒有消息或.groups = NULL有消息(默認值)。
從1.0.0版開始,分組信息可以保留(.groups = "keep")或刪除 (.groups = 'drop)
a <- by_species %>%
summarise(
n = n(),
height = mean(height, na.rm = TRUE),.groups='drop') %>%
group_vars()
b <- by_species %>%
summarise(
n = n(),
height = mean(height, na.rm = TRUE),.groups='keep') %>%
group_vars()
object.size(a)
object.size(b)在實際使用中,當數據較大時需要刪掉分組信息。以上可以看到保留分組信息的比沒保留的大了兩倍多。