2011-06-20 55 views
6

我需要按元素粘貼兩個數據框的內容以便輸入到另一個程序。我有一個手段的數據框架和平均值的標準錯誤的數據框架。將兩個數據框粘貼在一起R中的元素

我嘗試使用R paste()函數,但它似乎無法應付數據幀。在使用矢量時,它似乎將第一個矢量的所有元素連接成一個字符串,將第二個矢量的所有元素連接成一個單獨的字符串。相反,我需要將兩個數據幀中的每個相互元素連接在一起。

有關如何解決此問題的任何建議?我已經包含虛擬輸入數據(datMean和datSE)和我所需的輸出(datNew)。我的真實數據框大小約爲10行×150列。

# means and SEM 
datMean <- data.frame(a=rnorm(10, 3), b=rnorm(10, 3), d=rnorm(10, 3)) 
datSE <- data.frame(a=rnorm(10, 3)/100, b=rnorm(10, 3)/100, d=rnorm(10, 3)/100) 

# what the output should look like 
# i've chosen some arbitrary values here, and show only the first row. 
datNew <- data.frame(a="2.889-2.926", b="1.342-1.389", d="2.569-2.576") 

的想法是在datNew每個元素是由以下組成的範圍「的意思 - SE」和「平均值±SE」,用破折號分開「 - 」。 paste()函數可以爲一個元素做到這一點,如何在整個數據框中做到這一點?

paste(datMean[1,1] - datSE[1,1], datMean[1,1] + datSE[1,1], sep="-") 

編輯1: 看一些我知道我離開了一個重要的信息位的問題的答案。原始數據幀的每一行都被命名,我需要用這些名稱重構最後的數據幀。例如:

rownames(datMean) <- LETTERS[1:10] 
rownames(datSE) <- LETTERS[1:10] 

我需要datNew最終再次擁有這10個rownames。對於使用熔體()的一些解決方案,這可能會有問題。

回答

9

如果您先轉換爲矩陣,則可以在沒有應用或循環的情況下進行。

MdatMean <- as.matrix(datMean) 
MdatSE <- as.matrix(datSE) 
matrix(paste(MdatMean - MdatSE, MdatMean + MdatSE, sep="-"), 
     nrow=nrow(MdatMean), dimnames=dimnames(MdatMean)) 

你也可以考慮formatC更好的格式。

lo <- formatC(MdatMean - MdatSE, format="f", digits=3) 
hi <- formatC(MdatMean + MdatSE, format="f", digits=3) 
matrix(paste(lo, hi, sep="-"), 
     nrow=nrow(MdatMean), dimnames=dimnames(MdatMean)) 

如果你想在年底data.frame只是包裝的最後一行as.data.frame

+0

中使用參數'sep =「」'非常感謝這個 - 我決定接受這個作爲最好的答案,因爲它不依賴於外部包並且比替代方案更快,因爲它不依賴於應用程序或循環。 + 1 for formatC(),我以前沒有看過,格式也好多了。 – Steve

2

您可以一次對每行執行此操作,但是您正在應用兩個data.frames之間的配對列。既然你有一個具體的粘貼的工作,每次做的,定義函數:

pfun <- function(x, y) paste(x - y, x + y, sep = "-") 

,然後構建新的data.frame與功能:

datNew <- data.frame(a = pfun(datMean$a, datSE$a), b = pfun(datMean$b, datSE$b), d = pfun(datMean$d, datSE$d)) 

將會有應用此方法更簡潔,但也許這有助於你更好地理解。您可以傳遞整列來粘貼,但不能傳遞整個data.frames。

使用循環來匹配結果中的所有列,而無需單獨指定它們。

首先創建一個列表來存儲所有的列,我們將使用正確的列名轉換爲data.frame。

datNew <- vector("list", ncol(datMean)) 

命名確實假定列號,名稱和順序是兩個輸入data.frames之間的完全匹配。

names(datNew) <- names(datMean) 

for (i in 1:ncol(datMean)) { 
    datNew[[i]] <- pfun(datMean[[i]], datSE[[i]]) 
} 

轉換爲data.frame:

