2013-05-03 64 views
16

編輯 - 這個問題最初名爲< <龍寬數據R中重塑>>計算平均值和中data.frame由多個變量組標準差


我只是學習R並試圖找到應用它來幫助別人的方法。作爲一個測試案例,我正在重塑一些數據,並且遇到了我在網上找到的例子時遇到了麻煩。什麼我開始與這個樣子的:

ID Obs 1 Obs 2 Obs 3 
1 43  48  37 
1 27  29  22 
1 36  32  40 
2 33  38  36 
2 29  32  27 
2 32  31  35 
2 25  28  24 
3 45  47  42 
3 38  40  36 

我想結束了會是這樣的:

ID Obs 1 mean Obs 1 std dev Obs 2 mean Obs 2 std dev 
1 x   x    x   x 
2 x   x    x   x 
3 x   x    x   x 

等等。我不確定的是我是否需要我的長表格數據或其他信息。我認爲數學部分(找到平均值和標準偏差)將是一件容易的事情,但我一直無法找到一種似乎能正確重塑數據的方法,從而開始處理這一過程。

非常感謝您的幫助。

+3

只是一個評論:我不認爲這就是人們通常意味着從長格式轉爲寬格式。 – Frank 2013-05-03 21:06:32

+0

很多評論,但我很驚訝沒有人關心修復這樣一個誤導性的標題(現在完成)。 – flodel 2013-05-03 23:16:21

回答

15

有幾種不同的方法可以解決這個問題。 reshape2是一個有用的軟件包。 就個人而言,我喜歡使用data.table

下面是一步一步的

如果myDF是您data.frame

library(data.table) 
DT <- data.table(myDF) 

DT 

# this will get you your mean and SD's for each column 
DT[, sapply(.SD, function(x) list(mean=mean(x), sd=sd(x)))] 

# adding a `by` argument will give you the groupings 
DT[, sapply(.SD, function(x) list(mean=mean(x), sd=sd(x))), by=ID] 

# If you would like to round the values: 
DT[, sapply(.SD, function(x) list(mean=round(mean(x), 3), sd=round(sd(x), 3))), by=ID] 

# If we want to add names to the columns 
wide <- setnames(DT[, sapply(.SD, function(x) list(mean=round(mean(x), 3), sd=round(sd(x), 3))), by=ID], c("ID", sapply(names(DT)[-1], paste0, c(".men", ".SD")))) 

wide 

    ID Obs.1.men Obs.1.SD Obs.2.men Obs.2.SD Obs.3.men Obs.3.SD 
1: 1 35.333 8.021 36.333 10.214  33.0 9.644 
2: 2 29.750 3.594 32.250 4.193  30.5 5.916 
3: 3 41.500 4.950 43.500 4.950  39.0 4.243 

而且,這可能會或可能不會有幫助

> DT[, sapply(.SD, summary), .SDcols=names(DT)[-1]] 
     Obs.1 Obs.2 Obs.3 
Min. 25.00 28.00 22.00 
1st Qu. 29.00 31.00 27.00 
Median 33.00 32.00 36.00 
Mean 34.22 36.11 33.22 
3rd Qu. 38.00 40.00 37.00 
Max. 45.00 48.00 42.00 
17

這裏可能是t去它(用reproducible example),他最簡單的方法:

library(plyr) 
df <- data.frame(ID=rep(1:3, 3), Obs_1=rnorm(9), Obs_2=rnorm(9), Obs_3=rnorm(9)) 
ddply(df, .(ID), summarize, Obs_1_mean=mean(Obs_1), Obs_1_std_dev=sd(Obs_1), 
    Obs_2_mean=mean(Obs_2), Obs_2_std_dev=sd(Obs_2)) 

    ID Obs_1_mean Obs_1_std_dev Obs_2_mean Obs_2_std_dev 
1 1 -0.13994642  0.8258445 -0.15186380  0.4251405 
2 2 1.49982393  0.2282299 0.50816036  0.5812907 
3 3 -0.09269806  0.6115075 -0.01943867  1.3348792 

編輯:下面的辦法有許多列打交道時爲您節省大量的輸入。

ddply(df, .(ID), colwise(mean)) 

    ID  Obs_1  Obs_2  Obs_3 
1 1 -0.3748831 0.1787371 1.0749142 
2 2 -1.0363973 0.0157575 -0.8826969 
3 3 1.0721708 -1.1339571 -0.5983944 

ddply(df, .(ID), colwise(sd)) 

    ID  Obs_1  Obs_2  Obs_3 
1 1 0.8732498 0.4853133 0.5945867 
2 2 0.2978193 1.0451626 0.5235572 
3 3 0.4796820 0.7563216 1.4404602 
+1

還有一個你錯過了觀察。雖然這是減少列數的方法,但我認爲它很快變得很難看。 – Arun 2013-05-03 21:29:56

+0

'options(width = 300)' – mike 2013-05-03 21:36:52

