基于多列组合R中的数据帧行

时间:2016-09-13 14:10:41

标签: r dataframe reshape2

我在R中有一个数据帧,每行有一个个体。有时,个人出现在两行,我想根据重复的ID组合这些行。

问题是,每个人都有多个ID,当ID出现两次时,不一定会出现在同一列中

以下是一个示例数据框:

dat <- data.frame(a = c('cat', 'canine', 'feline', 'dog'),
                  b = c('feline', 'puppy', 'meower', 'wolf'),
                  c = c('kitten', 'barker', 'kitty', 'canine'),
                  d = c('shorthair', 'collie', '', ''),
                  e = c(1, 5, 3, 8))

> dat
       a      b      c         d e
1    cat feline kitten shorthair 1
2 canine  puppy barker    collie 5
3 feline meower  kitty           3
4    dog   wolf canine           8

因此应合并第1行和第3行,因为第1行的ID b等于第3行的ID a。同样,第2行的ID a等于ID {{1}第4行,所以这些行也应该合并。

理想情况下,输出应该如下所示。

c

(请注意,这些行未根据空字符串的共享ID进行组合。)

我对如何做到这一点的想法如下,但我很确定我已经走错了路,所以他们可能没有帮助解决问题。

我以为我可以为每一行分配行ID,然后融化数据。在那之后,我可以逐行。当我找到其中一个ID与前一行匹配的行时(例如,当第3行ID中的一个与第1行ID之一匹配时),我将更改当前行的行ID的每个实例以匹配先前的行ID (例如,所有行ID都将更改为1)。

以下是我一直在使用的代码:

     a.1    b.1    c.1       d.1 e.1    a.2    b.3    c.2 d.2 e.2
1    cat feline kitten shorthair   1 feline meower  kitty       3
2 canine  puppy barker    collie   5    dog   wolf canine       8

这种方法存在两个问题。

  1. 可能是第3行中的ID与第1行匹配,第5行中的不同ID与第3行匹配。在这种情况下,第3行和第5行的行ID应更改为1.这意味着顺序遍历行很重要,这导致我使用for循环而不是apply函数。我知道这不是很像R,而且我使用的大数据框架非常慢。
  2. 此代码生成以下输出。现在有多个行具有相同的dat$row.id <- 1:nrow(dat) library(reshape2) dat.melt <- melt(dat, id.vars = c('e', 'row.id')) for (i in 2:nrow(dat.melt)) { # This next step is just to ignore the empty values if (grepl('^[[:space:]]*$', dat.melt$value[i])) { next } earlier.instance <- dat.melt$row.id[which(dat.melt$value[1:(i-1)] == dat.melt$value[i])] if (length(earlier.instance) > 0) { earlier.row.id <- earlier.instance[1] dat.melt$row.id[dat.melt$row.id == dat.melt$row.id[i]] <- earlier.row.id } } row.id,因此我不知道如何投射它以获得上面显示的输出类型。在这里使用variable将被强制使用聚合函数。
  3. 输出:

    dcast

2 个答案:

答案 0 :(得分:2)

新答案。有一些乐趣(/挫折)通过这个工作。我敢肯定这不是最快的解决方案,但它应该让你过去我的其他答案。让我解释一下:

dat <- data.table(a = c('cat', 'canine', 'feline', 'dog', 'cat','fido'),
                  b = c('feline', 'puppy', 'meower', 'wolf', 'kitten', 'dog'),
                  c = c('kit', 'barker', 'kitty', 'canine', 'feline','wolf'),
                  d = c('shorthair', 'collie', '', '','',''),
                  e = c(1, 2, 3, 4, 5, 6))

dat[, All := paste(a, b,c),]

两个更改:dat$e现在是一个索引列,因此它只是它所在行的数字位置。如果e非常重要,您可以创建一个新列来替换它。

下面是第一个循环。这会产生3个新列FirstMatchingID等。这些与以前类似:它们为dat$All a和{{1}提供与b匹配的最早(最低行#)的索引}}

c

接下来,我们使用for(i in 2:nrow(dat)) { x <- grepl(dat[i]$a, dat[i-(1:i)]$All) y <- max(which(x %in% TRUE)) dat[i, FirstMatchingID := dat[i-y]$e] x2 <- grepl(dat[i]$b, dat[i-(1:i)]$All) y2 <- max(which(x2 %in% TRUE)) dat[i, SecondMatchingID := dat[i-y2]$e] x3 <- grepl(dat[i]$c, dat[i-(1:i)]$All) y3 <- max(which(x3 %in% TRUE)) dat[i, ThirdMatchingID := dat[i-y3]$e] } 查找pmin列的最早匹配行,并将其设置在自己的列中。如果您在第25行中匹配MatchingID并且在第12行中匹配a,则会出现这种情况;它会给你12(我认为这是你想要的根据你的问题)。

b

最后,此循环将执行3项操作,创建一个dat$MinID <- pmin(dat$FirstMatchingID, dat$SecondMatchingID, dat$ThirdMatchingID, na.rm=T) 列,其中包含来自FinalID的所有匹配ID号:

  1. 其中eMinID(无匹配)将NA设为FinalID
  2. 如果e是一个数字,请找到该行(最早的匹配项)并检查 MinID是否为数字;如果不是,则没有先前的匹配,并将MinID设置为FinalID
  3. 不符合上述条件的行是您的特殊情况,其中行MinID最早的匹配本身具有较早的匹配。这将找到该匹配并将其设置为i
  4. FinalID

    我认为应该这样做;让我知道事情的后续。我没有声称它的效率或速度。

答案 1 :(得分:1)

这是一次业余尝试。我认为它可以满足您的需求。我已经将data.frame(现在是一个data.table)扩展了两行,以提供更好的示例。

此循环会创建一个新列dat$FirstMatchingID,其中包含dat$e中最早匹配的ID。我只是将其与第一列dat$a匹配,但我认为它可以很容易地扩展到bc

library(data.table)

dat <- data.table(a = c('cat', 'canine', 'feline', 'dog', 'feline','puppy'),
                  b = c('feline', 'puppy', 'meower', 'wolf', 'kitten', 'dog'),
                  c = c('kitten', 'barker', 'kitty', 'canine', 'cat','wolf'),
                  d = c('shorthair', 'collie', '', '','',''),
                  e = c(1, 5, 3, 8, 4, 6))

dat[, All := paste(a, b,c),]

for(i in 2:nrow(dat)) {
  print(dat[i])
  x <- grepl(dat[i]$a, dat[i-(1:i)]$All)
  y <- max(which(x %in% TRUE))
  dat[i, FirstMatchingID := dat[i-y]$e]
}

结果:

        a      b      c         d e                 All FirstMatchingID
1:    cat feline kitten shorthair 1   cat feline kitten              NA
2: canine  puppy barker    collie 5 canine puppy barker              NA
3: feline meower  kitty           3 feline meower kitty               1
4:    dog   wolf canine           8     dog wolf canine              NA
5: feline kitten    cat           4   feline kitten cat               1
6:  puppy    dog   wolf           6      puppy dog wolf               5

然后你必须找出你想要如何组合行来获得你想要的结果,但希望这会有所帮助!