2012-03-21 1 views
8

У меня есть dataframe ДФ:Заполняем новый столбец в dataframe с поиском из двойной матрицы

colour shape 
'red' circle 
'blue' square 
'blue' circle 
'green' sphere 

И двойная матрица м с именованных строк/столбцов

 circle square sphere 
red 1  4  7 
blue 2  5  8 
green 3  6  9 

Я бы хотел бы добавить новый столбец DF так, что я получаю:

id colour shape 
1 'red' circle 
5 'blue' square 
2 'blue' circle 
9 'green' sphere 

Я попытался сделать это с помощью следующего кода, но это не похоже на работу:

df$id <- m[df$colour,df$shape] 

Я также попробовал apply(); и похоже, но не повезло. Может ли кто-нибудь сказать мне правильный подход к этому, не используя цикл?

+0

Спасибо всем за помощь. Как ответ @Tommy ниже, так и ответы DWin ниже работают отлично для этого. Я пошел с DWin для моего сценария, поскольку у меня были векторы символов в моих реальных данных. – Ina

ответ

5

Я думаю, что я мог бы выиграть самый короткий конкурс ответа здесь до тех пор, как те векторы символов, а не факторы, которые могли бы быть более ожидаемыми, если вы не сделали усилия specifid избежать. Он действительно только добавляет cbind, чтобы преобразовать два вектора df «character» в матрицу с двумя столбцами, ожидаемую функцией [.matrix, что вы были очень близки к успеху в использовании. (И это также кажется достаточно выразительным.)

# Data construct 
d <- data.frame(color=c('red','blue','blue','green'), 
shape=c('circle','square','circle','sphere'), stringsAsFactors=FALSE) 
m <- matrix(1:9, 3,3, dimnames=list(c('red','blue','green'), c('circle','square','sphere'))) 
# Code: 

d$id <- with(d, m [ cbind(color, shape) ]) 
d 
    color shape id 
1 red circle 1 
2 blue square 5 
3 blue circle 2 
4 green sphere 9 
+0

Обратите внимание, что это работает только в том случае, если уровни в 'd' имеют тот же порядок, что и имена rownames/colnames в m. Я попытался объяснить это в своем ответе. Повторите попытку с помощью 'm <-m [3: 1,]' и убедитесь, что он не работает ... – Tommy

+0

О, извините, не читал достаточно внимательно: учитывая, что 'd' содержит символьные векторы, а не факторы, которые фактически работают ... Мое решение работает в любом случае:;) – Tommy

+2

Можно также использовать 'm [cbind (as.character (d $ color), as.character (d $ shape)]', который, как я думаю, является общим и более –

1

merge() - ваш друг здесь. Чтобы использовать его, нам нужен соответствующий фрейм данных, чтобы объединиться с содержимым сложной версии вашей ID-матрицы. Я создаю что, как newdf следующего код:

df <- data.frame(matrix(1:9, ncol = 3)) 
colnames(df) <- c("circle","square","sphere") 
rownames(df) <- c("red","blue","green") 

newdf <- cbind.data.frame(ID = unlist(df), 
          expand.grid(colour = rownames(df), 
             shape = colnames(df))) 

что приводит:

> newdf 
     ID colour shape 
circle1 1 red circle 
circle2 2 blue circle 
circle3 3 green circle 
square1 4 red square 
square2 5 blue square 
square3 6 green square 
sphere1 7 red sphere 
sphere2 8 blue sphere 
sphere3 9 green sphere 

Затем с вашими исходными данными в объекте df2, определенный с помощью

df2 <- data.frame(colour = c("red","blue","blue","green"), 
        shape = c("circle","square","circle","sphere")) 

использования merge()

> merge(newdf, df2, sort = FALSE) 
    colour shape ID 
1 red circle 1 
2 blue circle 2 
3 blue square 5 
4 green sphere 9 

Вы можете сохранить, что и переставить столбцы, если вам нужно что: (! И быстро)

> res <- merge(newdf, df2, sort = FALSE) 
> res <- res[,c(3,1,2)] 
> res 
    ID colour shape 
1 1 red circle 
2 2 blue circle 
3 5 blue square 
4 9 green sphere 
7

Довольно простой альтернативой является использование матрицы для индексации в вашей матрице:

