2012-02-02 73 views
2

我有一个3列数据帧,看起来有点像这样的建筑,距离匹配值的列表:R:在data.frame

id  name links 
1 134235 dave "34657","34563","23459" 
2 23459 mary "134235","45868","45677" 
3 165432 jane "134235","23459","44657" 

其中id和name值是唯一的,而且链接是一个字符串表示与每行中某些名称的关联的ID。因此,例如戴夫包括链接ID 23459这是玛丽,所以戴夫连接到玛丽。我需要产生的数据中的所有连接的一对列表,以便与示例数据我想输出是这样的:用方法做这样apply才去

dave,mary 
mary,dave 
jane,dave 
jane,mary 

很新的R和看到令人惊奇的事情并试图复制一个解决方案,看起来更像是一个JavaScript例程,效率非常低,我想知道是否有人可以提供帮助。

回答

1

的一个解决方案,使用马特的dput():

tab <- structure(list(
    id = c("134235", "23459", "165432"), 
    name = c("dave", "mary", "jane"), 
    links = c("'34657', '34563', '23459'", 
      "'134235', '45868', '45677'", 
      "'134235', '23459', '44657'")), 
    .Names = c("id", "name", "links"), 
    row.names = c(NA, -3L), class = "data.frame") 

conns <- function(name, links) { 
    paste(name, tab$name[tab$id %in% as.numeric(unlist(strsplit(gsub('\'|\"', 
    '', links), ',')))], sep=',') 
} 

connections <- unname(unlist(mapply(conns, tab$name, tab$links, 
    SIMPLIFY=FALSE))) 
+1

<惊呆了......那么这真是太棒了!我知道R很强大,但是这让它进入了另一个联盟。所以我可以从这个mapply中学习如何运行函数conns,在每一行tab上做一些名字和链接(从这里返回的是未列出的和未命名的)。在每个“链接”的conns中,您分割并查看每个id是否在其中。如果是这种匹配是用来返回名称。 – mhawksey 2012-02-02 08:58:53

+0

mhawksey,令人印象深刻的使用单个子句中的'i'开头的所有两个字母单词(好的,您使用变量'id',但它是我使用谷歌搜索找到的最接近的例子之一)。 – Kylos 2014-01-09 19:42:02

0
dat<- structure(list(
    id = c("134235", "23459", "165432"), 
    name = c("dave", "mary", "jane"), 
    links = c("'34657', '34563', '23459'", 
       "'134235', '45868', '45677'", 
       "'134235', '23459', '44657'")), 
    .Names = c("id", "name", "links"), 
    row.names = c(NA, -3L), class = "data.frame") 


# It can all be done in base, of course... 
library(stringr) 
library(reshape2) 

# This would be easy to do if links weren't in that format - 
# one record per id-link pair would be preferable. 
# Split dat$links and remove any quotes 
dat.wider <- data.frame(
    dat[ , c("id", "name")], 
    str_split_fixed(string = gsub(dat$links, 
            pattern = "['|\"]", 
            replace = ""), 
        pattern = ", ", 
        n = 3) 
) 

# Reshape 
dat.long <- melt(dat.wider, id.var = c("id", "name")) 

# Self-join - this is not quite the right method, but I'm just not 
# thinking straight right now 
dat.joined <- unique(merge(x = dat.long[ , c("name", "value")], 
          y = dat.long[ , c("id", "name")], 
          by.x = "value", 
          by.y = "id" 
)) 

# And, finally, if you wanted vector output... 
res <- with(dat.joined, paste(name.x, name.y, sep = ", ")) 
0

第一步应正常化的数据,特别地,解析字符串。 您可以使用ddply:它应用了一个函数 ,该函数接收一个data.frame块(在我们的例子中为一行) 并以某种方式转换它。你只需要编写一个函数 ,它可以在一行上工作,即在一个字符串上工作。

# Sample data 
n <- 10 
k <- 3 
ids <- as.character(unique(round(1e5*runif(n)))) 
n <- length(ids) 
names <- LETTERS[1:n] 
links <- lapply(ids, function(u) 
    sample(setdiff(ids,u),k,replace=FALSE)) 
links <- sapply(links, function(u) 
    paste('"', paste(u,collapse='","'), '"', sep="")) 
d <- data.frame( 
    id=ids, 
    name=names, 
    links=links, 
    stringsAsFactors=FALSE 
) 

library(plyr) 
library(stringr) 
dd <- ddply( 
    d, 
    c("id", "name"), 
    function(u) data.frame(
    id=u$id, 
    name=u$name, 
    link=unlist(str_split(str_replace_all(u$links, '"', ''), ",")) 
)) 

然后,您可以加入的数据,无论是与mergesqldf

library(sqldf) 
sqldf(" 
    SELECT A.name, B.name 
    FROM dd AS A, d AS B 
    WHERE A.link = B.id 
")