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 不会共享任何公共行?
我认为您可以通过三种方式来解决这个问题。
\n由于您已经知道 1. 和 2. 更复杂,因此我将实现 3.
\nfactor <- 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\nRun Code Online (Sandbox Code Playgroud)\nlibrary(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 }\nRun Code Online (Sandbox Code Playgroud)\nmap(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\nRun Code Online (Sandbox Code Playgroud)\n由reprex 包于 2022 年 4 月 13 日创建(v2.0.1)
\n