Sådan styres din randomizer i R

Hvad sker der, når du har brug for en bestemt type randomisering?

Oversigt over tilfældig talgenerering i R

R har mindst 20 tilfældige talgeneratorfunktioner. Hver bruger en bestemt sandsynlighedsfordeling til at oprette numrene. Alle kræver, at du angiver antallet af tilfældige tal, du ønsker (billedet ovenfor viser 200). Alle er tilgængelige i base R - ingen pakker kræves.

Almindelige tilfældige talgeneratorfordelinger er:

  • normal (rnorm): standardgennemsnit på 0 og standardafvigelse på 1
  • binomial (rbinom): ingen standardindstillinger, angiv antallet af forsøg og sandsynligheden for succes på hvert forsøg
  • ensartet (runif): standard minimumværdi på 0 og maksimum værdi på 1

Af de tre ovenfor skaber kun binomial tilfældig talgenerator heltal.

Hvorfor oprette tilfældige tal?

Problemer med tilfældige tal er meget almindelige - der er omkring 50.000 spørgsmål vedrørende tilfældige tal på Stack Exchange.

Men hvorfor bruge dem?

Tilfældige tal har mange praktiske anvendelser. De bruges i Monte Carlo-simuleringer. De bruges i kryptografi. De er blevet brugt til at producere CAPTCHA-indhold. De bruges i spilleautomater. De er også blevet brugt til mere verdslige opgaver såsom at skabe en tilfældig sorteringsrækkefølge for en række bestilte data.

Problemer med tilfældige tal

Almindelige spørgsmål inkluderer “er mine tilfældige tal faktisk tilfældige?” og "hvordan kan jeg generere ikke-gentagne tilfældige tal?"

Bemærk : sidstnævnte mindsker tilfældighed, fordi populationen af ​​mulige tilfældige tal mindskes med en hver gang et tilfældigt tal trækkes. Metoden er passende i situationer som lotterier eller bingo, hvor hver billet eller bold kun kan trækkes en gang.

Dette problem medfører et andet problem! Den tilfældigt genererede prøveudtagning uden erstatningsnumre skal være heltal. Ingen har billet 5.6932 eller bingo bold 0.18967.

Et praktisk eksempel på tilfældige talproblemer

Lad os tage eksemplet med, at jeg har 20 kvindelige studerende i samme alder. Jeg har fire undervisningsmetoder, som jeg vil prøve. Jeg vil kun prøve en undervisningsmetode for hver elev. Let matematik - Jeg har brug for fem studerende i hver gruppe.

Men hvordan gør jeg det, så hver elev tildeles tilfældigt?

Og hvordan kan jeg sørge for, at jeg kun får produceret heltal?

Og hvordan gør jeg alt dette, mens jeg bruger tilfældigt genererede tal uden udskiftning? Jeg vil for eksempel ikke have seks studerende i en gruppe og fire studerende i en anden.

Først skal jeg oprette nogle dummy-data i R. Lad os oprette den liste over kvindelige studerende.

FemaleStudents <- data.frame(Names=c("Alice", "Betty", "Carol", "Denise", "Erica", "Frances", "Gina", "Helen", "Iris", "Julie", "Katherine", "Lisa", "Michelle", "Ngaire", "Olivia", "Penelope", "Rachel", "Sarah", "Trudy", "Uma"))

Nu har vi et endimensionelt datasæt med vores 20 studerende.

Vi ved, at runif()funktionen ikke opretter heltal. Hvorfor afrunder vi ikke tilfældige tal, så vi kun får heltal og bruger denne funktion? Vi kan pakke tilfældigt tal ind i en afrundingsfunktion.

Spørgsmål 1: hvorfor bruger jeg den tilfældige ensartede fordeling og ikke en anden, såsom den tilfældige normalfordeling?

Der er fem typer afrundingsfunktioner i R. Vi vil bruge round().

For at vi får de samme resultater, sætter jeg et frø til tilfældig talgenerering. Hver gang vi genererer tilfældige tal, bruger vi det samme frø. Jeg har valgt 5 som frø. Hvis du ikke sætter et frø, eller hvis du sætter et andet frø end 5, vil dine resultater være anderledes end mine.

set.seed(5)FemaleStudents$Group <- round(runif(20, 1, 5))

Nå, det syntes at fungere. Vi har hver elev tildelt en gruppe nummereret mellem 1 og 5.

Lad os dobbelttjekke vores fordeling.

table(FemaleStudents$Group)
1 2 3 4 5 2 6 5 4 3

Darn. Kun en af ​​de fem grupper har det rigtige antal studerende (gruppe 4). Hvorfor skete dette?

Vi kan kontrollere de numre, der faktisk sendes runif()uden at afrunde, og lade output udskrive til konsollen. Her udskrives output, fordi jeg ikke har tildelt funktionen til et objekt (for eksempel til en data.frame-variabel).

set.seed(5)runif(20,1,5)
[1] 1.800858 3.740874 4.667503 2.137598 1.418601 3.804230 3.111840 4.231741 4.826001 1.441812 2.093140 2.962053 2.273616 3.236691 2.050373[16] 1.807501 2.550103 4.551479 3.219690 4.368718

