0

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

我想在分类变量的每个级别内的数据框中构建所有可能的行对,然后在每个级别内为所有非因子变量生成这些行的差异:第 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() 
4

2 回答 2

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
于 2018-06-14T13:14:23.017 回答
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

使用这个,看看这里,我们可以做到:

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
于 2018-06-13T10:21:05.247 回答