2013-02-20 2 views
4

У меня есть dataframe, который выглядит следующим образом:Перестановка dataframe - R

 a  b  c   d 
ab 0  0  1   0 
cd -0.415 1.415 0   0 
ef 0  0  0.0811 0.918 

Есть простой способ превратить эту таблицу в:

 a  b  c   d 
ab 0  0  1   0 
cd -0.415 0  0   0 
cd 0 1.415  0   0 
ef 0  0  0.0811 0 
ef 0  0  0   0.918 

Если есть два или больше числа в original table Я хочу преобразовать его в соответствующие числа строк. Я не знаю, как это сделать, поэтому любая помощь будет оценена

+4

Останется ли потерял свой статус как число? Просто любопытно: Какова конечная цель/цель для этого? – A5C1D2H2I1M1N2O1R2T1

ответ

4

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

library(reshape2) 
mydf <- structure(list(a = c(0, -0.415, 0), b = c(0, 1.415, 0), 
         c = c(1, 0, 0.0811), d = c(0, 0, 0.918)), 
        .Names = c("a", "b", "c", "d"), 
        class = "data.frame", row.names = c("ab", "cd", "ef")) 
mydf$rows<- rownames(mydf) 
m1<- melt(mydf, id="rows", measured= names(mydf)) 
m2<- dcast(m1, rows+value~..., fill=0) 
m2<- m2[m2$value!=0, ] 
m2$value <- NULL  

#rows  a  b  c  d 
#2 ab 0.000 0.000 1.0000 0.000 
#3 cd -0.415 0.000 0.0000 0.000 
#5 cd 0.000 1.415 0.0000 0.000 
#7 ef 0.000 0.000 0.0811 0.000 
#8 ef 0.000 0.000 0.0000 0.918 
+0

(+1) очень приятное решение! Мне нравится использование 'dcast'. Могу ли я предложить заменить последнюю строку на 'm2 [! (Names (m2)% in%" value ")]' или 'm2 $ value <- NULL' вместо индексации номером col? – Arun

+1

Спасибо за подсказку - я знал, что это не лучшая практика, но не был уверен, какой из них был предпочтительным. , , –

-1

Я не думаю, что есть изящная версия того, что вы просите точно, но, возможно, вы можете использовать melt от reshape2 вместо этого? Он даст вам одну строку в строке строки/столбца:

> library(reshape2) 
> # add row names as column 
> df <- cbind(df, names=rownames(df)) 
> df <- melt(df,id.var="names") 
Using as id variables 
> df[df$value != 0,] 
    names variable value 
2  cd  a -0.4150 
5  cd  b 1.4150 
7  ab  c 1.0000 
9  ef  c 0.0811 
12 ef  d 0.9180 
4

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

reformat.dat <- function(dat) { 
    tdat <- t(dat) 
    nz <- tdat != 0 
    i <- col(tdat)[nz] 
    j <- row(tdat)[nz] 
    out <- matrix(0, sum(nz), ncol(dat)) 
    out[cbind(seq_len(sum(nz)), j)] <- tdat[nz] 
    rownames(out) <- rownames(dat)[i] 
    colnames(out) <- colnames(dat) 
    out 
} 

reformat.dat(dat) 
#   a  b  c  d 
# ab 0.000 0.000 1.0000 0.000 
# cd -0.415 0.000 0.0000 0.000 
# cd 0.000 1.415 0.0000 0.000 
# ef 0.000 0.000 0.0811 0.000 
# ef 0.000 0.000 0.0000 0.918 
+0

+1 Я действительно люблю индексирование матрицы ... – Aaron

1

Вот один подход, но вы должны следовать с некоторыми косметическими изменениями для фиксации имен строк.

Ваши данные в воспроизводимой форме:

mydf <- structure(list(a = c(0, -0.415, 0), b = c(0, 1.415, 0), 
         c = c(1, 0, 0.0811), d = c(0, 0, 0.918)), 
        .Names = c("a", "b", "c", "d"), 
        class = "data.frame", row.names = c("ab", "cd", "ef")) 

Replace нули с NA с:

mydf[mydf == 0] <- NA 

stack ваш data.frame, чтобы сделать это "длинный" data.frame:

mydf1 <- data.frame(Rows = rownames(mydf), stack(mydf)) 

Создайте уникальные значения для «Строки»

mydf1$Rows <- make.unique(as.character(mydf1$Rows)) 
# Let's see what we have so far.... 
mydf1 
# Rows values ind 
# 1 ab  NA a 
# 2 cd -0.4150 a 
# 3 ef  NA a 
# 4 ab.1  NA b 
# 5 cd.1 1.4150 b 
# 6 ef.1  NA b 
# 7 ab.2 1.0000 c 
# 8 cd.2  NA c 
# 9 ef.2 0.0811 c 
# 10 ab.3  NA d 
# 11 cd.3  NA d 
# 12 ef.3 0.9180 d 

Теперь просто используйте xtabs, чтобы получить результат, который вы ищете. Оберните его в as.data.frame.matrix, если вы хотите data.frame, и очистите имена строк, если вам нужно.

as.data.frame.matrix(xtabs(values ~ Rows + ind, mydf1)) 
#   a  b  c  d 
# ab.2 0.000 0.000 1.0000 0.000 
# cd -0.415 0.000 0.0000 0.000 
# cd.1 0.000 1.415 0.0000 0.000 
# ef.2 0.000 0.000 0.0811 0.000 
# ef.3 0.000 0.000 0.0000 0.918 
2

Вот простое решение с использованием diag:

o <- apply(df, 1, function(x) { 
    t <- diag(x) 
    colnames(t) <- names(x) 
    t <- t[rowSums(t == 0) != length(x), ,drop = FALSE] 
    t 
}) 
ids <- rep(names(o), sapply(o, nrow)) 
o <- do.call(rbind, o) 
row.names(o) <- ids 

#   a  b  c  d 
# ab 0.000 0.000 1.0000 0.000 
# cd -0.415 0.000 0.0000 0.000 
# cd 0.000 1.415 0.0000 0.000 
# ef 0.000 0.000 0.0811 0.000 
# ef 0.000 0.000 0.0000 0.918 

Это matrix. Используйте as.data.frame(.), если вам нужен data.frame.

Смежные вопросы