As we can see, the rounding caused our problem. But if we hadn’t rounded, each student would have been assigned to a different group.

What do we do?

sample()

sample() is now one of my favourite functions in R. Let’s see how it works.

Randomly allocate to equally sized groups (counts matter)

How can we use it to randomly assign our 20 students to four equally sized groups?

What happens if we try sample() normally?

set.seed(5)FemaleStudents$Sample <- sample(1:5, nrow(FemaleStudents), replace=TRUE)

Question 2: what output did you get when you used table(FemaleStudents$Sample)?

We can fix this problem by creating a vector of group numbers, and then using sampling without replacement from this vector. The rep command is used to create a range of repeated values. You can use it to repeat each number in the series, as I have used here. Number 1 is repeated four times, then number 2 is repeated four times, and so forth. You can also use it to repeat a sequence of numbers, if you use this code instead: rep(1:5,4)

OurGroups <- rep(1:5, each=4)set.seed(5)FemaleStudents$Sample <- sample(OurGroups, nrow(FemaleStudents), replace=FALSE)

We used our vector of numbers (OurGroups) to allocate our students to groups. We used sampling without replacement (replace=FALSE) from OurGroups because we need to use each value in that vector. We need to remove each value as we use it.

And we get the result we wanted!

table(FemaleStudents$Sample)
1 2 3 4 5 4 4 4 4 4

Question 3: why did I still set a seed?

Another advantage of sample() is that it doesn’t care about type. We can repeat the allocation using a vector of strings. This can be useful if you don’t want to keep referring back to what “1” means.

OurNamedGroups <- rep(c("Up", "Down", "Charmed", "Strange", "Top"), each=4)set.seed(5)FemaleStudents$Sample2 <- sample(OurNamedGroups, nrow(FemaleStudents), replace=FALSE)table(FemaleStudents$Sample2)
Charmed Down Strange Top Up 4 4 4 4 4

Because we used the same seed, we can see that the same student allocation was performed, irrespective of whether we used numeric or character data for the assignment.

table(FemaleStudents$Sample,FemaleStudents$Sample2) Charmed Down Strange Top Up 1 0 0 0 0 4 2 0 4 0 0 0 3 4 0 0 0 0 4 0 0 4 0 0 5 0 0 0 4 0

Randomly allocate when group size is not restricted

Sometimes we want to randomly allocate to groups, but we don’t have a vector of groups. We are still only allocating each unit (person, sheep, block of cheese) to a single group, and we use completely random allocation.

Let’s say that our school has a new, special library room. It’s been constructed to be soundproof to give students a better studying environment. The chief librarian would like to know about the experiences of students in that room. The only problem is that the room is limited in size. The chief librarian thinks that around four students is a large enough group to provide the initial feedback.

Again, we can use sample() to pick our student groups. In this case, we have “students who will test the room” and “students who won’t test the room”. I’m going to call them “Test” and “Not test”. These labels have been chosen for being 1. short and 2. easily distinguished.

Because we did sampling without replacement earlier, we didn’t specify probabilities of assignment to groups — we simply pulled out an assignment from a vector. Now we are going to use sampling with replacement. With replacement refers to the group, not to the students.

We need to sample with replacement as we only have two groups (“Test”, “Not test”) and 20 students. If we tried to sample without replacement, our code would error.

Our code is very similar:

set.seed(5)FemaleStudents$Library <- sample(c("Test", "Not test"), nrow(FemaleStudents), replace=TRUE, prob=c(4/20,16/20))table(FemaleStudents$Library)
Not test Test 15 5

As you can see, we allocated five students to test the room, not four. This type of result is expected when dealing with small samples. However, our allocation of students is completely random. Each student had exactly the same probability of being assigned to test the room. Whether previous students were testers or not had no impact on the allocation of the next student.

Let’s walk through some of that code.

I’ve constructed a new variable in the data.frame to collect the allocation (Library).

Instead of dealing with numbers for group names, I’ve used the strings I mentioned earlier. Because I’ve used strings, the c() must wrap the group names (“Test”, “Not test”) and each group name is separated by a comma.

Replacement has been set to TRUE.

The probability of assignment to either group must be provided. This is the prob=c(4/20,16/20) part of the sample() function. Again, note how c() is used to contain the probabilities. Also of interest is that the probabilities can be expressed as fractions, rather than decimals.

Hooray for sample()

Jeg bruger sample()hele tiden til det arbejde, jeg laver. Evnen til at bruge strenge såvel som at begrænse numerisk output til heltal (og definere det ønskede heltalsområde) giver mig mere kontrol end at prøve at bruge en af ​​tilfældige talfunktioner.

Svar

Svar 1 : Jeg brugte en tilfældig ensartet fordeling, fordi jeg ønskede, at hver værdi skulle være lige sandsynlig.

Svar 2 : Jeg fik denne output:

1 2 3 4 5 2 7 4 2 5

Svar 3: Hvis vi ikke indstiller en frøværdi, eller hvis vi bruger en anden, vil fordelingen af ​​specifikke studerende være forskellig. For eksempel, når frøet er 5, tildeles Alice til gruppe 2. Hvis frøet er 7, tildeles Alice til gruppe 5. Replikering er vigtig, når koden skal køres igen (for eksempel i test).