【问题标题】:Delete row from data.frame based on condition根据条件从 data.frame 中删除行
【发布时间】:2017-01-31 23:02:39
【问题描述】:

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

更改条目

如果有人在实际上应该是后测时从“前测链接”中进行了调查,我将使用以下代码对其进行修复:

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

这会根据 ID 过滤掉那个人的条目,然后将第二个条目更改为后测。这段代码有足够的意义,回顾它会告诉我发生了什么。

删除一行

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

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

【问题讨论】:

  • 或许df[!duplicated(interaction(df$UserID,df$Prepost)),]?
  • @A 我认为如果存在系统问题,这可能会奏效,但我必须逐案处理并确定哪个是错误的。

标签: r data-cleaning


【解决方案1】:

我会使用一组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

请注意,这种方法假定您的数据框是有序的。即,首次点击出现在靠近顶部的位置。

如果您不熟悉%&gt;%,请在“管道运算符”上寻求帮助。

额外:

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

data %&gt;% group_by(UserID) %&gt;% filter(row_number() == 1)

【讨论】:

  • 谢谢。我熟悉dplyrmutaterow_number。这可能是因为“标记”要删除的行的中间步骤。实际上,我可以为这些删除创建一个变量,类似于我的更改,然后一次删除所有内容。
  • 太棒了。如果您熟悉它,那么您可以跳过mutate 行,直接转到data %&gt;% group_by(UserID) %&gt;% filter(row_number() == 1)。我也添加了这个来回答其他人。
【解决方案2】:

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

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

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

【讨论】:

  • 我需要保留重复项,因为它现在是长数据格式。即使我通过重复的 UserID 和 Prepost 值进行过滤,我也希望对其进行更多控制。编辑:我意识到我的示例数据有点错误,应该只有两个ID,所以再看一遍。
【解决方案3】:

感谢@Simon 的建议。我想要的一个标准是代码在我“阅读”时是有意义的。当我想得更多时,另一个标准是我想仔细考虑要做出哪些改变。所以我采纳了 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

在我的上下文中,这里的优点是一切都是经过深思熟虑的而不是自动的,并且更改锚定到数据而不是可能更改的行号。我仍然欢迎任何反馈或实现这一目标的其他方式(可能是一步)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-06-04
    • 2018-01-11
    • 2018-03-03
    • 2023-02-21
    相关资源
    最近更新 更多