Мне нужно создать образец из моего фрейма данных, и для этого я использую приведенный ниже код.
name <- sample(c("Adam","John","Henry","Mike"),100,rep = TRUE)
area <- sample(c("run","develop","test"),100,rep = TRUE)
id <- sample(100:200,100,rep = FALSE)
mydata <- as.data.frame(cbind(id,area,name))
qcsample <- mydata %>%
group_by(area) %>%
nest() %>%
mutate(n = c(20, 15, 15)) %>%
mutate(samp = map2(data, n, sample_n)) %>%
select(area, samp) %>%
unnest()
Теперь я получаю эти результаты.
table(qcsample$area)
develop run test
15 15 20
-
table(qcsample$name)
Adam Henry John Mike
9 9 16 16
Я хотел бы создать образец, который имел бы более или менее одинаковое количество образцов для каждого имени, например. Адам - 12, Генри - 12, Джон - 13, Майк - 13. Как я могу этого добиться? Могу я как-нибудь попросить, чтобы образец был распределен поровну?
Также в этом примере я использовал функцию
sample_n
и указанное количество образцов.
Я ожидаю, что иногда не будет необходимого номера из данной группы. В моем примере я беру 20 образцов из области, называемой «тест», но иногда бывает только, скажем, 10 строк, содержащих «тест». Общее количество - 50, поэтому мне нужно убедиться, что если есть только 10 «test», код должен автоматически увеличивать остальные, поэтому образец будет «test» - 10, «run» - 20 и «develop» - 20. Это может произойти с любой областью, поэтому мне нужно проверить, достаточно ли строк для создания образца и увеличения других областей. Если есть только 1, его можно добавить к любой из оставшихся областей, или если разница составляет 3, мы добавляем 1 к одной области и 2 к другой.
Как это проверить, учитывая все возможности? Я считаю, что в этом случае есть восемь перестановок.
Заранее спасибо А.
Спасибо, я заранее исправил цифры ... Я опубликую свое решение в отдельной ветке в поисках более элегантной версии, так как мое решение немного запутано.





