2011-06-08 118 views
2

車削數據我有這樣R:在數據幀的列

Tag Date (DD/MM/YYYY) 
AA 1/1/2010 
AB 2/1/2010 
AC 3/1/2010 
AA 4/1/2010 
AB 5/1/2010 
AA 6/1/2010 
AB 7/1/2010 
AC 8/1/2010 

一個數據幀現在,有限量的不同標記,(小於10的平均)。我需要的是以更舒適的方式處理數據。我已經分析了標籤序列數據以找出更頻繁的重複模式,在這種情況下它將是(AA,AB,AC)。

現在,我想要的是將數據轉換成這樣的東西,所以我可以使用它。

AA  AB  AC 
1/1/2010 2/1/2010 3/1/2010 
4/1/2010 5/1/2010 NA 
6/1/2010 7/1/2010 8/1/2010 

我看到這個問題,Turning field values into column names in an R data frame,它非常接近我所需要的。這樣做

>libray(reshape2) 
>df<-sqldf("SELECT Tag, Date FROM validData") 
>head(dcast(df,Date~Tag)) 

產生

Using Date as value column: use value_var to override. 
Aggregation function missing: defaulting to length 

       Date AF687A AVISOO B32D76 B3DC39 B52C72 DF7EAD DF8E83 DFA521 DFA91A 
1 2010-12-23 09:18:50  0  0  0  0  1  0  0  0  0 
2 2010-12-23 09:18:52  1  0  0  0  0  0  0  0  0 
3 2010-12-23 09:18:54  0  0  0  0  1  0  0  0  0 
4 2010-12-23 09:18:57  1  0  0  0  0  0  0  0  0 
5 2010-12-23 09:18:58  0  0  0  0  1  0  0  0  0 
6 2010-12-23 09:19:00  0  0  0  1  0  0  0  0  0 

我覺得我很近,但我想不通的最後一個步驟,如在什麼上面描述我壓縮表。任何線索?

+1

你做沒有明確提及這一點,但你假設了一個關係(例如:當第六次觀察沒有標記AC時,在所需結果中使用NA)。如果您滿意:標籤爲'AA'的所有日期,以及標籤爲'AB'(等)的所有日期,即使這些日期的長度不相同,任務也會簡單得多。你能確認你想要哪一個? – 2011-06-08 15:51:54

+0

理想情況下,我想要第一個選擇,當模式與列表不同時創建一個新行。我知道使用命令式語言或PLSQL之類的語言比使用R語言更容易。但至少第二選擇將是我猜測的開始。 – 2011-06-08 15:59:03

回答

6

我會計算你想從Tag列的模式中放入Date的行和列,然後只填寫一個新的矩陣。

首先設置你想匹配每一行的模式;我將使用unique的結果。如果第一組缺少一個值(不是最後一個值),這將無法正常工作。

pat <- unique(df$Tag) 

然後通過將標籤與模式匹配來計算列,並通過注意何時開始新模式來計算該列。

col <- match(df$Tag, pat) 
row <- cumsum(c(0,diff(col))<=0) 

然後創建矩陣並填充它!

out <- matrix(nrow=max(row), ncol=max(col)) 
colnames(out) <- pat 
out[cbind(row, col)] <- df$Date 

結果是

> out 
    AA   AB   AC   
[1,] "1/1/2010" "2/1/2010" "3/1/2010" 
[2,] "4/1/2010" "5/1/2010" NA   
[3,] "6/1/2010" "7/1/2010" "8/1/2010" 
+0

真的很好的解決方案,但是,在'diff(k)'中有什麼'k',你意思是'col'? – 2011-06-08 17:48:02

+0

是的,謝謝。固定。 – Aaron 2011-06-08 18:48:48

+0

你解決這個問題的方式確實令人印象深刻,尤其是'cumsum(c(0,diff(col))<= 0)',因此'out [cbind(row,col)] < - df $ Date'。我希望你能獲得更多積分。 – Henrik 2011-06-08 20:34:22

1

儘管你在你的問題中描述了一張表格,但在我看來,你確實想要列出一個表格。爲此,您可以使用拆分功能:

