dplyr 1.0.0 之 rowwise
加載包
library(tidyverse, warn.conflicts = F)
<br />在 R 中 dplyr 通常是對列進行操作,然而對于行處理方面還是b比較困難,本節(jié)我們將學(xué)習(xí)通過 rowwise()函數(shù)來對數(shù)據(jù)進行行處理,常與 c_across() 連用。<br />
<br />本節(jié)中列舉了三個常見的案例:<br />
- 行水平的計算(比如,xyz 的平均值)
- 使用不同的參數(shù)調(diào)用同一個函數(shù)
- 對列表列進行操作
<br />當(dāng)然這些問題我們可以通過類似 for 等循環(huán)來進行操作,但是我們可以通過管道的形式進行更便捷的操作,這里作者有一句經(jīng)典的話:<br />
Of course, someone has to write loops. It doesn’t have to be you. — Jenny Bryan
<a name="a6d31b10"></a>
實戰(zhàn):
<br />rowwise 按行來進行分組,和 group_by() 函數(shù)一樣,并不會改變數(shù)據(jù)得內(nèi)容,僅僅是進行分組:<br />
df <- tibble(x = 1:2, y = 3:4, z = 5:6)
df %>% rowwise()
# 計算的是數(shù)據(jù)中所有的數(shù)值的平均值
df %>% mutate(m = mean(c(x, y, z)))
# 計算每一列的平均值
df %>% mutate(across(everything(), ~mean(.x, na.rm = T)))
# 計算的是每一行的平均值
df %>% rowwise() %>% mutate(m = mean(c(x, y, z)))
<a name="c5649d16"></a>
rowwise() 與 summarise() 函數(shù)連用
df <- tibble(name = c("Mara", "Hadley"), x = 1:2, y = 3:4, z = 5:6)
# 結(jié)果僅僅只有值
df %>%
rowwise() %>%
summarise(m = mean(c(x, y, z)))
# 可以通過加上需要處理的行作為 summarise() 的行名,可以使用 `rowwise(name)`,保留 `name` 列
df %>%
rowwise(name) %>%
summarise(m = mean(c(x, y, z)))
<a name="e2c5cace"></a>
每一行進行統(tǒng)計
df <- tibble(id = 1:6, w = 10:15, x = 20:25, y = 30:35, z = 40:45)
df
# 使用 `rowwise` 對數(shù)據(jù)進行行分組
rf <- df %>% rowwise(id)
rf %>% mutate(total = sum(c(w, x, y, z)))
rf %>% summarise(total = sum(c(w, x, y, z)))
<a name="b2d1310f"></a>
多列 c_across() 聯(lián)合操作
rf %>% mutate(total = sum(c_across(w:z)))
rf %>% mutate(total = sum(c_across(where(is.numeric))))
<a name="c275761c"></a>
rowwise() 、c_across()、across() 連用
ungroup()取消分組,這里表示取消按照行進行分組
rf %>%
mutate(total = sum(c_across(w:z))) %>%
ungroup() %>%
mutate(across(w:z, ~ . / total))
<a name="b09a9c97"></a>
行處理函數(shù)總結(jié):rowSums() 和 rowMeans()
內(nèi)置行處理函數(shù)更快,對行進行操作,沒有分成行、然后統(tǒng)計,最后連接到一起。
df %>% mutate(total = rowSums(across(where(is.numeric))))
df %>% mutate(mean = rowMeans(across(where(is.numeric))))
<a name="ec71b358"></a>
列表-列
df <- tibble(
x = list(1, 2:3, 4:6)
)
# 計算列表中向量的個數(shù),返回的是列的長度,而不是列表中每一個向量的長度
df %>% mutate(l = length(x))
# 計算列表中單個向量的長度
df %>% mutate(l = lengths(x))
# 或者利用 sapply()、vapply() map() 函數(shù)功能實現(xiàn)
df %>% mutate(l = sapply(x, length))
df %>% mutate(l = purrr::map_int(x, length))
# 我們可以通過 rowwise() 函數(shù)來實現(xiàn)
df %>%
rowwise() %>%
mutate(l = length(x))
<a name="5d04e51c"></a>
Subsetting:取子集
df <- tibble(g = 1:2, y = list(1:3, "a"))
gf <- df %>% group_by(g)
rf <- df %>% rowwise(g)
gf %>% mutate(type = typeof(y), length = length(y))
rf %>% mutate(type = typeof(y), length = length(y))
<a name="2c6a15d0"></a>
通過 for 循環(huán)來計算列表中子向量的長度應(yīng)該取 [[]] 而非 []
# grouped
out1 <- integer(2)
for (i in 1:2) {
out1[[i]] <- length(df$y[i])
}
out1
# rowwise
out2 <- integer(2)
for (i in 1:2) {
out2[[i]] <- length(df$y[[i]])
}
out2
<a name="709da5d0"></a>
當(dāng) group_by() 和 rowwise() 分組后添加新的列時,應(yīng)該注意以下
gf %>% mutate(y2 = y)
# 報錯,由于 rowwise 的結(jié)果是列表中子向量的值,長度不一致
# rf %>% mutate(y2 = y)
# 通過 `list()` 函數(shù)將其存儲為一個 list()
rf %>% mutate(y2 = list(y))
<a name="9c427e2d"></a>
Modelling:建模(無腦運行的。)
nest_by()分組存儲為一個 list
by_cyl <- mtcars %>% nest_by(cyl)
by_cyl
<a name="2524ce58"></a>
按行線性建模
mods <- by_cyl %>% mutate(mod = list(lm(mpg ~ wt, data = data)))
mods
mods <- mods %>% mutate(pred = list(predict(mod, data)))
mods
<a name="5105b123"></a>
summarise() 函數(shù)進行統(tǒng)計
mods %>% summarise(rmse = sqrt(mean((pred - data$mpg) ^ 2)))
mods %>% summarise(rsq = summary(mod)$r.squared)
mods %>% summarise(broom::glance(mod))
mods %>% summarise(broom::tidy(mod))
<a name="35610ed3"></a>
重復(fù)的函數(shù)調(diào)用:按行傳入變量參數(shù)
<br />rowwise() 不僅適用于返回長度為 1 的向量的函數(shù); 如果結(jié)果是一個列表,它可以與任何函數(shù)一起連用。這意味著 rowwise() 和 mutate() 提供了一種優(yōu)雅的方法,可以多次使用不同的參數(shù)調(diào)用函數(shù),將輸出存儲在輸入旁邊。<br />
一定要用
list()函數(shù)來將命令括起來,比如list(runif(n, min, max))而非runif(n, min, max)
df <- tribble(
~ n, ~ min, ~ max,
1, 0, 1,
2, 10, 100,
3, 100, 1000,
)
df %>%
rowwise() %>%
mutate(data = list(runif(n, min, max)))
# 會報錯
df %>%
rowwise() %>%
mutate(data = runif(n, min, max))
<a name="194c5bcf"></a>
兩兩多重組合:tidyr::expand_grid() 函數(shù)
# 這里就會得到 3*3 九種結(jié)果
df <- expand.grid(mean = c(-1, 0, 1), sd = c(1, 10, 100))
df %>%
rowwise() %>%
mutate(data = list(rnorm(10, mean, sd)))
<a name="bc13740f"></a>
各種功能:結(jié)合 do.call()
df <- tribble(
~rng, ~params,
"runif", list(n = 10),
"rnorm", list(n = 20),
"rpois", list(n = 10, lambda = 5),
) %>%
rowwise()
df %>%
mutate(data = list(do.call(rng, params)))
<a name="772ab8dd"></a>
以前的操作
作者建議使用
purrr中map()函數(shù)執(zhí)行行操作,但是又會增加額外學(xué)習(xí)。