# 第 45 章 tidyverse中行方向的操作

dplyr 1.0 推出之后，数据框行方向的操作得到完美解决，因此本章的内容已经过时，大家可以跳出本章，直接阅读第21 章。（留着本章，主要是让自己时常回顾下之前的探索。让自己最难忘的，或许就是曾经的痛点吧）

library(tidyverse)

tidyverse 喜欢数据框，因为一列就是一个向量，一列一列的处理起来很方便。然而我们有时候也要，完成行方向的操作，所以有必要介绍tidyverse中行方向的处理机制。

## 45.1 问题

df <- tibble(x = 1:3, y = 4:6)
df

## 45.2 rowwise函数

dplyr提供了rowwise函数，但大神说不推荐

df %>%
rowwise() %>%
mutate(i = sum(x, y))
df %>%
rowwise() %>%
mutate(i = mean(c(x, y)))
df %>%
rowwise() %>%
mutate(
min = min(x, y),
max = max(x, y)
)
df %>%
rowwise() %>%
do(i = mean(c(.$x, .$y))) %>%
unnest(i)

## 45.3 Row-wise Summaries

df %>% mutate(row_sum = rowSums(.[1:2]))
df %>% mutate(row_mean = rowMeans(.[1:2]))
df %>% mutate(t_sum = rowSums(select_if(., is.numeric)))

## 45.4 purrr::map方案

df %>% mutate(t_sum = pmap_dbl(list(x, y), sum))
df %>%
mutate(t_sum = pmap_dbl(select_if(., is.numeric), sum))

df %>% mutate(t_sum = pmap_dbl(select_if(., is.numeric), mean))

tidyverse 总会想出办法来解决，把mean() 变成 lift_vd(mean)

df %>%
mutate(data = pmap_dbl(select_if(., is.numeric), lift_vd(mean)))

df %>% mutate(t_median = pmap_dbl(select_if(., is.numeric), lift_vd(median)))
df %>% mutate(t_sd = pmap_dbl(select_if(., is.numeric), lift_vd(sd)))

## 45.5 tidy 的方案

new_df <- df %>%
mutate(id = row_number())

s <- new_df %>%
gather("time", "val", -id) %>%
group_by(id) %>%
summarize(
t_avg = mean(val),
t_sum = sum(val)
)

s
new_df %>%
left_join(s)

ss <- new_df %>%
group_by(id) %>%
summarise(t_avg = mean(c(x, y)))

ss
new_df %>%
left_join(ss)

## 45.6 用slide方案

slide很强大，可以滚动喔

• 如果第一个参数是数据框，slide把数据框看作a vector of rows， 然后行方向的滚动，事实上， .x是一个个的小数据框（如下）
• purrr::map不同，因为map把数据框看作列方向的向量， 然后迭代
• 如果第一个参数是原子型向量的话，还是依次迭代逗号分隔的元素，只不过这里是slide比map更强大的是，还可以是滚动
library(slider)

df <- tibble(a = 1:3, b = 4:6)

slide(
select_if(df, is.numeric),
~.x,
.before = 1
)
df %>%
mutate(
r_mean = slide_dbl(
select_if(df, is.numeric),
~ mean(unlist(.x)),
.before = 1
)
)

## 45.7 rowwise() + c_across()

df <- tibble(id = 1:6, w = 10:15, x = 20:25, y = 30:35, z = 40:45)
df

df %>%
rowwise(id) %>%
summarise(mean = mean(c(w, x, y, z)))

df %>%
rowwise(id) %>%
mutate(mean = mean(c(w, x, y, z)))

df %>%
rowwise(id) %>%
mutate(total = mean(c_across(w:z)))

df %>%
rowwise(id) %>%
mutate(mean = mean(c_across(is.numeric)))

# across()
df %>% mutate(mean = rowMeans(across(is.numeric & -id)))

## 45.8 用lay方案

lay包解决方案

library(lay)
library(dplyr, warn.conflicts = FALSE)

iris <- as_tibble(iris)

# apply mean to each "row"
iris %>%
mutate(sepal = lay(across(starts_with("Sepal")), mean))