split(df, df$Tag) 

$AA 
    Tag  Date 
1 AA 1/1/2010 
4 AA 4/1/2010 
6 AA 6/1/2010 

$AB 
    Tag  Date 
2 AB 2/1/2010 
5 AB 5/1/2010 
7 AB 7/1/2010 

$AC 
    Tag  Date 
3 AC 3/1/2010 
8 AC 8/1/2010 

爲了擺脫在每個列表中的標籤欄,你可以結合使用lapplysplit

lapply(split(df, df$Tag), function(x)x$Date[drop=TRUE]) 

$AA 
[1] 1/1/2010 4/1/2010 6/1/2010 
Levels: 1/1/2010 4/1/2010 6/1/2010 

$AB 
[1] 2/1/2010 5/1/2010 7/1/2010 
Levels: 2/1/2010 5/1/2010 7/1/2010 

$AC 
[1] 3/1/2010 8/1/2010 
Levels: 3/1/2010 8/1/2010 
+0

我瞭解您的解決方案,但表格會突出顯示NA值,如果它恰好顯示。現在,這是一個很好的起點,我一定會考慮一下。 – 2011-06-08 16:08:22

1

我的回答使用了大量的討厭編碼(即兩個嵌套的循環),以獲得所需的解決方案,但它給你你想要什麼:

df <- structure(list(Tag = c("AA", "AB", "AC", "AA", "AB", "AA", "AB", 
"AC"), Date = c("1/1/2010", "2/1/2010", "3/1/2010", "4/1/2010", 
"5/1/2010", "6/1/2010", "7/1/2010", "8/1/2010")), .Names = c("Tag", 
"Date"), class = "data.frame", row.names = c(NA, -8L)) 

l <- nrow(df) 
counter <- 1 
cols <- c("AA", "AB", "AC") 

fin <- data.frame(AA = NULL, AB = NULL, AC = NULL) 
tmp <- data.frame(AA = NA, AB = NA, AC = NA) 

while(counter < l) { 
    tmp <- data.frame(AA = NA, AB = NA, AC = NA) 
    for (col in 1:3) { 
     if (df[counter,1] == cols[col]) { 
      tmp[1,col] <- df[counter,2] 
      counter <- counter + 1 
     } 
    } 
    fin <- rbind(fin, tmp) 
} 

fin 

爲您提供:

 AA  AB  AC 
1 1/1/2010 2/1/2010 3/1/2010 
2 4/1/2010 5/1/2010  <NA> 
3 6/1/2010 7/1/2010 8/1/2010 

請注意,您可以用cols <- unique(sort(df[,1]))爭取更通用的解決方案(for (col in 1:3)fintmp建立將需要作相應改變)。

此外,這種解決方案根本不符合內存效率或任何事情。如果您預先分配等等(在更大的數據框架上),您將獲得巨大的改進,但是如果要快速且骯髒的方式,它會起作用。

+0

非常好!我發現這是做這件事的方法,只是認爲在R中可能有一個隱藏的包,它用一些神祕的參數來投射它會按我想要的那樣吐出來。但是,謝謝! (我會等待已接受的解決方案,看看是否有其他人提出了更好的R-ness方法) – 2011-06-08 16:32:05

1

@Andrie是相當接近的解決方案

# here assumed length 3 
# but you can calculate it as max 
do.call(cbind,lapply(split(mdf$Date,mdf$Tag),"[",seq(3))) 


    AA   AB   AC   
[1,] "1/1/2010" "2/1/2010" "3/1/2010" 
[2,] "4/1/2010" "5/1/2010" "8/1/2010" 
[3,] "6/1/2010" "7/1/2010" NA   

EDIT(第一個解決方案沒有考慮到模式

mdf$grp <- cumsum(1*c(TRUE,diff(as.numeric(factor(mdf$Tag)))<=0)) 
reshape(mdf,direction="wide",idvar="grp",timevar="Tag") 

    grp Date.AA Date.AB Date.AC 
1 1 1/1/2010 2/1/2010 3/1/2010 
4 2 4/1/2010 5/1/2010  <NA> 
6 3 6/1/2010 7/1/2010 8/1/2010