在运行查询之前“预测”查询结果

sta*_*oob 5 r data-manipulation

我有以下数据集(每个变量可以取 1-10 之间的值):

factor <- c(1,2,3,4,5,6,7,8,9,10)

var_1 <- as.factor(sample(factor, 10000, replace=TRUE, prob=c(0.1,0.1,0.1,0.1,0.1, 0.1,0.1,0.1,0.1,0.1)))
var_2 <- as.factor(sample(factor, 10000, replace=TRUE, prob=c(0.1,0.1,0.1,0.1,0.1, 0.1,0.1,0.1,0.1,0.1)))    
var_3 <- as.factor(sample(factor, 10000, replace=TRUE, prob=c(0.1,0.1,0.1,0.1,0.1, 0.1,0.1,0.1,0.1,0.1)))    
var_4 <- as.factor(sample(factor, 10000, replace=TRUE, prob=c(0.1,0.1,0.1,0.1,0.1, 0.1,0.1,0.1,0.1,0.1)))
var_5 <- as.factor(sample(factor, 10000, replace=TRUE, prob=c(0.1,0.1,0.1,0.1,0.1, 0.1,0.1,0.1,0.1,0.1)))

my_data = data.frame(var_1, var_2, var_3, var_4, var_5)

head(my_data)
  var_1 var_2 var_3 var_4 var_5
1     2     9     8     3     5
2    10     1     4     7     5
3     4     7     1     7     6
4     9     8     3     4     7
5     6     5     5     9     7
6     2     8    10     2     7
Run Code Online (Sandbox Code Playgroud)

我还有一个数据框,其中包含一系列用于从此数据框中选择行的“条件”:

conditions = data.frame(var_1 = c("1,2", "2"), var_2 = c("1,2,3,4", "1,2,3,8,9"), var_3 = c("4,6", "5,6,7"))

 conditions
  var_1     var_2 var_3
1   1,2   1,2,3,4   4,6
2     2 1,2,3,8,9 5,6,7
Run Code Online (Sandbox Code Playgroud)

假设我想对此数据集运行以下查询:

query_1 <- my_data[Reduce(`&`,
  Map(`%in%`,
      lapply(my_data[,1:3], as.character),
      lapply(conditions, function(z) strsplit(z, ",")[[1]]))),]

query_2 <- my_data[Reduce(`&`,
  Map(`%in%`,
      lapply(my_data[,1:3], as.character),
      lapply(conditions, function(z) strsplit(z, ",")[[2]]))),]

# traditional form for reference 
# query_1 = my_data[my_data$var_1 %in% c("1", "2") & my_data$var_2 %in% c("1", "2", "3", "4") & my_data$var_3 %in% c("4", "6") ,  ]

# query_2 = my_data[my_data$var_1 %in% c("2") & my_data$var_2 %in% c("1", "2", "3", "8", "9") & my_data$var_3 %in% c("5", "6", "7") ,  ]
Run Code Online (Sandbox Code Playgroud)

很明显,这两个查询的结果并不相同:

> identical(query_1, query_2)
[1] FALSE
Run Code Online (Sandbox Code Playgroud)

然而,我们也可以看到,尽管两个查询的结果不相同,但这两个查询之间仍然存在公共行:

combined <- rbind(query_1, query_2)

duplicate_rows <- unique(combined[duplicated(combined), ])

ifelse(nrows(duplicate_rows) == 0, "EMPTY", "NOT EMPTY")

[1] "NOT EMPTY"
Run Code Online (Sandbox Code Playgroud)

我的问题:是否可以以某种方式向“条件”数据帧添加一些“随机噪声”,以便“query_1”和“query_2”将没有公共行?

我知道一个简单的解决方案是确保“query_1”和“query_2”的条件中不存在任何常见数字- 但使用基本逻辑,“query_1”和“query_2”的条件中可能存在一些常见数字query_1”和“query_2”,仍然导致“query_1”和“query_2”没有公共行。

例如:

  • Query_1:身高 = 高且篮球 = 是

  • Query_2:身高 = 高 AND 篮球 = 否

  • Query_3:身高 = 不高且篮球 = 否

  • Query_4:身高 = 高且篮球 = 是

在这种情况下,很明显 Query_3 和 Query_4 将不会共享公共记录,因为它们的身高和篮球条件完全相反。

