根据条件从 data.frame 中删除行

Delete row from data.frame based on condition

我在 R 中尝试清理一些重复测量数据。在这一点上,它是长格式的,我试图在转向宽格式之前修复一些条目——例如,如果人们参加我的调查太多次,我将删除这些行。我有两个要解决的主要问题:

更改条目

如果有人在“预测试 link”中进行了调查,而实际上它应该是 post-测试,我将使用以下代码修复它:

data[data$UserID == 52118254, "Prepost"][2] <- 2

这会根据 ID 过滤掉那个人的条目,然后将第二个条目更改为编码为 post-测试。此代码具有足够的含义,查看它可以告诉我发生了什么。

掉一行

我正在努力获取有意义的代码来删除额外的行 - 例如,如果有人不小心点击了我的 link 两次。我有如下数据:

    UserID Prepost Duration..in.seconds.
1 52118250       1                   357
2 52118284       1                   226
3 52118284       1                    11 #This is an extra attempt to remove
4 52118250       2                   261
5 52118284       2                   151
#to reproduce:
structure(list(UserID = c(52118250, 52118284, 52118284, 52118250, 52118284), Prepost = c("1", "1", "1", "2", "2"), Duration..in.seconds. = c("357", "226", "11", "261", "151")), class = "data.frame", row.names = c(NA, -5L), .Names = c("UserID", "Prepost", "Duration..in.seconds."))

我可以按 UserID 进行过滤,以查看谁使用了它太多次,并且我正在寻找一种方法来轻松地从数据集中删除这些行。在这种情况下,UserID 52118284 已经尝试了三次,第二次尝试需要删除。如果它像其他修复程序一样“可读”,那就更好了。

我会使用一组 dplyr 函数,如下所示。解释一下:

group_by(UserID) 将有助于将功能分别应用到每个用户。
mutate(click_n = row_number()) 迭代计算用户出现次数并将其保存为新变量 click_n.

library(dplyr)

data %>% 
  group_by(UserID) %>% 
  mutate(click_n = row_number())
#> Source: local data frame [5 x 4]
#> Groups: UserID [4]
#> 
#>     UserID Prepost Duration..in.seconds. click_n
#>      <dbl>   <chr>                 <chr>   <int>
#> 1 52118254       1                   357       1
#> 2 52118284       1                   226       1
#> 3 52118284       1                    11       2
#> 4 52118250       2                   261       1
#> 5 52118280       2                   151       1

filter(click_n == 1) 可用于仅保留第一次尝试,如下所示。

data <- data %>% 
  group_by(UserID) %>% 
  mutate(click_n = row_number()) %>% 
  filter(click_n == 1)
data
#> Source: local data frame [4 x 4]
#> Groups: UserID [4]
#> 
#>     UserID Prepost Duration..in.seconds. click_n
#>      <dbl>   <chr>                 <chr>   <int>
#> 1 52118254       1                   357       1
#> 2 52118284       1                   226       1
#> 3 52118250       2                   261       1
#> 4 52118280       2                   151       1

请注意,此方法假定您的数据框是有序的。即,第一次点击出现在顶部附近。

如果您不熟悉 %>%,请在 "pipe operator" 上寻求帮助。

额外:

要将评论变成答案,一旦您对这里发生的事情感到满意,您可以跳过 mutate 行,只需执行以下操作:

data %>% group_by(UserID) %>% filter(row_number() == 1)

下面是删除重复项的简单解决方案:

subset(data, !duplicated(data$UserID))

但是,您可能还需要考虑按持续时间进行子集化,例如,如果持续时间少于 30 秒。

感谢@Simon 的建议。我想要的一个标准是代码有意义,因为我 "read" 它。正如我所想的那样,另一个标准是我想仔细考虑要进行哪些更改。所以我采纳了 Simon 的建议,单独列了一个专栏,然后使用 dplyr::filter() 来排除那些变量。下面是一段示例代码:

#Change pre/post entries
data[data$UserID == 52118254, "Prepost"][2] <- 2

#Mark rows to delete
data$toDelete <- NA #Makes new empty column for marking deletions
data[data$UserID == 52118284,][2, "toDelete"] <- 1 #Marks row for deletion

#Filter to exclude rows
data %>% filter(is.na(toDelete))
    #Optionally add "%>% select(-toDelete)" to remove the extra column

在我的上下文中,这里的优点是一切都是故意的而不是自动的,并且更改锚定到数据而不是可能更改的行号。我仍然欢迎任何反馈或其他实现此目的的方法(也许只需一步)。