R: Создание списка из соответствующих значений в data.frame - PullRequest
2 голосов
/ 02 февраля 2012

У меня есть фрейм данных из 3 столбцов, который выглядит примерно так:

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

, где значения идентификатора и имени уникальны, а ссылки - это строка идентификаторов, которые указывают на связь с некоторыми именами.в каждом ряду.Так, например, Дэйв включает в себя номер ссылки 23459, который является Мэри, поэтому Дейв связан с Мэри.Мне нужно составить список всех соединений в данных, поэтому на примере данных я бы вывел что-то вроде:

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

Очень плохо знаком с R и видел удивительные вещи, выполненные с помощью таких методов, как apply и прежде чем уйти и попытаться воспроизвести решение, которое будет больше похоже на рутину javascript и быть очень неэффективным, я подумал, может ли кто-нибудь помочь.

Ответы [ 3 ]

1 голос
/ 02 февраля 2012

Одно решение с использованием Matt's 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)))
0 голосов
/ 02 февраля 2012

Первым шагом должно стать нормализация данных, в частности, разбор строк. Вы можете использовать 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, '"', '' ), "," ))
))

Затем вы можете объединить данные с помощью merge или sqldf.

library(sqldf)
sqldf(" 
  SELECT A.name, B.name 
  FROM dd AS A, d AS B 
  WHERE A.link = B.id 
")
0 голосов
/ 02 февраля 2012
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 = ", "))
...