从具有每最小最大值的数据框到每个键的值

From dataframe with values per min max to value per key

我有一个数据框,每个桶都定义了值。 (见下面的 df1) 现在我有另一个数据框,其中包含那些桶中的值,我想从桶中的数据框中查找值(参见下面的 df2)

现在我想要下面的结果 df3。

df1 <- data.frame(MIN = c(1,4,8), MAX = c(3, 6, 10), VALUE = c(3, 56, 8))
df2 <- data.frame(KEY = c(2,5,9))
df3 <- data.frame(KEY = c(2,5,9), VALUE = c(3, 56, 8))

> df1
  MIN MAX VALUE
1   1   3     3
2   4   6    56
3   8  10     8
> df2
  KEY
1   2
2   5
3   9
> df3
  KEY VALUE
1   2     3
2   5    56
3   9     8

编辑: 扩展示例。

> df1 <- data.frame(MIN = c(1,4,8, 14), MAX = c(3, 6, 10, 18), VALUE = c(3, 56, 3, 5))
> df2 <- data.frame(KEY = c(2,5,9,18,3))
> df3 <- data.frame(KEY = c(2,5,9,18,3), VALUE = c(3, 56, 3, 5, 3))
> df1
  MIN MAX VALUE
1   1   3     3
2   4   6    56
3   8  10     3
4  14  18     5
> df2
  KEY
1   2
2   5
3   9
4  18
5   3
> df3
  KEY VALUE
1   2     3
2   5    56
3   9     3
4  18     5
5   3     3

此解决方案假设 KEYMINMAX 是整数,因此我们可以创建一个键序列,然后连接。

df1 <- data.frame(MIN = c(1,4,8, 14), MAX = c(3, 6, 10, 18), VALUE = c(3, 56, 3, 5))
df2 <- data.frame(KEY = c(2,5,9,18,3))

library(dplyr)
library(purrr)
library(tidyr)

df1 %>%
  group_by(VALUE, id=row_number()) %>%             # for each value and row id
  nest() %>%                                       # nest rest of columns
  mutate(KEY = map(data, ~seq(.$MIN, .$MAX))) %>%  # create a sequence of keys
  unnest(KEY) %>%                                  # unnest those keys
  right_join(df2, by="KEY") %>%                    # join the other dataset
  select(KEY, VALUE) 

# # A tibble: 5 x 2
#     KEY VALUE
#   <dbl> <dbl>
# 1  2.00  3.00
# 2  5.00 56.0 
# 3  9.00  3.00
# 4 18.0   5.00
# 5  3.00  3.00

或者,仅按行号分组并在 map 中添加 VALUE

df1 %>%
  group_by(id=row_number()) %>% 
  nest() %>%                 
  mutate(K = map(data, ~data.frame(VALUE = .$VALUE, 
                                   KEY = seq(.$MIN, .$MAX)))) %>%
  unnest(K) %>%
  right_join(df2, by="KEY") %>% 
  select(KEY, VALUE)

来自@AntioniosK 的一个非常好的和深思熟虑的解决方案。

这是一个基本的 R 解决方案,它作为一个通用查找函数实现,作为参数给出了一个关键数据帧和一个如问题中所列定义的存储桶数据帧。在此示例中,查找值不必是唯一的或连续的,考虑到@Michael 的评论,即值可能出现在多行中(尽管通常此类查找会使用唯一范围)。

lookup = function(keydf, bucketdf){
  keydf$rowid = 1:nrow(keydf)
  T = merge(bucketdf, keydf)
  T = T[T$KEY >= T$MIN & T$KEY <= T$MAX,]
  T = merge(T, keydf, all.y = TRUE)
  T[order(T$rowid), c("rowid", "KEY", "VALUE")]
}

第一个合并使用笛卡尔连接键中的所有行到存储桶列表中的所有行。如果实际表中的行数很大,则此类连接可能效率低下,因为将键中的 x 行连接到存储桶中的 y 行将是 xy 行;我怀疑在这种情况下这会是个问题,除非 x 或 y 运行 成数千行。

完成第二次合并以恢复任何 与存储桶列表中的行匹配的键值。

使用@AntioniosK 中列出的示例数据 post:

> lookup(df2, df1)
  rowid KEY VALUE
2     1   2     3
4     2   5    56
5     3   9     3
1     4  18     5
3     5   3     3

使用键和桶示例测试边缘情况(其中键 = 最小值或最大值),其中键值不在桶列表中(df2A 中的值 50),并且有非-独特的范围(下面 df4 的第 6 行):

df4 <- data.frame(MIN = c(1,4,8, 20, 30, 22), MAX = c(3, 6, 10, 25, 40, 24), VALUE = c(3, 56, 8, 10, 12, 23))
df2A <- data.frame(KEY = c(3, 6, 22, 30, 50))

df4
  MIN MAX VALUE
1   1   3     3
2   4   6    56
3   8  10     8
4  20  25    10
5  30  40    12
6  22  24    23

> df2A
  KEY
1   3
2   6
3  22
4  30
5  50

> lookup(df2A, df4)
  rowid KEY VALUE
1     1   3     3
2     2   6    56
3     3  22    10
4     3  22    23
5     4  30    12
6     5  50    NA

如上所示,在这种情况下的查找 returns 与键值 22 匹配的非唯一范围的两个值,以及键中但不在存储桶列表中的值的 NA。