dplyr 1.0.0 之 rowwise

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>

以前的操作

作者建議使用 purrrmap() 函數(shù)執(zhí)行行操作,但是又會增加額外學(xué)習(xí)。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容