Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/r/67.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
R 将两个数据帧绑定在一起时如何合并因子?_R_Dplyr_Tibble - Fatal编程技术网

R 将两个数据帧绑定在一起时如何合并因子?

R 将两个数据帧绑定在一起时如何合并因子?,r,dplyr,tibble,R,Dplyr,Tibble,这是一个相当小的复制代码。真实的数据集较大且有许多因素,因此手动列出因素是不实际的。还有一些更有趣的数据转换,我想继续使用dplyr library(dplyr) a = data.frame(f=factor(c("a", "b")), g=c("a", "a")) b = data.frame(f=factor(c("a", "c")), g=c("a", "a")) a = a %>% group_by(g) %>% mutate(n=1) b = b %>% group

这是一个相当小的复制代码。真实的数据集较大且有许多因素,因此手动列出因素是不实际的。还有一些更有趣的数据转换,我想继续使用dplyr

library(dplyr)
a = data.frame(f=factor(c("a", "b")), g=c("a", "a"))
b = data.frame(f=factor(c("a", "c")), g=c("a", "a"))
a = a %>% group_by(g) %>% mutate(n=1)
b = b %>% group_by(g) %>% mutate(n=2)
rbind(a,b)
这将产生:

# A tibble: 4 x 3
# Groups:   g [1]
      f      g     n
  <chr> <fctr> <dbl>
1     a      a     1
2     b      a     1
3     a      a     2
4     c      a     2
Warning messages:
1: In bind_rows_(x, .id) : Unequal factor levels: coercing to character
2: In bind_rows_(x, .id) :
  binding character and factor vector, coercing into character vector
3: In bind_rows_(x, .id) :
  binding character and factor vector, coercing into character vector
rbind
之前显式转换为
data.frame
,同样有效:

> rbind(data.frame(a),data.frame(b))
  f g n
1 a a 1
2 b a 1
3 a a 2
4 c a 2
有没有一种简单的方法可以使用base R或dplyr
rbind
/
bind_rows
自动合并这些因素及其级别,而不是将它们转换为字符(这对我来说毫无意义),同时仍然使用dplyr进行数据转换

我发现它提出了一个手动合并因子的解决方案,但这非常冗长

我的实际用例是使用
read.table
加载两个.csv文件,进行一些数据转换,然后合并互补的数据。 我目前的解决方法是在数据转换结束时调用
data.frame(data)

我想知道为什么dplyr/tibble不会自动合并因子,因为在这种情况下似乎是安全的。这是不是可以改进?

使用
数据的解决方案。表

数据.frame
转换为
数据.table
并使用
:=
(无需
dplyr
)添加
n


a如果因子只是字符串的有效存储,则可以在合并之前将其转换为字符串,然后再转换为因子:

bind_rowsFactors <- function(
  ### bind_rows on two data.frames with merging factors levels
  a      ##<< first data.frame to bind
  , b    ##<< second data.frame to bind
  , ...  ##<< further arguments to \code{bind_rows}
){
  isInconsistentFactor <- sapply( names(a),  function(col){
    (is.factor(a[[col]]) | is.factor(b[[col]])) &&
      any(levels(a[[col]]) != levels(b[[col]]))
  })
  if (sum(isInconsistentFactor)) warning(
    "releveling factors ", paste(names(a)[isInconsistentFactor], collapse = ","))
  for (col in names(a)[isInconsistentFactor]) {
    a <- mutate(ungroup(a), !!col := as.character(!!rlang::sym(col)))
    b <- mutate(ungroup(b), !!col := as.character(!!rlang::sym(col)))
  }
  ans <- bind_rows(a, b, ...)
  # convert former factors form string back to factor
  for (col in names(ans)[isInconsistentFactor]) {
    ans <- mutate(ungroup(ans), !!col := factor(!!rlang::sym(col)))
  }
  ##value<< result of \code{bind_rows} with inconsistend factor columns still factors
  ans
}

library(dplyr)
a = data.frame(f = factor(c("a", "b")), g = c("a", "a"))
b = data.frame(f = factor(c("a", "c")), g = c("a", "a"))
a = a %>% group_by(g) %>% mutate(n = 1)
b = b %>% group_by(g) %>% mutate(n = 2)
#bind_rows(a,b)
bind_rowsFactors(a,b)

我在做类似的工作时遇到了这个问题。使用
forcats::lvls\u union
,您可以在本例中获得因子列表中所有级别的字符向量,
a$f
b$f
。然后您可以使用
forcats::fct_expand
来扩展每个数据帧的
f
,以获得因子级别的并集

