R:根据data.frame中的匹配值构建列表

时间:2012-02-02 00:42:33

标签: r list extract dataframe

我有一个3列数据框,看起来有点像这样:

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

其中id和name值是唯一的,而links是一个id字符串,表示与每行中的某些名称的关联。所以例如dave包含链接id 23459,它是mary,所以dave连接到mary。我需要生成的是数据中所有连接的对列表,因此我将输出示例数据,如下所示:

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

对于R来说很新,看到使用像apply之类的方法做的惊人的事情,然后在尝试复制一个看起来更像javascript例程并且效率非常低的解决方案之前我想知道是否有人可以提供帮助。 / p>

3 个答案:

答案 0 :(得分:1)

一种解决方案,使用Matt的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 :(得分: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 = ", "))

答案 2 :(得分: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 
")