5

输入

row.no   column2    column3  column4
1        bb         ee       up
2        bb         ee       down
3        bb         ee       up
4        bb         yy       down
5        bb         zz       up

我有一个删除第 1 行、第 2 行和第 3 行的规则,因为第 1、2 和 3 行的 column2 和 column3 是相同的,但在第 4 列中发现了矛盾的数据(up 和)。 down

我如何要求 R 删除 column2 和 column3 中具有相同名称的那些行,但将第 3 列收缩以产生如下矩阵:

row.no   column2    column3  column4
4        bb         yy       down
5        bb         zz       up
4

4 回答 4

6

包中的函数在plyr这类问题上非常出色。这是使用两行代码的解决方案。

设置数据(@GavinSimpson 友情提供)

dat <- structure(list(row.no = 1:5, column2 = structure(c(1L, 1L, 1L, 
1L, 1L), .Label = "bb", class = "factor"), column3 = structure(c(1L, 
1L, 1L, 2L, 3L), .Label = c("ee", "yy", "zz"), class = "factor"), 
    column4 = structure(c(2L, 1L, 2L, 1L, 2L), .Label = c("down", 
    "up"), class = "factor")), .Names = c("row.no", "column2", 
"column3", "column4"), class = "data.frame", row.names = c(NA, 
-5L))

加载plyr

library(plyr)

用于ddply拆分、分析和合并数据。以下代码行分析将 dat 拆分为 (column2 和 column3) 的唯一组合。然后我添加一个名为 unique 的列,它计算每个集合的 column4 的唯一值的数量。最后,使用一个简单的子集来仅返回那些 unique==1 的行,并删除第 5 列。

df <- ddply(dat, .(column2, column3), transform, 
    row.no=row.no, unique=length(unique(column4)))
df[df$unique==1, -5]

结果:

  row.no column2 column3 column4
4      4      bb      yy    down
5      5      bb      zz      up
于 2011-04-17T08:30:27.837 回答
4

这是一个潜在的,如果有点不雅,解决方案

out <- with(dat, split(dat, interaction(column2, column3)))
out <- lapply(out, function(x) if(NROW(x) > 1) {NULL} else {data.frame(x)})
out <- out[!sapply(out, is.null)]
do.call(rbind, out)

这使:

> do.call(rbind, out)
      row.no column2 column3 column4
bb.yy      4      bb      yy    down
bb.zz      5      bb      zz      up

一些解释,逐行:

  • 第 1 行:将数据拆分为一个列表,其中的每个组件都是一个数据框,其中的行对应于由 和 的唯一组合形成的column2column3
  • 第 2 行:迭代第 1 行的结果;如果数据框中有超过 1 行,则返回 NULL,如果没有,则返回 1 行数据框。
  • 第 3 行:迭代第 2 行的输出;仅返回非 NULL 组件
  • 第 4 行:需要逐行绑定第 3 行的输出,我们通过do.call()

这可以简化为两行,将第 1-3 行合并为一行:

out <- lapply(with(dat, split(dat, interaction(column2, column3))),
              function(x) if(NROW(x) > 1) {NULL} else {data.frame(x)})
do.call(rbind, out[!sapply(out, is.null)])

以上全部完成:

dat <- structure(list(row.no = 1:5, column2 = structure(c(1L, 1L, 1L, 
1L, 1L), .Label = "bb", class = "factor"), column3 = structure(c(1L, 
1L, 1L, 2L, 3L), .Label = c("ee", "yy", "zz"), class = "factor"), 
    column4 = structure(c(2L, 1L, 2L, 1L, 2L), .Label = c("down", 
    "up"), class = "factor")), .Names = c("row.no", "column2", 
"column3", "column4"), class = "data.frame", row.names = c(NA, 
-5L))
于 2011-04-17T06:42:25.950 回答
4

加文不断提高答案质量的标准。这是我的尝试。

# This is one way of importing the data into R
sally <- textConnection("row.no   column2    column3  column4
1        bb         ee       up
2        bb         ee       down
3        bb         ee       up
4        bb         yy       down
5        bb         zz       up")
sally <- read.table(sally, header = TRUE)

# Order the data frame to make rle work its magic
sally <- sally[order(sally$column3, sally$column4), ]

# Find which values are repeating
sally.rle2 <- rle(as.character(sally$column2))
sally.rle3 <- rle(as.character(sally$column3))
sally.rle4 <- rle(as.character(sally$oclumn4))

sally.can.wait2 <- sally.rle2$values[which(sally.rle3$lengths != 1)]
sally.can.wait3 <- sally.rle3$values[which(sally.rle3$lengths != 1)]
sally.can.wait4 <- sally.rle4$values[which(sally.rle4$lengths != 1)]

# Find which lines have values that are repeating
dup <- c(which(sally$column2 == sally.can.wait2),
         which(sally$column3 == sally.can.wait3),
         which(sally$column4 == sally.can.wait4))
dup <- dup[duplicated(dup)]

# Display the lines that have no repeating values
sally[-dup, ]
于 2011-04-17T07:40:28.520 回答
-1

您可以尝试以下两种方法之一。假设该表称为“table1”。

方法一

repeated_rows = c();
for (i in 1:(nrow(table1)-1)){
  for (j in (i+1):nrow(table1)){
    if (sum((table1[i,2:3] == table1[j,2:3])) == 2){
      repeated_rows = c(repeated_rows, i, j)
    }
  }
}
repeated_rows = unique(repeated_rows)
table1[-repeated_rows,]

方法二

duplicates = duplicated(table1[,2:3])
for (i in 1:length(duplicates)){
  if (duplicates[i] == TRUE){
    for (j in 1:nrow(table1)){
      if (sum(table1[i,2:3] == table1[j,2:3]) == 2){
        duplicates[j] = TRUE;
      }
    }
  }
}
table1[!duplicates,]
于 2011-04-17T05:43:20.103 回答