库(tidyverse)
a%
突变(n=1)%>%
分组人(g)
b%
突变(n=2)%>%
分组人(g)
所有LVL%突变(f=fct\U扩展(f,所有LVL)),
b%>%突变(f=fct\U扩展(f,所有LVL))
)
#>#tibble:4 x 3
#>#组:g[1]
#>f g n
#>     
#>1 a 1
#>2 b a 1
#>3 a 2
#>4 c a 2
或者,为了获得相同的结果,您可以将两个数据帧的列表映射到
f
。使用
map\u-dfr
是一种速记,就像调用
map
,然后通过管道进入
bind\u行

map_-dfr(列表(a,b),~mutate(,f=fct_-expand(f,all_-lvls)))
#>#tibble:4 x 3
#>#组:g[1]
#>f g n
#>     
#>1 a 1
#>2 b a 1
#>3 a 2
#>4 c a 2

由(v0.2.0)于2018年7月17日创建。

为了避免警告,数据集<代码>因子列<代码>级别可以在之前更改,以适应另一个数据集中的<代码>级别。有点像一个
联盟
@akrun是的,这是一种方法,就像链接的帖子一样,但我不想手动执行此操作,而真实的数据集有许多因素和级别。另一种解决方法可能是使用
stringsAsFactors=FALSE
并仅在将输入文件绑定在一起后将您想要的列强制转换为
factor
,实际上根本不需要声明
n
,只需使用
idcol
参数:
rbind(a,b,idcol='n')
。这似乎是一个核心的
dplyr
bug。如果我们写
a$n=1;b$n=1;rbind(a,b)
(即,在
base
中执行此操作),没有错误。对,这是另一种解决方法。但当然,在我的真实案例中,我有一些dplyr的转换,这些转换很容易替换,还有一个更真实/更大的数据集。@eregon我建议1)用
dplyr
归档一个bug,2)让你的例子更像你的用例,因为这个答案解决了你的问题1)是的,我想先这么做,但是他们重定向到SO和他们的邮件列表(我也在其中发布了关于“为什么”的部分:)。2) 我在问题中添加了两句话,以澄清这是最小的,以及它与真实数据集/转换的区别
a <- data.frame(f=factor(c("a", "b")), g=c("a", "a"))
b <- data.frame(f=factor(c("a", "c")), g=c("a", "a"))
library(data.table)
rbind(setDT(a)[, n := 1], 
      setDT(b)[, n := 2])
   f g n
1: a a 1
2: b a 1
3: a a 2
4: c a 2
bind_rowsFactors <- function(
  ### bind_rows on two data.frames with merging factors levels
  a      ##<< first data.frame to bind
  , b    ##<< second data.frame to bind
  , ...  ##<< further arguments to \code{bind_rows}
){
  isInconsistentFactor <- sapply( names(a),  function(col){
    (is.factor(a[[col]]) | is.factor(b[[col]])) &&
      any(levels(a[[col]]) != levels(b[[col]]))
  })
  if (sum(isInconsistentFactor)) warning(
    "releveling factors ", paste(names(a)[isInconsistentFactor], collapse = ","))
  for (col in names(a)[isInconsistentFactor]) {
    a <- mutate(ungroup(a), !!col := as.character(!!rlang::sym(col)))
    b <- mutate(ungroup(b), !!col := as.character(!!rlang::sym(col)))
  }
  ans <- bind_rows(a, b, ...)
  # convert former factors form string back to factor
  for (col in names(ans)[isInconsistentFactor]) {
    ans <- mutate(ungroup(ans), !!col := factor(!!rlang::sym(col)))
  }
  ##value<< result of \code{bind_rows} with inconsistend factor columns still factors
  ans
}

library(dplyr)
a = data.frame(f = factor(c("a", "b")), g = c("a", "a"))
b = data.frame(f = factor(c("a", "c")), g = c("a", "a"))
a = a %>% group_by(g) %>% mutate(n = 1)
b = b %>% group_by(g) %>% mutate(n = 2)
#bind_rows(a,b)
bind_rowsFactors(a,b)
# A tibble: 4 x 3
  f     g         n
  <fct> <fct> <dbl>
1 a     a        1.
2 b     a        1.
3 a     a        2.
4 c     a        2.
Warning message:
In bind_rowsFactors(a, b) : releveling factors f