3

我遇到了一个非常复杂的问题。我有一个包含三行的数据框:id、info 和 rownum。数据如下所示:

id   info   row
 1      a     1
 1      b     2
 1      c     3
 2      a     4
 3      b     5
 3      a     6
 4      b     7
 4      c     8

我现在要做的是删除一个 id 的所有其他行,如果其中一行包含信息a。这意味着例如第2行和第 3行应该被删除,因为第1行的列信息包含值a。请注意,信息值未排序(id 3/第 5 行和第 6 行)并且由于其他数据限制而无法排序。

我使用for 循环解决了这个问题:

# select all id containing an "a"-value 
a_val <- data$id[grep("a", data$info)]

# check for every id containing an "a"-value
for(i in a_val) {

   temp_data <- data[which(data$id == i),]

   # only go on if the given id contains more than one row
   if (nrow(temp_data) > 1) {

      for (ii in nrow(temp_data)) {

         if (temp_data$info[ii] != "a") {
            temp <- temp_data$row[ii]

            if (!exists("delete_rows")) {
               delete_rows <- temp
            } else {
               delete_rows <- c(delete_rows, temp)
            }
         }
      }
   }
}

我的解决方案效果很好。然而,它非常、非常、非常慢,因为原始数据包含超过 70 万行和超过 15 万行的“a”值。

我可以使用具有 4 个核心的foreach循环来加速它,但也许有人可以给我一个提示以获得更好的解决方案。

最好的问候,
阿恩

[更新]

结果应该是:

id   info   row
 1      a     1
 2      a     4
 3      a     6
 4      b     7
 4      c     8
4

5 回答 5

2

这是一种可能的解决方案。

首先找到ids 其中info包含"a"

ids <- with(data, unique(id[info == "a"]))

子集数据:

subset(data, (id %in% ids & info == "a") | !id %in% ids)

输出:

  id info row
1  1    a   1
4  2    a   4
6  3    a   6
7  4    b   7
8  4    c   8

另一种解决方案(可能更难破译):

subset(data, info == "a" | !rep.int(tapply(info, id, function(x) any(x == "a")),
                                    table(id)))

注意。@BenBarnes 发现此解决方案仅在数据框根据id.

于 2012-11-26T11:37:56.347 回答
2

您可能需要调查该data.table软件包:

编辑:如果row变量不是数据中每一行的顺序编号(正如我假设的那样),您可以创建这样一个变量来获取原始行顺序:

library(data.table)
# Create data.table of your data
dt <- as.data.table(data)
# Create index to maintain row order
dt[, idx := seq_len(nrow(dt))]
# Set a key on id and info
setkeyv(dt, c("id", "info"))
# Determine unique ids
uid <- dt[, unique(id)]
# subset your data to select rows with "a"
dt2 <- dt[J(uid, "a"), nomatch = 0]
# identify rows of dataset where the id doesn't have an "a"
dt3 <- dt[J(dt2[, setdiff(uid, id)])]
# rbind those two data.tables together
(dt4 <- rbind(dt2, dt3))

#    id info row idx
# 1:  1    a   1   1
# 2:  2    a   4   4
# 3:  3    a   6   6
# 4:  4    b   7   7
# 5:  4    c   8   8

# And if you need the original ordering of rows,
dt5 <- dt4[order(idx)]

请注意,为 设置键data.table将根据键列对行进行排序。最后一步(创建dt5)将行顺序设置回原来的顺序。

于 2012-11-26T11:42:27.553 回答
1

这是一种使用方法ddply

df <- read.table(text="id   info   row
 1      a     1
 1      b     2
 1      c     3
 2      a     4
 3      b     5
 3      a     6
 4      b     7
 4      c     8",header=TRUE)


library("plyr")
ddply(df,.(id),subset,rep(!'a'%in%info,length(info))|info=='a')

回报:

  id info row
1  1    a   1
2  2    a   4
3  3    a   6
4  4    b   7
5  4    c   8
于 2012-11-26T11:44:57.880 回答
0

如果 df 是这个(上面的 RE Sacha),则使用match来查找第一次出现的索引:

df <- read.table(text="id   info   row
 1      a     1
 1      b     2
 1      c     3
 2      a     4
 3      b     5
 3      a     6
 4      b     7
 4      c     8",header=TRUE)


# the first info row matching 'a' and all other rows that are not 'a'
with(df, df[c(match('a',info), which(info != 'a')),])

  id info row
1  1    a   1
2  1    b   2
3  1    c   3
5  3    b   5
7  4    b   7
8  4    c   8
于 2012-11-26T16:47:21.853 回答
-1

尝试看一下子集,它很容易使用,它会解决你的问题。

您只需要指定要基于子集的列的值,或者您可以选择更多列。

http://stat.ethz.ch/R-manual/R-devel/library/base/html/subset.html

http://www.statmethods.net/management/subset.html

于 2012-11-26T11:22:34.030 回答