首页 > 解决方案 > 每个因子水平内所有列的所有可能行对之间的差异

问题描述

我知道这是一个常见问题,但我无法完成这项工作。

我想在分类变量的每个级别内的数据框中构建所有可能的行对,然后在每个级别内为所有非因子变量生成这些行的差异:第 1 行 - 第 2 行,第 1 行 - 第 3 行, …</p> namename

set.seed(9) 
df <- data.frame(ID = 1:10, 
                 name=as.factor(rep(LETTERS, each=4)[1:10]), 
                 X1 = sample(1001, 10), 
                 X2 = sample(1001, 10), 
                 bool=sample(c(TRUE, FALSE), 10, replace = TRUE),
                 fruit = as.factor(sample(c("Apple", "Orange", "Kiwi" ), 10, replace = TRUE)))

这是示例的样子:

   ID name  X1  X2  bool  fruit
1   1    A 222 118 FALSE  Apple
2   2    A  25   9  TRUE   Kiwi
3   3    A 207 883  TRUE Orange
4   4    A 216 301  TRUE   Kiwi
5   5    B 443 492 FALSE  Apple
6   6    B 134 499 FALSE   Kiwi
7   7    B 389 401  TRUE   Kiwi
8   8    B 368 972  TRUE   Kiwi
9   9    C 665 356 FALSE  Apple
10 10    C 985 488 FALSE   Kiwi

我想得到一个 13 行的数据框,如下所示:

   ID  name  X1   X2  bool  fruit
1  1-2    A 197  109    -1  Apple
2  1-3    A  15 -765    -1   Kiwi
…

请注意,该因子fruit应保持不变。但这是一个额外的好处,我首先希望改变 and 并X1保留因素。X2name

我知道我可以使用combn函数,但我不知道该怎么做。我更喜欢带有dplyr包和group_by功能的解决方案。

我已经设法dplyr使用使用为连续行创建所有差异

varnotfac <- names(df)[!sapply(df, is.factor )] # remove factorial variable
# but not logical variable

library(dplyr)
diff <- df%>%
  group_by(name) %>%
  mutate_at(varnotfac, funs(. - lead(.))) %>% #      
  na.omit() 

标签: rdplyrcombn

解决方案


我不知道如何使用filter_if/来保存所有变量,filter_at所以我使用了select_at. 所以从@Axeman的回答

set.seed(9)
varnotfac <- names(df)[!sapply(df, is.factor )] # names of non-factorial variables

 diff1<- df %>%
  group_by(name) %>%
  select_at(vars(varnotfac)) %>%
  nest() %>% 
  mutate(data = purrr::map(data, ~as.data.frame(map(.x, ~combn(., 2, base::diff))))) %>% 
  unnest()

或者使用该outer功能,它的速度比combn

set.seed(9)
varnotfac <- names(df)[!sapply(df, is.factor )] # names of non-factorial variables

allpairs <- function(v){
  y <- outer(v,v,'-')
  z <- y[lower.tri(y)]
  return(z)
}

diff2<- df %>%
  group_by(name) %>%
  select_at(vars(varnotfac)) %>%
  nest() %>% 
  mutate(data = purrr::map(data, ~as.data.frame(map(.x, ~allpairs(.))))) %>% 
  unnest()
)

可以检查获得的 data.frame 是否与

all.equal(diff1,diff2)
[1] TRUE

推荐阅读