2016-02-24 18 views
2

在R中,向量不能包含不同的類型。一切都必須是一個整數或者一切都必須是字符等。這有時會讓我頭痛。例如。當我想爲data.frame添加邊距,並且需要一些coloumns爲數字,其他爲字符時。向量中的混合類型(rbind dataframe without typeconversion)

下面重複的例子:

# 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. 

必須有一個更簡單/更好的辦法?

+0

Downvote是有點苛刻沒有?可複製的例子和OP的嘗試修復是存在的。 – thelatemail

回答

4

使用list對象在rbind,如:

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" 
+1

不是真的值得一個單獨的答案,但'data.table'的'rbind'有一個'use.names'參數,它可以讓你跳過'unname'。味道的問題。 – MichaelChirico

+0

謝謝。我確實找到了自己的名字 - 但從未想過要使用一個列表。謝謝。 – Andreas

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)) 
+1

甜。這是一個很好的答案。我必須將'thelatemail'答案標記爲接受,因爲它比較接近(使用data.frame) - 但這是有爭議的一個答案,我會盡可能多地使用 - 也許可以從中學到更多。 – Andreas

+0

@Andreas感謝您的反饋。是的,你應該將這個電子郵件的答案標出來,因爲它與原來的想法是一個很好的答案。 – akrun