Если вы используете выдуманные данные, вы можете создать минимальное количество каждой строки, а затем создать заполнитель, чтобы получить общее количество:
set.seed(42)
names <- c("Adam", "John", "Henry", "Mike")
areas <- c("run", "develop", "test")
totalrows <- 100
minname <- 22 # No less than 20 of each name (set to near threshold to test)
minarea <- 30 # No less than 30 of each area (less randomness the higher these are)
qcsample <- data.frame(
name=sample(c(rep(names, minname), sample(names, totalrows-length(names)*minname, replace=T))),
area=sample(c(rep(areas, minarea), sample(areas, totalrows-length(areas)*minarea, replace=T))),
id=sample(99+(1:totalrows))
)
Это приводит к:
R> table(qcsample$name)
Adam Henry John Mike
23 28 24 25
R> table(qcsample$area)
develop run test
37 31 32
Обратите внимание, что количество от name до area не ограничено:
R> table(qcsample[,-3])
area
name develop run test
Adam 5 11 7
Henry 11 8 9
John 10 7 7
Mike 11 5 9
R>
Используя цикл, предложенный @ r2evans:
library(dplyr)
set.seed(42)
mydata <- data.frame(
name = sample(c("Adam","John","Henry","Mike"), 100, rep = TRUE),
area = sample(c("run","develop","test"), 100, rep = TRUE),
id = sample(100:200, 100, rep = FALSE)
)
Nsamples <- 50
mysample <- data.frame(sample_n(mydata, Nsamples))
minname <- 11 # max is 50/4 -> 12
minarea <- 15 # max is 50/3 -> 16
# the test you were asking about
while( (min(table(mysample$name)) < minname) || (min(table(mysample$area)) < minarea) ) {
mysample <- data.frame(sample_n(mydata, Nsamples))
}
Это приводит к:
R> table(mysample$name)
Adam Henry John Mike
13 15 11 11
R> table(mysample$area)
develop run test
15 17 18
И, как и раньше, у области нет минимума имени.
R> table(mysample[-3])
area
name develop run test
Adam 4 3 6
Henry 2 6 7
John 4 4 3
Mike 5 4 2
Если вам нужно установить минимальное количество для каждой перестановки, добавьте это в тест:
while(... || (min(table(mysample[-3])) < some_min)) {
Кстати, количество перестановок, как вы можете видеть из таблицы, - это количество имен, умноженное на количество областей.
Спасибо. На самом деле я использую реальные данные, и приведенный пример просто объясняет, чего я пытаюсь достичь. Главное, чтобы образец имел необходимый размер, всего 50. Затем поддерживайте процентное значение 50, тестируйте 40%, запускайте 30% и развивайте 30%, что дает соответственно 20,15,15. Если для любого из них недостаточно данных, я должен увеличить (более или менее равномерно) другие области, чтобы их общее количество составляло 50. Все образцы должны быть уникальными, поэтому я не могу их заменить. Thnaks
Я этого боялся. Я сделал одно решение, в котором отбиралось минимальное количество для каждой категории, а затем выполнялось отборочное заполнение остальных или удаление строк по мере необходимости, но это было слишком некрасиво для публикации. Вероятно, ЛЮБОЕ другое решение, которое кто-то придумал, было более элегантным, чем мое. :) @ r2evans "Зацикливание, пока не получите нужные пропорции", вероятно, лучший вариант.
Спасибо. Знаете ли вы, как создать оператор if для установки счетчика? скажем, я сначала проверю, равен ли размер первой области 50. Если это 40, я бы установил свой первый счетчик на 40 и протестировал другие. Если второй и третий больше 50, я бы сказал, установите 50 + 5 для каждого из них. От первого осталось 10, поэтому я разделил его на 2. Если число нечетное, скажем 9, мне нужно будет разделить его на 4 и 5. Я хочу сделать общее число 150. Мне нужно будет проверить все возможности по трем направлениям. Тогда я мог бы получить от них процентную выборку. Большое спасибо !
Отредактируйте исходный ответ, чтобы включить такой тест.
Ну, я думаю, короткий ответ - «нет, я не знаю, как проводить такой тест», но я не думаю, что это выход.
Кроме того, возможно, что с другим семенем вы не сможете достичь минимума. Вероятно, вам следует убедиться, что это возможно, прежде чем запускать цикл while!
Большое спасибо! Как только у меня появится больше времени на работе, я протестирую его на реальных данных и расскажу, как у меня дела. Очень признателен! :)
Привет, наконец-то у меня появилось время реализовать код для моих данных и запустить несколько тестов ... единственное условие для цикла while, которое я установил для (min (table (mysample [-3])) <1) ... цикл никогда не останавливается :( он работает вечно ... мой набор данных больше, чем в примере, но даже в установленном примере цикл while никогда не останавливается ...
Вот еще одна мысль.
В зависимости от желаемого конечного размера, он может создать избыточное количество выборок, чтобы уменьшить некоторые пары имя / область, чтобы уменьшить общее количество.
Допустим, вы хотите получить в итоге 50 строк:
final_size <- 50
Для полноты картины, вот наборы, из которых мы выберем:
avail_names <- c("Adam", "John", "Henry", "Mike")
avail_areas <- c("run", "develop", "test")
и минимум, который нам нужно создать для Adam,run (и т. д.), чтобы в конечно осталось не менее final_size строк:
size_per_namearea <- ceiling(final_size / (length(avail_names) * length(avail_areas)))
Хорошо, сгенерируйте как минимум столько (вероятно, больше, чем) количество строк, которые нам нужны:
set.seed(20180920)
qcsample <- crossing(data_frame(rownum = seq_len(size_per_namearea)),
data_frame(name = avail_names),
data_frame(area = avail_areas)) %>%
group_by(name, area) %>%
mutate(id = sample(100, size = n(), replace = FALSE))
qcsample
# # A tibble: 60 x 4
# # Groups: name, area [12]
# rownum name area id
# <int> <chr> <chr> <int>
# 1 1 Adam run 59
# 2 1 Adam develop 51
# 3 1 Adam test 23
# 4 1 John run 71
# 5 1 John develop 5
# 6 1 John test 24
# 7 1 Henry run 4
# 8 1 Henry develop 29
# 9 1 Henry test 79
# 10 1 Mike run 77
# # ... with 50 more rows
Убедитесь, что у нас одинаковые размеры выборки для каждого имени / области:
xtabs(~ name + area, data = qcsample) %>%
stats::addmargins()
# area
# name develop run test Sum
# Adam 5 5 5 15
# Henry 5 5 5 15
# John 5 5 5 15
# Mike 5 5 5 15
# Sum 20 20 20 60
Если мы просто сделаем head(final_size), то мы будем знать, имена которых мы будем сокращать, что немного подрывает случайность вашей выборки. Причина, по которой я добавил rownum заранее, заключалась в том, чтобы я мог организовать с помощью него плюс джиттер, гарантируя, что я получу весь max(rownum)-1, а затем некоторую выборку max(rownum), гарантия, чтобы каждая пара имя / область имела строки max(rownum)-1 или max(rownum); ваши результаты никогда не отличаются более чем на 1.
reducedsample <- arrange(qcsample, rownum + runif (n())) %>%
head(final_size) %>%
select(-rownum)
reducedsample %>%
xtabs(~ name + area, data = .) %>%
stats::addmargins()
# area
# name develop run test Sum
# Adam 4 4 5 13
# Henry 5 4 4 13
# John 4 4 4 12
# Mike 4 4 4 12
# Sum 17 16 17 50
Чтобы обеспечить почти равные пропорции (т.е. намеренно уменьшить случайность), вам нужно либо (а) выполнить повторную выборку (неизвестное количество раз), пока не получите приемлемые пропорции; или (б) заранее зафиксируйте свои пропорции и просто выберите порядок этих имен. Вы не можете действительно "запросить", чтобы случайный выбор был менее случайным :-)