R - 在循环中使用 'Which' 条件提取随机样本
R - Extract random sample with Conditional using 'Which' in Loop
我有一个 data.frame 看起来像这样:
Patch, Xmeters, Ymeters, Genome
2, 6050, 3954.850, 4 2 0 2 1 0 0 0 2 1 2 1 1 0 2 2 2 0 1 0
2, 5900, 6293.118, 4 0 2 0 1 0 0 0 0 0 0 3 0 4 2 0 1 1 1 2
1, 4550, 4301.260, 3 3 1 3 0 1 0 0 0 0 0 3 2 2 0 0 0 0 1 2
2, 6150, 2396.004, 0 0 1 2 2 1 0 0 0 0 2 4 0 3 2 0 0 0 0 1
1, 4400, 4907.477, 2 4 1 4 0 0 0 1 2 2 0 4 1 1 2 2 2 0 1 2
3, 8550, 6033.310, 3 1 2 1 0 2 0 0 0 0 0 4 2 4 0 2 0 0 0 2
"Patch" 包含值 1:6。 1:6 包含不相等的行数。
我的目标是从每个 Patch 中随机抽取 25 行并编译到一个新的数据框中;一个有 150 行的数据框,6 个补丁中的每一个有 25 行。
我正在构建 this post 以使用 'sample' 和 'which' 提取具有条件的随机行样本。
sample = NULL
subset = NULL
for (patch in c(1:6))
{sample <- H0_LONG[ sample( which( H0_LONG$Patch == "[", patch, "]"), 25, replace = FALSE), ]
subset<- rbind(subset, sample)
rm(sample)
}
我是 for-loop 用户的新手,但我正在尝试完成这项工作,因为我需要对数百个数据帧进行采样(阅读,欢迎提供更优雅的建议。)如果我输入一个'which' 函数中的整数,它工作正常,而 'rbind' 函数似乎工作正常 - 所以我假设我执行的 for 循环有问题。
dplyr package 中的 group_by
和 sample_n
函数让您轻松做到这一点:
library(dplyr)
subset <- H0_LONG %>%
group_by(Patch) %>%
sample_n(25)
这种方法通常 运行 比 for 循环更快。注意这段代码只是另一种写法:
subset <- sample_n(group_by(H0_LONG, Patch), 25)
由于您没有提供完整数据,我在这里综合了自己的数据:
set.seed(1);
counts <- 25:30;
H0_LONG <- data.frame(Patch=sample(rep(1:6,sample(counts))),Xmeters=4000L+sample(1:80,sum(counts),replace=T)*50L,Ymeters=runif(sum(counts),2000,7000),Genome=replicate(sum(counts),paste0(c(' ',' '),sample(0:4,20,replace=T),collapse='')),stringsAsFactors=F);
head(H0_LONG);
## Patch Xmeters Ymeters Genome
## 1 6 7400 4212.962 3 3 3 2 4 2 4 3 2 4 2 0 3 3 0 3 2 1 3 4
## 2 4 7450 2783.571 3 1 0 1 4 4 3 4 4 3 0 1 1 0 0 1 1 0 3 1
## 3 4 5600 4911.026 4 3 1 0 0 4 1 2 3 4 2 0 4 3 1 0 0 4 4 3
## 4 1 5550 6850.811 0 1 3 4 3 1 3 1 4 0 2 1 0 4 2 3 2 4 3 1
## 5 2 7600 6947.499 4 3 0 2 2 0 2 4 3 2 1 3 3 4 3 2 2 1 2 4
## 6 2 6600 2882.260 4 0 3 4 4 1 1 4 0 4 1 2 2 3 2 0 1 3 0 4
nrow(H0_LONG);
## [1] 165
table(H0_LONG$Patch);
##
## 1 2 3 4 5 6
## 26 30 27 28 25 29
对于基础 R 解决方案,您可以使用 by()
进行分组:
res <- do.call(rbind,by(H0_LONG,H0_LONG$Patch,function(g) g[sample(seq_len(nrow(g)),min(nrow(g),25)),]));
head(res);
## Patch Xmeters Ymeters Genome
## 1.134 1 5550 5451.284 0 4 3 0 0 0 2 3 4 4 0 0 1 3 3 3 0 2 3 1
## 1.112 1 7550 6712.527 3 0 2 0 4 0 3 4 3 1 3 0 0 0 1 2 3 1 0 2
## 1.96 1 4300 2362.303 0 4 3 0 2 0 3 3 0 4 4 2 3 2 1 3 3 4 3 0
## 1.137 1 7300 5562.701 3 0 1 3 4 0 3 3 4 4 0 1 4 1 2 2 2 4 2 2
## 1.4 1 5550 6850.811 0 1 3 4 3 1 3 1 4 0 2 1 0 4 2 3 2 4 3 1
## 1.86 1 5000 4573.663 4 0 2 4 2 2 1 2 0 3 4 0 2 0 3 2 1 3 1 2
nrow(res);
## [1] 150
table(res$Patch);
##
## 1 2 3 4 5 6
## 25 25 25 25 25 25
对于选择的数量,我使用 min(nrow(g),25)
而不是 25
来处理输入 data.frame 中少于 25 行的补丁,如果这样的补丁曾经存在的话。
我还建议查看 data.table
:
library(data.table);
H0_LONG_dt <- as.data.table(H0_LONG);
H0_LONG_dt;
## Patch Xmeters Ymeters Genome
## 1: 6 7400 4212.962 3 3 3 2 4 2 4 3 2 4 2 0 3 3 0 3 2 1 3 4
## 2: 4 7450 2783.571 3 1 0 1 4 4 3 4 4 3 0 1 1 0 0 1 1 0 3 1
## 3: 4 5600 4911.026 4 3 1 0 0 4 1 2 3 4 2 0 4 3 1 0 0 4 4 3
## 4: 1 5550 6850.811 0 1 3 4 3 1 3 1 4 0 2 1 0 4 2 3 2 4 3 1
## 5: 2 7600 6947.499 4 3 0 2 2 0 2 4 3 2 1 3 3 4 3 2 2 1 2 4
## ---
## 161: 6 5200 4170.154 2 4 4 3 2 3 0 0 4 0 3 0 1 1 1 1 0 3 2 2
## 162: 1 5600 4585.049 4 1 3 4 1 0 3 2 0 4 3 4 4 2 4 1 0 2 1 1
## 163: 2 7250 6231.229 1 1 0 0 4 2 0 2 2 1 2 0 2 0 2 1 4 4 1 1
## 164: 3 4350 2275.821 4 1 4 4 4 0 0 2 1 3 2 1 0 4 0 3 4 2 0 0
## 165: 5 5500 4770.885 1 3 3 1 2 0 0 2 4 3 3 2 0 4 1 0 4 3 4 1
res2 <- H0_LONG_dt[,.SD[sample(seq_len(.N),min(.N,25))],Patch];
res2;
## Patch Xmeters Ymeters Genome
## 1: 6 5500 2715.833 0 1 1 1 1 1 1 4 3 0 3 2 1 0 0 1 1 1 4 4
## 2: 6 7250 6695.684 2 3 1 2 3 4 0 1 0 4 0 0 3 4 2 1 1 3 1 2
## 3: 6 6900 3109.069 3 1 3 1 1 2 4 0 1 1 1 3 4 3 3 0 4 3 4 0
## 4: 6 7850 6892.770 2 1 3 4 1 2 1 0 3 2 1 0 3 4 0 3 0 1 3 1
## 5: 6 7850 2113.706 3 0 0 0 1 4 1 1 4 4 4 0 2 4 0 4 2 1 2 3
## ---
## 146: 5 4700 6678.562 3 1 3 0 4 4 0 0 1 1 3 2 1 1 2 0 2 1 0 0
## 147: 5 4250 6008.439 1 4 0 0 3 0 2 0 3 1 1 4 0 2 4 1 4 0 1 2
## 148: 5 8000 6387.890 0 1 3 1 4 4 0 3 0 1 3 2 1 2 3 0 4 1 4 0
## 149: 5 4550 5738.175 4 2 0 0 3 0 0 3 2 2 0 1 3 0 1 0 3 4 1 1
## 150: 5 5950 6113.967 4 2 1 3 3 2 1 2 0 1 0 4 2 1 1 3 2 2 3 4
table(res2[,Patch]);
##
## 1 2 3 4 5 6
## 25 25 25 25 25 25
我有一个 data.frame 看起来像这样:
Patch, Xmeters, Ymeters, Genome
2, 6050, 3954.850, 4 2 0 2 1 0 0 0 2 1 2 1 1 0 2 2 2 0 1 0
2, 5900, 6293.118, 4 0 2 0 1 0 0 0 0 0 0 3 0 4 2 0 1 1 1 2
1, 4550, 4301.260, 3 3 1 3 0 1 0 0 0 0 0 3 2 2 0 0 0 0 1 2
2, 6150, 2396.004, 0 0 1 2 2 1 0 0 0 0 2 4 0 3 2 0 0 0 0 1
1, 4400, 4907.477, 2 4 1 4 0 0 0 1 2 2 0 4 1 1 2 2 2 0 1 2
3, 8550, 6033.310, 3 1 2 1 0 2 0 0 0 0 0 4 2 4 0 2 0 0 0 2
"Patch" 包含值 1:6。 1:6 包含不相等的行数。
我的目标是从每个 Patch 中随机抽取 25 行并编译到一个新的数据框中;一个有 150 行的数据框,6 个补丁中的每一个有 25 行。
我正在构建 this post 以使用 'sample' 和 'which' 提取具有条件的随机行样本。
sample = NULL
subset = NULL
for (patch in c(1:6))
{sample <- H0_LONG[ sample( which( H0_LONG$Patch == "[", patch, "]"), 25, replace = FALSE), ]
subset<- rbind(subset, sample)
rm(sample)
}
我是 for-loop 用户的新手,但我正在尝试完成这项工作,因为我需要对数百个数据帧进行采样(阅读,欢迎提供更优雅的建议。)如果我输入一个'which' 函数中的整数,它工作正常,而 'rbind' 函数似乎工作正常 - 所以我假设我执行的 for 循环有问题。
dplyr package 中的 group_by
和 sample_n
函数让您轻松做到这一点:
library(dplyr)
subset <- H0_LONG %>%
group_by(Patch) %>%
sample_n(25)
这种方法通常 运行 比 for 循环更快。注意这段代码只是另一种写法:
subset <- sample_n(group_by(H0_LONG, Patch), 25)
由于您没有提供完整数据,我在这里综合了自己的数据:
set.seed(1);
counts <- 25:30;
H0_LONG <- data.frame(Patch=sample(rep(1:6,sample(counts))),Xmeters=4000L+sample(1:80,sum(counts),replace=T)*50L,Ymeters=runif(sum(counts),2000,7000),Genome=replicate(sum(counts),paste0(c(' ',' '),sample(0:4,20,replace=T),collapse='')),stringsAsFactors=F);
head(H0_LONG);
## Patch Xmeters Ymeters Genome
## 1 6 7400 4212.962 3 3 3 2 4 2 4 3 2 4 2 0 3 3 0 3 2 1 3 4
## 2 4 7450 2783.571 3 1 0 1 4 4 3 4 4 3 0 1 1 0 0 1 1 0 3 1
## 3 4 5600 4911.026 4 3 1 0 0 4 1 2 3 4 2 0 4 3 1 0 0 4 4 3
## 4 1 5550 6850.811 0 1 3 4 3 1 3 1 4 0 2 1 0 4 2 3 2 4 3 1
## 5 2 7600 6947.499 4 3 0 2 2 0 2 4 3 2 1 3 3 4 3 2 2 1 2 4
## 6 2 6600 2882.260 4 0 3 4 4 1 1 4 0 4 1 2 2 3 2 0 1 3 0 4
nrow(H0_LONG);
## [1] 165
table(H0_LONG$Patch);
##
## 1 2 3 4 5 6
## 26 30 27 28 25 29
对于基础 R 解决方案,您可以使用 by()
进行分组:
res <- do.call(rbind,by(H0_LONG,H0_LONG$Patch,function(g) g[sample(seq_len(nrow(g)),min(nrow(g),25)),]));
head(res);
## Patch Xmeters Ymeters Genome
## 1.134 1 5550 5451.284 0 4 3 0 0 0 2 3 4 4 0 0 1 3 3 3 0 2 3 1
## 1.112 1 7550 6712.527 3 0 2 0 4 0 3 4 3 1 3 0 0 0 1 2 3 1 0 2
## 1.96 1 4300 2362.303 0 4 3 0 2 0 3 3 0 4 4 2 3 2 1 3 3 4 3 0
## 1.137 1 7300 5562.701 3 0 1 3 4 0 3 3 4 4 0 1 4 1 2 2 2 4 2 2
## 1.4 1 5550 6850.811 0 1 3 4 3 1 3 1 4 0 2 1 0 4 2 3 2 4 3 1
## 1.86 1 5000 4573.663 4 0 2 4 2 2 1 2 0 3 4 0 2 0 3 2 1 3 1 2
nrow(res);
## [1] 150
table(res$Patch);
##
## 1 2 3 4 5 6
## 25 25 25 25 25 25
对于选择的数量,我使用 min(nrow(g),25)
而不是 25
来处理输入 data.frame 中少于 25 行的补丁,如果这样的补丁曾经存在的话。
我还建议查看 data.table
:
library(data.table);
H0_LONG_dt <- as.data.table(H0_LONG);
H0_LONG_dt;
## Patch Xmeters Ymeters Genome
## 1: 6 7400 4212.962 3 3 3 2 4 2 4 3 2 4 2 0 3 3 0 3 2 1 3 4
## 2: 4 7450 2783.571 3 1 0 1 4 4 3 4 4 3 0 1 1 0 0 1 1 0 3 1
## 3: 4 5600 4911.026 4 3 1 0 0 4 1 2 3 4 2 0 4 3 1 0 0 4 4 3
## 4: 1 5550 6850.811 0 1 3 4 3 1 3 1 4 0 2 1 0 4 2 3 2 4 3 1
## 5: 2 7600 6947.499 4 3 0 2 2 0 2 4 3 2 1 3 3 4 3 2 2 1 2 4
## ---
## 161: 6 5200 4170.154 2 4 4 3 2 3 0 0 4 0 3 0 1 1 1 1 0 3 2 2
## 162: 1 5600 4585.049 4 1 3 4 1 0 3 2 0 4 3 4 4 2 4 1 0 2 1 1
## 163: 2 7250 6231.229 1 1 0 0 4 2 0 2 2 1 2 0 2 0 2 1 4 4 1 1
## 164: 3 4350 2275.821 4 1 4 4 4 0 0 2 1 3 2 1 0 4 0 3 4 2 0 0
## 165: 5 5500 4770.885 1 3 3 1 2 0 0 2 4 3 3 2 0 4 1 0 4 3 4 1
res2 <- H0_LONG_dt[,.SD[sample(seq_len(.N),min(.N,25))],Patch];
res2;
## Patch Xmeters Ymeters Genome
## 1: 6 5500 2715.833 0 1 1 1 1 1 1 4 3 0 3 2 1 0 0 1 1 1 4 4
## 2: 6 7250 6695.684 2 3 1 2 3 4 0 1 0 4 0 0 3 4 2 1 1 3 1 2
## 3: 6 6900 3109.069 3 1 3 1 1 2 4 0 1 1 1 3 4 3 3 0 4 3 4 0
## 4: 6 7850 6892.770 2 1 3 4 1 2 1 0 3 2 1 0 3 4 0 3 0 1 3 1
## 5: 6 7850 2113.706 3 0 0 0 1 4 1 1 4 4 4 0 2 4 0 4 2 1 2 3
## ---
## 146: 5 4700 6678.562 3 1 3 0 4 4 0 0 1 1 3 2 1 1 2 0 2 1 0 0
## 147: 5 4250 6008.439 1 4 0 0 3 0 2 0 3 1 1 4 0 2 4 1 4 0 1 2
## 148: 5 8000 6387.890 0 1 3 1 4 4 0 3 0 1 3 2 1 2 3 0 4 1 4 0
## 149: 5 4550 5738.175 4 2 0 0 3 0 0 3 2 2 0 1 3 0 1 0 3 4 1 1
## 150: 5 5950 6113.967 4 2 1 3 3 2 1 2 0 1 0 4 2 1 1 3 2 2 3 4
table(res2[,Patch]);
##
## 1 2 3 4 5 6
## 25 25 25 25 25 25