R - 根据多个条件查找最小值,并根据最小值返回一个或多个创建的字符串

时间:2014-04-29 17:34:37

标签: r tapply

我问这个问题是this one的后续问题,@alexis_laz以一种非常简洁的方式回答了这个问题。 不幸的是,他的方法(包括创建一个带有零加载的长数据帧)的数据太强,现在原始数据集已经大大扩展。

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

这是一个可重复的例子 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 <- df[order(y,x,z),]

  1. 对于y = A,min(x)= 2,其中z = 313 =&gt;期望的结果(可以删除NA)应该类似于paste0(y,"_",x,"_",z),因此A_1_313
  2. 对于y = B,min(x)= 2,其中z = 782,6008或7230 =&gt;期望的结果会给我所有三个字符串,因此B_2_782,B_2_6008和B_2_7230
  3. 对于y = F,min(x)= 3且此最小值与5个不同的z值(4114,4712,5336,7234,7520)相关联,因此我想得到5个字符串 ....
  4. 我不希望真实数据集中的任何地方输出超过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的rownumber的东西将是作业的99%。

1 个答案:

答案 0 :(得分:2)

编辑:我有点微妙的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在评论中提供的更清洁的版本:

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