每个因子级别内所有列的所有可能行对之间的差异

时间:2018-06-13 10:00:31

标签: r dplyr combn

我知道这是一个常见的问题,但我无法做到这一点。

我想在分类变量name的每个级别的数据框中构建所有可能的行,然后在这些行中区分这些行所有非因子变量的每个级别name:第1行 - 第2行,第1行 - 第3行,...

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应保持不变。但这是一个奖励,我想首先要更改X1X2并保留因子name

我知道我可以使用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() 

2 个答案:

答案 0 :(得分:1)

我无法找到如何使用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

答案 1 :(得分:0)

我的样本看起来不一样......

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

使用此功能,并查看here,我们可以:

library(dplyr)
library(tidyr)
library(purrr)

df %>% 
  group_by(name) %>% 
  nest() %>% 
  mutate(data = map(data, ~as.data.frame(map(.x, ~as.numeric(dist(.)))))) %>% 
  unnest()
# A tibble: 13 x 5
   name     ID    X1    X2  bool
   <fct> <dbl> <dbl> <dbl> <dbl>
 1 A         1   197   109     1
 2 A         2    15   765     1
 3 A         3     6   183     1
 4 A         1   182   874     0
 5 A         2   191   292     0
 6 A         1     9   582     0
 7 B         1   309     7     0
 8 B         2    54    91     1
 9 B         3    75   480     1
10 B         1   255    98     1
11 B         2   234   473     1
12 B         1    21   571     0
13 C         1   320   132     0

但这是未签名的。可替换地:

df %>% 
  group_by(name) %>% 
  nest() %>% 
  mutate(data = map(data, ~as.data.frame(map(.x, ~combn(., 2, diff))))) %>% 
  unnest()
# A tibble: 13 x 5
   name     ID    X1    X2  bool
   <fct> <int> <int> <int> <int>
 1 A         1  -197  -109     1
 2 A         2   -15   765     1
 3 A         3    -6   183     1
 4 A         1   182   874     0
 5 A         2   191   292     0
 6 A         1     9  -582     0
 7 B         1  -309     7     0
 8 B         2   -54   -91     1
 9 B         3   -75   480     1
10 B         1   255   -98     1
11 B         2   234   473     1
12 B         1   -21   571     0
13 C         1   320   132     0