datNew <- as.data.frame(datNew) 
+0

這工作得很好,謝謝。對於150列以上的數據框,這將是很費力的。我想知道是否有辦法進一步自動化... – Steve

+0

已更新,以適應任何數量的列,fwiw – mdsumner

2

以下是我理解您的問題。我使用reshape2::melt將平均值和SE從多列到一列的數據融合。

library(reshape2) 
datMean <- melt(datMean)$value 
datSE <- melt(datSE)$value 
dat <- cbind(datMean, datSE) 

apply(X = dat, MARGIN = 1, FUN = function(x) { 
      paste(x[1] - x[2], x[1] + x[2], sep = " - ") 
     }) 

而結果

[1] "3.03886802467251 - 3.08551547263516" 
[2] "3.01803172559258 - 3.05247871975711" 
[3] "3.4609230722069 - 3.56097173966387" 
[4] "1.35368243309618 - 1.45548512578821" 
[5] "2.39936853846605 - 2.47570756724791" 
[6] "3.21849170272184 - 3.29653660329785" 

編輯

該解決方案充分尊重您的原始數據的尺寸。我所做的就是製作一個3D陣列,並且在保持第三維([x,y, 1:2])不變的情況下一次處理每個單元格。

dat <- array(c(datMean, datSE), dim = c(10, 3, 2)) 

datNEW <- matrix(rep(NA, nrow(dat)*ncol(dat)), ncol = ncol(dat)) 

for (column in seq(ncol(dat))) { 
    cls <- rep(NA, nrow(dat)) 
    for (rows in seq(nrow(dat))) { 
     tmp <- dat[rows, column, 1:2] 
     cls[rows] <- paste(tmp[1] - tmp[2], tmp[1] + tmp[2], sep = " - ") 
    } 
    datNEW[, column] <- cls 
} 
+0

這很好,但我忘了提及我需要datNew具有與其他數據幀相同的結構(相同的rownames和colnames - 請參閱我的EDIT1)。熔化和鑄造似乎很難做到這一點。 – Steve

+0

的確,@Steve。看到我的編輯,將在幾秒鐘後。 –

+0

...另外,您可以拆分我的第一個解決方案,以便它適合您的維度。 –

6

這是一種無需手動指定每列即可完成此操作的方法。首先,我們做的數據,並把他們在使用abind包一個陣列,四捨五入到3,因爲這看起來更好:

datMean <- data.frame(a=rnorm(10, 3), b=rnorm(10, 3), d=rnorm(10, 3)) 
datSE <- data.frame(a=rnorm(10, 3)/100, b=rnorm(10, 3)/100, d=rnorm(10, 3)/100) 

library(abind) 

datArray <- round(abind(datMean,datSE,along=3),3) 

然後,我們可以將paste功能,這個陣列中的每個元素和列:

apply(datArray,1:2,function(x)paste(x[1]-x[2],"-",x[1]+x[2])) 

     a    b    d    
[1,] "3.537 - 3.581" "3.358 - 3.436" "3.282 - 3.312" 
[2,] "2.452 - 2.516" "1.372 - 1.44" "3.041 - 3.127" 
[3,] "3.017 - 3.101" "3.14 - 3.228" "5.238 - 5.258" 
[4,] "3.397 - 3.451" "2.783 - 2.839" "3.381 - 3.405" 
[5,] "1.918 - 1.988" "2.978 - 3.02" "3.44 - 3.504" 
[6,] "4.01 - 4.078" "3.014 - 3.068" "1.914 - 1.954" 
[7,] "3.475 - 3.517" "2.117 - 2.159" "1.871 - 1.929" 
[8,] "2.551 - 2.619" "3.907 - 3.975" "1.588 - 1.614" 
[9,] "1.707 - 1.765" "2.63 - 2.678" "1.316 - 1.348" 
[10,] "4.051 - 4.103" "3.532 - 3.628" "3.235 - 3.287" 
+0

非常感謝!這工作得很好,並且能夠保留rownames(請參閱我的編輯)。一個問題:有沒有辦法在短劃線之前和之後省略空間? – Steve

+0

是的,在'paste()' –