# Your data 
d <- data.frame(color=c('red','blue','blue','green'), shape=c('circle','square','circle','sphere')) 
m <- matrix(1:9, 3,3, dimnames=list(c('red','blue','green'), c('circle','square','sphere'))) 

# Create index matrix - each row is a row/col index 
i <- cbind(match(d$color, rownames(m)), match(d$shape, colnames(m))) 

# Now use it and add as the id column... 
d2 <- cbind(id=m[i], d) 

d2 
# id color shape 
#1 1 red circle 
#2 5 blue square 
#3 2 blue circle 
#4 9 green sphere 

match Функция используется для поиска соответствующего числового индекса для конкретной строки.

Обратите внимание, что в более новой версии R (2.13 и более новой, я думаю) вы можете использовать символьные строки в индексной матрице. К сожалению, цвета и формы колонны, как правило, factors и cbind не нравится, что (он использует целые коды), так что вам нужно, чтобы заставить их as.character:

i <- cbind(as.character(d$color), as.character(d$shape)) 

... Я подозреваю, что использование match однако, более эффективен.

EDIT Я измерил и это, кажется, около 20% быстрее использовать match:

# Make 1 million rows 
d <- d[sample.int(nrow(d), 1e6, TRUE), ] 

system.time({ 
    i <- cbind(match(d$color, rownames(m)), match(d$shape, colnames(m))) 
    d2 <- cbind(id=m[i], d) 
}) # 0.46 secs 


system.time({ 
    i <- cbind(as.character(d$color), as.character(d$shape)) 
    d2 <- cbind(id=m[i], d) 
}) # 0.55 secs 
+0

Пока @Tommy подводит его, решение, преобразующее m в вектор, принимает 0,14 секунды по сравнению с 0,50 секунд для первого примера выше на моей машине;) – BenBarnes

+0

Я отметил ответ @DWin правильный, поскольку это тот Я использовал (я предпочитаю простоту и не имею ограничений по времени), но этот ответ тоже отлично работает, и я очень ценю усилия, которые были в нем. Благодаря! – Ina

1

Можно также преобразовать матрицу т в вектор, а затем сопоставить идентификатор для значений цвета и формы :

df<-data.frame(colour=c("red","blue","blue","green"), 
    shape=c("circle","square","circle","sphere")) 


m<-matrix(1:9,nrow=3,dimnames=list(c("red","blue","green"), 
    c("circle","square","sphere"))) 


mVec<-as.vector(m) 

следующий шаг соответствует цвету в DF к соответствующему dimname в матрице м, а затем добавляет целое число, соответствующее форме. Результат в индексе m-вектора с соответствующим ID.

df$ID<-mVec[match(df$colour, dimnames(m)[[1]]) + (dim(m)[1]* 
    (match(df$shape, dimnames(m)[[2]]) - 1))] 
+0

+1 за то, что он самый быстрый! – Tommy

2

Другой ответ Использование reshape2 и plyr (опция только для присоединиться) пакетов.

require(plyr) 
require(reshape2) 

Df <- data.frame(colour = c("red", "blue", "blue", "green"), 
        shape = c("circle", "square", "circle", "sphere")) 

Mat <- matrix(1:9, dimnames = list(c("red", "blue", "green"), 
            c("circle", "square", "sphere")), 
        nrow = 3) 

Df2 <- melt.array(Mat, varnames = c("colour", "shape")) 

join(Df, Df2) 
result <- join(Df, Df2) 

join(Df, Df2) 
Joining by: colour, shape 
    colour shape value 
1 red circle  1 
2 blue square  5 
3 blue circle  2 
4 green sphere  9 

Надеется, что это поможет

0
#recreating your data 
dat <- read.table(text="colour shape 
'red' circle 
'blue' square 
'blue' circle 
'green' sphere", header=TRUE) 

d2 <- matrix(c(1:9), ncol=3, nrow=3, byrow=TRUE) 
dimnames(d2) <-list(c('circle', 'square', 'sphere'), 
c("red", "blue", "green")) 
d2<-as.table(d2) 

#make a list of matching to the row and column names of the look up matrix 
LIST <- list(match(dat[, 2], rownames(d2)), match(dat[, 1], colnames(d2))) 
#use sapply to index the lookup matrix using the row and col values from LIST 
id <- sapply(seq_along(LIST[[1]]), function(i) d2[LIST[[1]][i], LIST[[2]][i]]) 
#put it all back together 
data.frame(id=id, dat) 
Смежные вопросы