R: превращение данных в кадре данных в столбцы - PullRequest
2 голосов
/ 08 июня 2011

У меня есть такой фрейм данных

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

Я видел этот вопрос, Превращение значений полей в имена столбцов в фрейме данных R , и это довольно близко к тому, что мне нужно. Делаем это

>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

Я думаю, что я близок, но я не могу понять последний шаг, например, сжатие таблицы в том, что я описал выше. Любые подсказки?

Ответы [ 4 ]

6 голосов
/ 08 июня 2011

Я бы вычислил строку и столбец, который вы хотите поместить Date, из шаблона в столбце Tag, а затем просто заполнил новую матрицу.

Сначала установите шаблон, которому хотите соответствоватьдля каждого ряда;Я буду использовать результаты от 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"
1 голос
/ 08 июня 2011

@ Андри была довольно близка к решению

# 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        

РЕДАКТИРОВАТЬ (первое решение не учитывало шаблон

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
1 голос
/ 08 июня 2011

В моем ответе используется много неприятного кодирования (то есть двух вложенных циклов), чтобы найти желаемое решение, но оно дает именно то, что вы хотите:

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) и создание fin и tmp должно быть соответственно изменено).

Кроме того, это решение совсем не эффективно для памяти или чего-либо еще. Вы добьетесь значительных улучшений, если предварительно назначите и т. Д. (На больших фреймах data.frames), но для быстрого и грязного способа это работает.

1 голос
/ 08 июня 2011

Хотя вы описываете таблицу в своем вопросе, мне кажется, что вы действительно хотите составить список. Вы можете сделать это, используя функцию разделения:

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

Чтобы избавиться от столбца Tag в каждом списке, вы можете использовать lapply и split в комбинации:

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