【问题标题】:Select rows with at least one (any) negative value选择至少有一个(任何)负值的行
【发布时间】:2021-05-22 15:10:18
【问题描述】:

我希望创建一个新的 data.table,其中包含至少一个负值的所有行。

这是一个简单的可重现数据表:

dt <- data.table(
  ID = c(42, 43, 44),
  Stage_1 = c(-6, 7, 4),
  Stage_2 = c(-15, 4, -8),
  Stage_3 = c(-20, 2, -5)
)

#    ID Stage_1 Stage_2 Stage_3
# 1: 42      -6     -15     -20 # <~~ row to be selected (> 0 negative values)
# 2: 43       7       4       2
# 3: 44       4      -8      -5 # <~~ row to be selected (> 0 negative values)

我想要的输出是:

dt2 <- data.table(
  ID = c(42, 44),
  Stage_1 = c(-6, 4),
  Stage_2 = c(-15, -8),
  Stage_3 = c(-20, -5)
)

#    ID Stage_1 Stage_2 Stage_3
# 1: 42      -6     -15     -20
# 2: 44       4      -8      -5

例如,ID 44 有两个负值,但我想包括主数据表中的所有行。基本上,我想将所有列中 any 中具有负值的所有行添加到包含其所有信息的新数据表中。

我正在使用的实际数据集有大约 50 个阶段列,因此最有效的解决方案就是我所追求的。

【问题讨论】:

  • 另一种可能性:dt[dt[ , do.call(pmin, .SD) &lt; 0, .SDcols = -1]],例如描述的想法here
  • 还有Reduce("|", lapply(.SD,,如所述,例如here

标签: r data.table subset data-manipulation


【解决方案1】:
dt <- data.table::data.table(
  ID = c(42, 43, 44),
  Stage_1 = c(-6, 7, 4),
  Stage_2 = c(-15, 4, -8),
  Stage_3 = c(-20, 2, -5)
)

dt
#>    ID Stage_1 Stage_2 Stage_3
#> 1: 42      -6     -15     -20
#> 2: 43       7       4       2
#> 3: 44       4      -8      -5
  • 带有apply()函数:
dt[apply(dt[, -'ID'], 1, min) < 0, ]
#>    ID Stage_1 Stage_2 Stage_3
#> 1: 42      -6     -15     -20
#> 2: 44       4      -8      -5
  • 使用rowMeans() 函数基于具有至少一个真值的布尔向量的平均值始终大于零这一事实(感谢@utubun):
dt[rowMeans(dt[, -'ID'] < 0) > 0, ]
#>    ID Stage_1 Stage_2 Stage_3
#> 1: 42      -6     -15     -20
#> 2: 44       4      -8      -5
  • 以及fBasics 包的rowMins() 函数:
dt[fBasics::rowMins(dt[, -'ID']) < 0, ]
#>    ID Stage_1 Stage_2 Stage_3
#> 1: 42      -6     -15     -20
#> 2: 44       4      -8      -5

# Created on 2021-02-19 by the reprex package (v0.3.0.9001)

(与Equivalent to rowMeans() for min()相关)

问候,

【讨论】:

  • 这是一种非常有效的代码执行方式!如果将来列的数量发生变化,为了避免更改代码,我会在函数中添加nrow(dt)。据此:dt[apply(dt[,2:nrow(dt)], 1, min) &lt; 0,]
  • 是我,还是你的意思是dt[, 2:ncol(dt)]?它之所以有效,是因为它是平方数据,否则它将无法正常工作。
  • 哦,是的,确实,非常感谢。我纠正了。
  • 是的,对不起,我的错。 @utubun 感谢您的检查
  • 是的,您可以使用rowMeans() 代替apply(),这只是基于以下事实,即具有至少一个真值的布尔向量的平均值始终大于零,这导致@987654336 @
【解决方案2】:
dt[Stage_1 < 0 | Stage_2 < 0 | Stage_3 < 0]

#    ID Stage_1 Stage_2 Stage_3
# 1: 42      -6     -15     -20
# 2: 44       4      -8      -5

在 OP 澄清后编辑:

有很多列:

# Find all the rows with at least one negative in each column
rowsDT <- dt[, lapply(.SD, function(x) which(x < 0)), .SDcols = -'ID']
# Reduce to a vector by applying union
rows <- Reduce(union, rowsDT)
# Extract from the main data.table
dt[rows]

【讨论】:

  • 谢谢!我应该把它包含在我原来的问题中,但我想避免这种语法,因为我正在使用的实际数据集大约有 50 个阶段列
  • 罗杰。我相应地更新了答案。不确定这是否是最有效的,但应该会相对较快。
  • 谢谢!完美运行
【解决方案3】:

不知道是不是真的很好的风格,但作为速记你可以使用:

dt[ dt[, any(.SD < 0), by = ID][['V1']], ]

#    ID Stage_1 Stage_2 Stage_3
# 1: 42      -6     -15     -20
# 2: 44       4      -8      -5

¹但是,如果 ID 不是唯一的,它可能会产生意想不到的结果。

【讨论】:

  • ID 可以替换为 list(rownames(dt)) 以获得唯一标识符。
  • 希望保持简短。但是,是的,因为在子集调用中不需要ID,所以有办法解决。我想知道所有解决方案的分析会是什么样子。
【解决方案4】:

data.table 选项使用 sign + rowSums

> dt[, .SD[rowSums(sign(.SD)) < length(.SD)], ID]
   ID Stage_1 Stage_2 Stage_3
1: 42      -6     -15     -20
2: 44       4      -8      -5

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-04-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-05-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多