【问题标题】:R - Finding minimum values based on multiple conditions and returning one or multiple created strings based on the minimum valueR - 根据多个条件查找最小值并根据最小值返回一个或多个创建的字符串
【发布时间】:2014-04-29 17:34:37
【问题描述】:

我问这个问题是this one 的后续问题,@alexis_laz 以非常简洁的方式回答了这个问题。 不幸的是,他的方法(包括创建一个带有零负载的长数据框)现在原始数据集已经急剧扩展,因此数据过于密集。

基本问题就是这个。 考虑一个具有三列 x、y、z 的数据框。我正在寻找与每个 y 的最低 x 值相关联的 z 和 x 的值。理想的输出是y[i]_x[i]_z[i] 类型的字符串,其中 i 是相关的行号。

这是一个可重现的示例 set.seed(1)

x <- rpois(10000, lambda = 10); x[sample.int(50, 20)] <- NA
y <- rep(LETTERS, length.out=10000)
z <- seq(1:10000)
df <- data.frame(cbind(x,y,z))

所需的输出(我通过简单地订购 df 和滚动找到):

df &lt;- df[order(y,x,z),]

  1. 对于 y = A,min(x) = 2,z = 313 => 所需的结果(NA 可以被删除)应该类似于 paste0(y,"_",x,"_",z) 因此 A_1_313
  2. 对于 y = B,min(x) = 2,z = 782、6008 或 7230 => 所需结果将为我提供所有三个字符串,即 B_2_782、B_2_6008 和 B_2_7230
  3. 对于 y = F,min(x) = 3,这个最小值与 5 个不同的 z 值(4114、4712、5336、7234、7520)相关,所以我想得到五个字符串 ....

我不希望在真实数据集中的任何地方都有超过 5 个字符串作为输出。 如前所述,@alexis_laz 为几乎相同的问题(我也问过)提供了一个解决方案,但该解决方案需要创建一个超过我的计算机能力的数据帧(>2.4GB 数据帧,6.5 亿行),因为我的数据集已经从37 到 15000 家公司:)

提前致谢!

PS: 我已经使用max.colwhich.maxtapply 寻找解决方案,但到目前为止没有一个对我有用。似乎tapply(x,y,which.min) 之类的东西只是在有序 df 中返回 1 的列表,因为 which.min 返回向量/矩阵中的位置,该位置在 tapply 函数中始终为 1。因此,使用 tapply 但返回 df 的行号的东西将是工作的 99%。

【问题讨论】:

    标签: r tapply


    【解决方案1】:

    编辑:我被一个微妙的data.table 行为所困扰。 data.table 保留汇总数据的密钥,但仅保留您汇总的数据。所以加入并没有做我认为它正在做的事情。这是完全相同的逻辑,但需要一个临时步骤来取消设置分组数据的部分键:

    # data generated with `set.seed(1)`
    library(data.table)
    dt <- data.table(x, y, z)[!is.na(x)]
    setkey(dt, y, x)                                   # among other things, this sorts `dt` by `x` and `y` quickly
    sub.dt <- dt[, list(x=x[[1]]), by=y][, list(y, x)] # get low X for each Y, and reorder cols to match key
    setkey(sub.dt, NULL)                               # need to remove key as otherwise would join only on `y`
    dt[sub.dt, paste(x, y, z, sep="_")]                # now join
    

    生产:

        y x       V1
     1: A 1  1_A_313
     2: B 2  2_B_782
     3: B 2 2_B_6008
     4: B 2 2_B_7230
     5: C 2 2_C_2993
     6: D 2 2_D_4762
     7: E 2  2_E_239
     8: E 2 2_E_4581
     9: F 3 3_F_4114
    10: F 3 3_F_4712
    ...
    41: S 2 2_S_3113
    42: S 2 2_S_7949
    43: T 2 2_T_4570
    44: U 1  1_U_671
    45: V 2  2_V_178
    46: W 2 2_W_1817
    47: W 2 2_W_2233
    48: X 1  1_X_648
    49: Y 2  2_Y_857
    50: Y 2 2_Y_7227
    51: Z 3 3_Z_6526
        y x       V1
    

    Edit2:由 Arun 在 cmets 中提供的更简洁的版本:

    dt[dt[, .I[x==min(x)], by=y][, V1]]
    

    【讨论】:

    • 嗨@BrodieG,非常感谢这个建议。我不确定它是否真的解决了我的问题。运行您的代码,我以 9980 个解决方案结束,这似乎太多了。应该只存在与不同 y 变量一样多的解决方案(所以 26),考虑到每个 y 变量可能有多个解决方案(例如,在 y = G 和这些 y_x 组合中的每一个都附加了另一个 z 值。应该设置种子,现在将做并编辑我的问题
    • 我看到你 set.seed 为 1。所以我所追求的只是最小的解决方案(基本上只有 A_1_313 用于 A)。它消除了所有其他问题。
    • @simon_icl,是的,我使用了set.seed(1)。见更新。如果您只想要每个 Y 的最低 X/Z 值,那就更容易了。
    • 哇哇哇哇。我不敢相信这进展得有多快。在超过 150.000 行上运行它实际上只用了不到 1.5 秒。那是一些强大的编程。非常感谢。我真的要研究 data.tables 中的子集。这将为我节省大量时间。非常感谢@BrodieG!
    猜你喜欢
    • 2017-05-16
    • 2014-01-21
    • 2021-12-31
    • 1970-01-01
    • 1970-01-01
    • 2014-02-04
    • 2022-01-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多