但是,Query_1 和 Query_2 对于“高度”共享相似的条件,但对于“篮球”共享不同的条件 - 这也将导致 Query_1 和 Query_2 不共享公共行。例如,罗伯特·瓦德洛(Robert Wadlow)(https://en.wikipedia.org/wiki/Robert_Wadlow)很高并且不打篮球,但是威尔特·张伯伦(Wilt Chamberlain)(https://en.wikipedia.org/wiki/Wilt_Chamberlain)很高并且打篮球打篮球。两者都有一个共同的“高”,但由于他们对“篮球”有独特的价值,所以他们属于不同的类别。从逻辑上讲,您可以考虑地球上的全部人口,但由于两个查询的排他性,“query_1”和“query_2”的结果中仍然不会出现人类。

同样,我想预先预测和预期早期查询的结果,并确保这些查询没有公共行 - 如果它们确实有公共行,我想向其中添加一些“随机噪声”用于创建这些查询的条件(数据框),以便这些查询不共享公共行。

因此,有没有办法获取“条件”数据帧并向该数据帧添加一些“随机噪声”,以便 Query_1 和 Query_2 不会共享任何公共行?

shs*_*shs 2

我认为您可以通过三种方式来解决这个问题。

\n
    \n
  1. 事先确保条件是不相交的。
  2. \n
  3. 编写拒绝采样函数(如 bdecaf 提到的)或找到实现它的包
  4. \n
  5. 然后,取两个数据集的交集并将其元素随机分配给两个集合中的任何一个。
  6. \n
\n

由于您已经知道 1. 和 2. 更复杂,因此我将实现 3.

\n

您的数据

\n
factor <- c(1,2,3,4,5,6,7,8,9,10)\n\nvar_1 <- as.factor(sample(factor, 10000, replace=TRUE, prob=c(0.1,0.1,0.1,0.1,0.1, 0.1,0.1,0.1,0.1,0.1)))\nvar_2 <- as.factor(sample(factor, 10000, replace=TRUE, prob=c(0.1,0.1,0.1,0.1,0.1, 0.1,0.1,0.1,0.1,0.1)))    \nvar_3 <- as.factor(sample(factor, 10000, replace=TRUE, prob=c(0.1,0.1,0.1,0.1,0.1, 0.1,0.1,0.1,0.1,0.1)))    \nvar_4 <- as.factor(sample(factor, 10000, replace=TRUE, prob=c(0.1,0.1,0.1,0.1,0.1, 0.1,0.1,0.1,0.1,0.1)))\nvar_5 <- as.factor(sample(factor, 10000, replace=TRUE, prob=c(0.1,0.1,0.1,0.1,0.1, 0.1,0.1,0.1,0.1,0.1)))\n\nmy_data = data.frame(var_1, var_2, var_3, var_4, var_5)\n\nconditions = data.frame(var_1 = c("1,2", "2"), var_2 = c("1,2,3,4", "1,2,3,8,9"), var_3 = c("4,6", "5,6,7"))\n\nquery_1 <- my_data[Reduce(`&`,\n  Map(`%in%`,\n      lapply(my_data[,1:3], as.character),\n      lapply(conditions, function(z) strsplit(z, ",")[[1]]))),]\n\nquery_2 <- my_data[Reduce(`&`,\n  Map(`%in%`,\n      lapply(my_data[,1:3], as.character),\n      lapply(conditions, function(z) strsplit(z, ",")[[2]]))),]\n# Your code up to here\n
Run Code Online (Sandbox Code Playgroud)\n

随机分配观察值

\n
library(tidyverse)\nl <- list(intersect(query_1, query_2),\n          setdiff(query_1, query_2),\n          setdiff(query_2, query_1)) %>%\n  {\n    map2(split(.[[1]], sample(1:2, nrow(.[[1]]), T)),\n         .[-1],\n         bind_rows)\n  }\n
Run Code Online (Sandbox Code Playgroud)\n

检查结果

\n
map(l, as_tibble) # use tibble for nicer printing\n#> $`1`\n#> # A tibble: 123 \xc3\x97 5\n#>    var_1 var_2 var_3 var_4 var_5\n#>    <fct> <fct> <fct> <fct> <fct>\n#>  1 2     3     6     10    8    \n#>  2 2     3     6     8     4    \n#>  3 2     1     6     1     1    \n#>  4 2     2     6     1     3    \n#>  5 2     1     6     2     1    \n#>  6 2     1     6     10    5    \n#>  7 2     2     6     9     1    \n#>  8 2     2     6     2     2    \n#>  9 2     3     6     6     8    \n#> 10 2     3     6     2     3    \n#> # \xe2\x80\xa6 with 113 more rows\n#> \n#> $`2`\n#> # A tibble: 122 \xc3\x97 5\n#>    var_1 var_2 var_3 var_4 var_5\n#>    <fct> <fct> <fct> <fct> <fct>\n#>  1 2     2     6     1     4    \n#>  2 2     3     6     5     10   \n#>  3 2     2     6     3     6    \n#>  4 2     2     6     2     7    \n#>  5 2     1     6     9     1    \n#>  6 2     3     6     6     4    \n#>  7 2     1     6     7     8    \n#>  8 2     2     6     6     2    \n#>  9 2     1     6     10    3    \n#> 10 2     1     6     7     5    \n#> # \xe2\x80\xa6 with 112 more rows\n\nreduce(l, intersect) # Show frames are disjoint\n#> [1] var_1 var_2 var_3 var_4 var_5\n#> <0 rows> (or 0-length row.names)\nmap_int(l, nrow) # length of frames\n#>   1   2 \n#> 123 122\n\nbind_rows(query_1, query_2) |> # length of joint set -> adds up\n  distinct() |> \n  nrow()\n#> [1] 245\n
Run Code Online (Sandbox Code Playgroud)\n

由reprex 包于 2022 年 4 月 13 日创建(v2.0.1)

\n