【问题标题】:Mixed type in vector (rbind dataframe without typeconversion)向量中的混合类型(没有类型转换的 rbind 数据帧)
【发布时间】:2016-06-06 03:51:17
【问题描述】:

在 R 中,向量不能包含不同的类型。一切都必须例如是整数或一切都必须是字符等。这有时让我头疼。例如。当我想为 data.frame 添加边距时,需要一些列是数字,而其他列是字符。

下面是一个可重现的例子:

# dummy data.frame
set.seed(42)
test <- data.frame("name"=sample(letters[1:4], 10, replace=TRUE),
                   "val1" = runif(10,2,5),
                   "val2"=rnorm(10,10,5),
                   "Status"=sample(c("In progres", "Done"), 10, replace=TRUE),
                   stringsAsFactors = FALSE)

# check that e.g. "val1" is indeed numeric
is.numeric(test$val1)
# TRUE
# create coloumn sums for my margin.
tmpSums <- colSums(test[,c(2:3)])
# Are the sums numeric?
is.numeric(tmpSums[1])
#TRUE
# So add the margin
test2 <- rbind(test, c("All", tmpSums, "Mixed"))
# is it numeric
is.numeric(test2$val1)
#FALSE
# DAMN. Because the vector `c("All", tmpSums, "Mixed")` contains strings
# the whole vector is forced to be a string. And when doing the rbind
# the orginal data.frame is forced to a new type also

# my current workaround is to convert back to numeric
# but this seems convoluted, back and forward.
valColoumns <- grepl("val", names(test2))
test2[,valColoumns] <- apply(test2[,valColoumns],2, function(x) as.numeric(x))
is.numeric(test2$val1)
# finally. It works.

一定有更简单/更好的方法吗?

【问题讨论】:

  • 投反对票有点苛刻,不是吗?存在可重现的示例和 OP 的修复尝试。

标签: r types dataframe rbind


【解决方案1】:

这是一个使用data.table 的选项。我们将“data.frame”转换为“data.table”(setDT(test)),使用lapply 获取数字列的sum,将(c)与应该代表其他列的值连接起来,将其放在list 中并使用rbindlist

library(data.table)
rAll <-  setDT(test)[, c(name="All", lapply(.SD, sum), 
              Status="Mixed"), .SDcols= val1:val2]
rbindlist(list(test, rAll))

如果我们需要让它更自动化一点,

i1 <- sapply(test, is.numeric)
v1 <- setNames(list("All", "Mixed"), setdiff(names(test),
                      names(test)[i1]))
rAll <-  setDT(test)[, c(v1, lapply(.SD, sum)), 
                 .SDcols=i1][, names(test), with=FALSE]
rbindlist(list(test, rAll))

【讨论】:

  • 甜蜜。这是一个很好的答案。我必须将 'thelatemail' 答案标记为已接受,因为它更接近(使用 data.frame) - 但这是一个可以说的答案,我将使用同样多的 - 并且可能从中学到更多。
  • @Andreas 感谢您的反馈。是的,你应该标记 thelatemail 的答案,因为它是一个很好的原始想法。
【解决方案2】:

在您的rbind 中使用list 对象,例如:

test2 <- rbind(test, c("All", unname(as.list(tmpSums)), "Mixed"))

rbind 的第二个参数是一个列表,删除了会导致 rbind 失败的冲突名称:

c("All", unname(as.list(tmpSums)), "Mixed")
#[[1]]
#[1] "All"
# 
#[[2]]
#[1] 37.70092
#
#[[3]]
#[1] 91.82716
#
#[[4]]
#[1] "Mixed"

【讨论】:

  • 真的不值得单独回答,但data.tables 的rbind 有一个use.names 参数,可以让您跳过unname。口味问题。
  • 谢谢。我自己确实找到了未命名的位-但从未想过要使用列表。谢谢。
猜你喜欢
  • 1970-01-01
  • 2013-04-08
  • 2021-03-27
  • 2019-11-12
  • 1970-01-01
  • 1970-01-01
  • 2020-12-06
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多