【问题标题】:Replacing values in data frame in R替换R中数据框中的值
【发布时间】:2016-02-10 20:49:12
【问题描述】:

我正在尝试在 R 中完成一项有点复杂的任务。

我有一个data frame(为简单起见)三列。

第 1 列是一个字符串。
第 2 列是一个整数。
第 3 列是一个整数。

我想获取第 1 列中包含某个子字符串并且第 2 列具有精确值的所有观察值,并将第三列替换为数字 1。

也就是说,我有以下dataframe

x <- data.frame(x1 = c("bob","jane","bob","bobby","bob","jane","bobby","bob","jane","bob"),
                x2 = c(1,1,1,1,1,2,2,2,2,2),
                x3 = c(13,22,3,34,10,23,53,42,13,35))

而且,我想选择第 1 列包含 bob 且第 2 列==1 的观察值,并将第三列更改为 1,这样我最终得到:

y1 <- c("bob","jane","bob","bobby","bob","jane","bobby","bob","jane","bob")
y2 <- c(1,1,1,1,1,2,2,2,2,2)
y3 <- c(1,22,1,1,1,23,53,42,13,35)
y <- data.frame(y1,y2,y3)

我想在一个非常非常大的数据集上执行此操作。拆分数据集并将其重新组合在一起是不可行的。 我尝试过使用grep,但是当我尝试同时进行两场比赛时它不起作用。另外,我尝试过子集,但是我必须将dataframe 分开并将其重新组合在一起。 提前非常感谢。

【问题讨论】:

  • grepl 通常更有用,因为它支持逻辑测试与矢量化&amp;| 的组合。

标签: r dataframe


【解决方案1】:

借助 R 使用 [&lt;- 函数进行逻辑索引的能力,这真的很容易:

> x$x3[ grepl("bob", x$x1) & x$x2 == 1] <- 1
> x
      x1 x2 x3
1    bob  1  1
2   jane  1 22
3    bob  1  1
4  bobby  1  1
5    bob  1  1
6   jane  2 23
7  bobby  2 53
8    bob  2 42
9   jane  2 13
10   bob  2 35

要阅读代码,您应该将其视为:“对于 x 的每一行,其中列 'x1' 具有 "bob' 并且列 'x2' 等于 1 ,...您将值 1 分配给列'x3'。”如果您想拥有一个具有该值的新对象,您可以使用 y &lt;- x 制作 x 的副本,然后进行处理。

【讨论】:

  • ifelse 类似的东西:ifelse((x$x2 == 1 &amp; grepl("bob", x$x1)), 1, x$x3)
  • @RonakShah ifelse 不如一般的替换策略那么好。试试ifelse(c(TRUE,FALSE), Sys.Date()+1, Sys.Date()) # doesn't return dates
  • @Frank Ohh..在这种情况下我们应该避免使用ifelse吗?那么运行时间呢?是一样还是ifelse很慢?
  • @RonakShah 是的,它通常很慢stackoverflow.com/q/16275149/1191259 但有时比其他选择更方便。我尽量避免。
  • @Frank 非常感谢。这很有帮助!
【解决方案2】:
x1   <- c("bob","jane","bob","bobby","bob","jane","bobby","bob","jane","bob")
x2   <- c(1,1,1,1,1,2,2,2,2,2)
x3   <- c(13,22,3,34,10,23,53,42,13,35)
x    <- data.frame(x1,x2,x3)

rows <- grepl("bob", x[,1]) & x[,2] == 1 # Logical Selector Of Rows

x[rows, 3] <- 1

除了符号之外,我的答案和@42- 的答案之间的主要区别是我的logical-selector-of-rows 短语仅在数据帧上运行,而@42- 引用了原始向量之一(可能由监督)。

      x1 x2 x3
1    bob  1  1
2   jane  1 22
3    bob  1  1
4  bobby  1  1
5    bob  1  1
6   jane  2 23
7  bobby  2 53
8    bob  2 42
9   jane  2 13
10   bob  2 35

【讨论】:

  • x[rows, 3]x$x3[rows] 之间确实没有本质区别。
  • .... 只是样式/可读性。但是,我指的是 x2 和 x$x2 之间的差异(同时您已在答案中更正)
  • 是的。有人已经修复了这个疏忽。我编辑了问题以删除不必要的向量。
【解决方案3】:

如果您正在寻找子字符串 grep,可以在这种情况下与 'ifelse' 函数一起使用。以 x 作为数据框并希望更改 x$x3 执行以下操作,

1: 找到需要的子字符串

req_sub<-grep("bob",x$x1)

这将返回子字符串中匹配的x3的所有位置

2:在第 x3 列中进行更改

x$x3[grep("bob",x$x1)]<-ifelse(x[req_sub,]$x2==1,1,x[req_sub,]$x3)

以下将是输出

      x1 x2 x3
1    bob  1  1
2   jane  1 22
3    bob  1  1
4  bobby  1  1
5    bob  1  1
6   jane  2 23
7  bobby  2 53
8    bob  2 42
9   jane  2 13
10   bob  2 35

【讨论】:

    【解决方案4】:

    用户 akrun 使用 dplyr 包对类似问题 here 提供了一个很好的答案,用户 docendo discimus here 提供了一个更快的变体。在您的情况下,代码将是:

    x %&gt;% mutate(x3 = replace(x3, x1 == 'bob' &amp; x2 == 1, 1))

    x %&gt;% mutate(x3 = replace(x3, which(x1 == 'bob' &amp; x2 == 1), 1))

    如果你想直接更新 x,你可以结合 magrittr 包中的 %&lt;&gt;% 操作符为:

    x %&lt;&gt;% mutate(x3 = replace(x3, x1 == 'bob' &amp; x2 == 1, 1))

    【讨论】:

    • 如何处理包含“bob”的字符串,例如示例中的“bobby”?谢谢。
    • 然后,我会调用grepl(它返回一个逻辑)来救援:x %% mutate(x3 = replace(x3, grepl('bob', x1) & x2 == 1, 1))
    【解决方案5】:

    您也可以使用data.table 包获得高性能:

    library(data.table)
    setDT(x)[grepl('bob', x1) & x2==1, x3:=1][]
    
    #       x1 x2 x3
    # 1:   bob  1  1
    # 2:  jane  1 22
    # 3:   bob  1  1
    # 4: bobby  1  1
    # 5:   bob  1  1
    # 6:  jane  2 23
    # 7: bobby  2 53
    # 8:   bob  2 42
    # 9:  jane  2 13
    #10:   bob  2 35
    

    【讨论】:

      猜你喜欢
      • 2014-12-15
      • 1970-01-01
      • 2022-01-14
      • 1970-01-01
      • 2018-05-04
      • 1970-01-01
      • 2012-10-01
      • 2015-07-15
      • 2017-08-06
      相关资源
      最近更新 更多