2016-09-14 15 views
-8

比方說,我想打一個數據幀與數字列和字符列:如何將行添加到循環內的數據框而不強制所有列爲相同類型?

df<-data.frame() 
for(i in 1:26) { 
    df<-rbind(df, cbind(x=i, y=toString(i))) 
} 
str(df) 
'data.frame': 26 obs. of 2 variables: 
$ x: Factor w/ 26 levels "1","2","3","4",..: 1 2 3 4 5 6 7 8 9 10 ... 
    ..- attr(*, "names")= chr "x" "x" "x" "x" ... 
$ y: Factor w/ 26 levels "1","2","3","4",..: 1 2 3 4 5 6 7 8 9 10 ... 
    ..- attr(*, "names")= chr "y" "y" "y" "y" ... 

哎呀,我不想因素。

df2<-data.frame() 
for(i in 1:26) { 
    df2<-rbind(df2, cbind(x=i, y=toString(i)), stringsAsFactors=FALSE) 
    } 
str(df2) 
'data.frame': 26 obs. of 2 variables: 
$ x: chr "1" "2" "3" "4" ... 
$ y: chr "1" "2" "3" "4" ... 

現在一切都是一個字符。我可以計算出,以避免這種情況的唯一方法是通過在年底構建單獨的載體中,然後形成數據幀:

x<-NULL 
y<-NULL 
for(i in 1:26) { 
    x<-c(x, i) 
    y<-c(y, toString(i)) 
} 
df3<-data.frame(x, y, stringsAsFactors=FALSE) 
str(df3) 
'data.frame': 26 obs. of 2 variables: 
$ x: int 1 2 3 4 5 6 7 8 9 10 ... 
$ y: chr "1" "2" "3" "4" ... 

但正如你所看到的,這需要額外的代碼。如果您有一個包含20列的數據框,則需要20個循環前的初始化語句和循環內的20個語句才能添加到向量中。

是否有一個更簡潔的方法來完成這個?

+0

我認爲最好將它作爲'list'來避免類型轉換 – akrun

+0

您是否必須在每一步都指定df?這似乎非常低效。爲什麼不只是輕鬆地完成所有的步驟,然後'do.call(rbind,list)'? – Shape

+8

**從不**將行添加到循環中的data.frame。當你沒有描述實際問題時,這看起來像是一個典型的XY問題,而是尋找幫助解決非常糟糕的問題。我建議你不要描述你如何解決它,而是描述你實際想要達到的目標。 –

回答

3

不要這樣做。由於內存管理,在循環中增加對象的速度非常慢。正如評論告訴你的,你不太可能需要遍歷行。但是,如果你需要這樣做,你應該預先分配向量,分配給它們,並在循環之後將它們組合成一個data.frame。在循環中使用單獨向量(或者可以使用向量列表)的原因是data.frame子集分配也很慢。

x <- integer(26) 
y <- character(26) 
for(i in 1:26) { 
    x[i] <- i 
    y[i] <- toString(i) 
} 

df <- data.frame(x, y, stringsAsFactors = FALSE) 
str(df) 
#'data.frame': 26 obs. of 2 variables: 
# $ x: int 1 2 3 4 5 6 7 8 9 10 ... 
# $ y: chr "1" "2" "3" "4" ... 

如果你有很多列,你至少應該知道他們的類。然後,你可以這樣做:

colclasses <- c("integer", "character") 
l <- lapply(colclasses, vector, length = 26) 
for(i in 1:26) { 
    l[[1]][i] <- i 
    l[[2]][i] <- toString(i) 
} 
names(l) <- c("x", "y") 
df <- as.data.frame(l, stringsAsFactors = FALSE) 

編輯:

既然你想要的東西簡潔,可以考慮使用lapply

l <- lapply(1:26, function(i) list(x = i, y = toString(i))) 
df <- do.call(rbind.data.frame, l) 
+0

如果我不關心性能(我的數據幀很小,並且內存管理時間與循環內部的計算相比很小),但是我擔心代碼的簡潔性,沒有辦法在沒有爲數據幀的每一列單獨初始化和附加行? –

+0

如果你想簡潔的代碼,你不應該使用'for'循環。您一再被告知,您的實際問題可能有更好的(更高效的*和更優雅的)解決方案。 PS:真的沒有理由在一個循環中生成一個對象。你不會用其他語言來做。原因是這是一個主要的表演罪。 – Roland

+0

一般而言,我避免了'for'循環,但在這種情況下,我看不到它。 –

-5

我知道這將是downvoted遺忘,但這裏有一個解決方案,我的同事想出了:

df<-data.frame() 
for(i in 1:26) { 
    df<-rbind(df, data.frame(x=i, y=toString(i), stringsAsFactors=FALSE)) 
} 
str(df) 
'data.frame': 26 obs. of 2 variables: 
$ x: int 1 2 3 4 5 6 7 8 9 10 ... 
$ y: chr "1" "2" "3" "4" ... 

性能可能是差,但它是我一直在尋找的那種簡潔的解決方案的。

相關問題