R 将两个数据帧绑定在一起时如何合并因子?
这是一个相当小的复制代码。真实的数据集较大且有许多因素,因此手动列出因素是不实际的。还有一些更有趣的数据转换,我想继续使用dplyrR 将两个数据帧绑定在一起时如何合并因子?,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
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或dplyrrbind
/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