8

這裏的另一個採取的data.table答案,使用@卡森的數據,這是(因爲使用lapply代替sapply的也快一點,)更具可讀性一點:

library(data.table) 
set.seed(1) 
dt = data.table(ID=c(1:3), Obs_1=rnorm(9), Obs_2=rnorm(9), Obs_3=rnorm(9)) 

dt[, c(mean = lapply(.SD, mean), sd = lapply(.SD, sd)), by = ID] 
# ID mean.Obs_1 mean.Obs_2 mean.Obs_3 sd.Obs_1 sd.Obs_2 sd.Obs_3 
#1: 1 0.4854187 -0.3238542 0.7410611 1.1108687 0.2885969 0.1067961 
#2: 2 0.4171586 -0.2397030 0.2041125 0.2875411 1.8732682 0.3438338 
#3: 3 -0.3601052 0.8195368 -0.4087233 0.8105370 0.3829833 1.4705692 
+0

第二個應該使用'sd'並且你使用'.SD'兩次..是否有性能問題?任何想法? – Arun 2013-05-03 21:31:54

+0

@阿倫,謝謝,修正了'sd'位。我不知道是否有這樣的表現,讓我檢查 – eddi 2013-05-03 21:35:16

+0

@阿倫看起來有一個〜10%的表現,但好消息是,它不會增加更多的類別 – eddi 2013-05-03 21:38:39

26

這是一個聚合問題,而不是最初提出的問題所導致的重塑問題 - 我們希望通過ID將每列聚合爲平均值和標準偏差。有很多軟件包可以處理這些問題。在R的基它可以使用aggregate這樣做(假設DF是輸入數據幀):

ag <- aggregate(. ~ ID, DF, function(x) c(mean = mean(x), sd = sd(x))) 

注1:甲評論者指出ag是數據幀用於其中的一些列矩陣。雖然最初看起來很奇怪,但實際上它簡化了訪問。 ag具有與輸入DF相同的列數。其第一列ag[[1]]ID,剩餘的ag[[i+1]](或等值線ag[-1][[i]])的第i列爲第i個輸入觀察列的統計矩陣。如果希望獲得第i個觀測的第j個統計量,則因此可以將ag[[i+1]][, j]也寫爲ag[-1][[i]][, j]

另一方面,假設對於輸入中的每個觀察(其中k = 2的問題)有k統計列。然後,如果我們將輸出平坦化,然後訪問第i個觀測列的第j個統計量,我們必須使用更復雜的ag[[k*(i-1)+j+1]]或等效的ag[-1][[k*(i-1)+j]]

例如,比較所述第一表達的簡單性與所述第二:

ag[-1][[2]] 
##  mean  sd 
## [1,] 36.333 10.2144 
## [2,] 32.250 4.1932 
## [3,] 43.500 4.9497 

ag_flat <- do.call("data.frame", ag) # flatten 
ag_flat[-1][, 2 * (2-1) + 1:2] 
## Obs_2.mean Obs_2.sd 
## 1  36.333 10.2144 
## 2  32.250 4.1932 
## 3  43.500 4.9497 

注2:在重現的形式的輸入是:

Lines <- "ID Obs_1 Obs_2 Obs_3 
1 43  48  37 
1 27  29  22 
1 36  32  40 
2 33  38  36 
2 29  32  27 
2 32  31  35 
2 25  28  24 
3 45  47  42 
3 38  40  36" 
DF <- read.table(text = Lines, header = TRUE) 
+2

也許需要注意:儘管這樣的輸出看起來像是一個data.frame,每個列都有兩列進行聚合(結果是帶有您的示例數據的7列),但如果查看結構,則會看到它實際上只有四個你可以用do.call(data.frame,aggregate(。〜ID,DF,function(x)c)(mean = mean(x),sd = sd (x))))'。 – A5C1D2H2I1M1N2O1R2T1 2013-05-04 06:42:29

+0

@Ananda Mahto,好點,我添加了一些comemnts詳細說明這個。 – 2013-05-04 10:25:51

6

我添加dplyr溶液。

set.seed(1) 
df <- data.frame(ID=rep(1:3, 3), Obs_1=rnorm(9), Obs_2=rnorm(9), Obs_3=rnorm(9)) 

library(dplyr) 
df %>% group_by(ID) %>% summarise_each(funs(mean, sd)) 

#  ID Obs_1_mean Obs_2_mean Obs_3_mean Obs_1_sd Obs_2_sd Obs_3_sd 
# (int)  (dbl)  (dbl)  (dbl)  (dbl)  (dbl)  (dbl) 
# 1  1 0.4854187 -0.3238542 0.7410611 1.1108687 0.2885969 0.1067961 
# 2  2 0.4171586 -0.2397030 0.2041125 0.2875411 1.8732682 0.3438338 
# 3  3 -0.3601052 0.8195368 -0.4087233 0.8105370 0.3829833 1.4705692 
相關問題