Watts-College / paf-514-template

https://watts-college.github.io/paf-514-template/
1 stars 0 forks source link

Lab 2 Knitting Error #36

Closed jacobmorgan05 closed 2 weeks ago

jacobmorgan05 commented 7 months ago

Hi Jesse, I believe I have the correct, code, everything works in the markdown file, however when I try to knit the document I get this error:

**Quitting from lines 119-217 [unnamed-chunk-4] (Lab-2-Morgan-PAF-514.Rmd) Error in open_goat_door(): ! could not find function "open_goat_door" Backtrace:

  1. global play_game()

Execution halted**

My gut feeling was that there was a problem with the scope, but I may be wrong on that. I've done my best to find a fix online but I can't quite figure out the problem. I was hoping you could take a look at the code and see if anything pops out as a problem that could be causing the knit to not work.

Simulation Set-Up:

play_game <- function()
{

#Step 1
create_game <- function( )
{
    a.game <- sample( x=c("goat","goat","car"), size=3, replace=F )
    return( a.game )
} 

#Step 2
select_door <- function( )
{
  doors <- c(1,2,3) 
  a.pick <- sample( doors, size=1 )
  return( a.pick )  # number between 1 and 3
}

#Step 3
open_goat_door <- function( game, a.pick )
{
   doors <- c(1,2,3)
   # if contestant selected car,
   # randomly select one of two goats 
   if( game[ a.pick ] == "car" )
   { 
     goat.doors <- doors[ game != "car" ] 
     opened.door <- sample( goat.doors, size=1 )
   }
   if( game[ a.pick ] == "goat" )
   { 
     opened.door <- doors[ game != "car" & doors != a.pick ] 
   }
   return( opened.door ) # number between 1 and 3
}

#Step 4
change_door <- function( stay=T, opened.door, a.pick )
{
   doors <- c(1,2,3) 

   if( stay )
   {
     final.pick <- a.pick
   }
   if( ! stay )
   {
     final.pick <- doors[ doors != opened.door & doors != a.pick ] 
   }

   return( final.pick )  # number between 1 and 3
}

#Step 5
determine_winner <- function( final.pick, game )
{
   if( game[ final.pick ] == "car" )
   {
      return( "WIN" )
   }
   if( game[ final.pick ] == "goat" )
   {
      return( "LOSE" )
   }
}
new.game <- create_game()
  first.pick <- select_door()
  opened.door <- open_goat_door( new.game, first.pick )
  final.pick.stay <- change_door( stay=T, opened.door, first.pick )
  final.pick.switch <- change_door( stay=F, opened.door, first.pick )
  outcome.stay <- determine_winner( final.pick.stay, new.game  )
  outcome.switch <- determine_winner( final.pick.switch, new.game )

  # game.results <- bundle the results
  # return( <<< game.results >>> )

  strategy <- c("stay","switch")
  outcome <- c(outcome.stay,outcome.switch)
  game.results <- data.frame( strategy, outcome,
                              stringsAsFactors=F )
  return( game.results )
}

Simulation setup

results.df <- NULL #collector

for( i in 1:10000 ) #iterator
{
  game.outcome <- play_game()
  #binding step
  results.df <- rbind( results.df, game.outcome)
}
table( results.df )  %>%
  prop.table( margin=1 ) %>%
  round( 2 )

Part 1

play_game <- function()
{
build_doors <- function( n=5 ){ return( 1:n ) }

create_game <- function( )
{
    a.game <- sample( x=rep( c("goat","car"), c(3,2) ), size=5, replace=F )
    return( a.game )
}

select_door <- function( )
{
  doors <- build_doors() 
  a.pick <- sample( doors, size=1 )
  return( a.pick )  # number between 1 and 5
}

open_doors <- function( game, a.pick )
{
   # reveal one car and one goat

   doors <- build_doors()

   if( game[ a.pick ] == "car" )
   { 
     opened.car.door <- doors[ game == "car" & doors != a.pick ]
     goat.doors <- doors[ game != "car" ] 
     opened.goat.door <- sample( goat.doors, size=1 )
     opened.doors <- c( opened.car.door, opened.goat.door )
   }

   if( game[ a.pick ] == "goat" )
   { 
     opened.car.door <- sample( doors[game=="car"], size=1 )
     available.goat.doors <- doors[ game != "car" & doors != a.pick ] 
     opened.goat.door <- sample( available.goat.doors, size=1 )
     opened.doors <- c( opened.car.door, opened.goat.door )
   }
   return( opened.doors ) # two numbers
}

change_door <- function( stay=T, opened.doors, a.pick )
{
   doors <- build_doors()

   if( stay )
   {
     final.pick <- a.pick
   }
   if( ! stay )
   {
     available.doors <- doors[ ! ( doors %in% opened.doors | doors == a.pick ) ]
     final.pick  <- sample( available.doors, size=1 ) 
   }

   return( final.pick )  # number between 1 and 5
}

determine_winner <- function( final.pick, game )
{
   if( game[ final.pick ] == "car" )
   {
      return( "WIN" )
   }
   if( game[ final.pick ] == "goat" )
   {
      return( "LOSE" )
   }
}
new.game <- create_game()
  first.pick <- select_door()
  opened.door <- open_goat_door( new.game, first.pick )
  final.pick.stay <- change_door( stay=T, opened.door, first.pick )
  final.pick.switch <- change_door( stay=F, opened.door, first.pick )
  outcome.stay <- determine_winner( final.pick.stay, new.game  )
  outcome.switch <- determine_winner( final.pick.switch, new.game )

  # game.results <- bundle the results
  # return( <<< game.results >>> )

  strategy <- c("stay","switch")
  outcome <- c(outcome.stay,outcome.switch)
  game.results <- data.frame( strategy, outcome,
                              stringsAsFactors=F )
  return( game.results )
}
play_game()

results.df <- NULL #collector

for( i in 1:10000 ) #iterator
{
  game.outcome <- play_game()
  results.df <- rbind( results.df, game.outcome )
}
table( results.df ) %>% 
  prop.table( margin=1 ) %>%  # row proportions
  round( 2 )

Let me know if there is anything else I can provide!

kphart2 commented 7 months ago

Hi Jacob, Did you ever figure this out? I had a similar issue with mine:

image

I tried to search online and it said to ensure I had magrittr installed/loaded and I did but it still did not work. -Paige

jacobmorgan05 commented 7 months ago

I couldn't figure out mine, but the function "%>%" is a part of the dplyr package, do you already have that loaded in your workplace?

kphart2 commented 7 months ago

Yes, I doublechecked that too. Not sure what's wrong with it :/

lecy commented 7 months ago

Are you getting the error when you knit? If so, do you have a library(dplyr) line in your RMD?

Recall that R Markdown files start from a clean environment (empty R console) when knitting, so your code might run interactively because you have loaded a package in your current session but will fail when knitting because the load library command is missing in the RMD.

lecy commented 7 months ago

Your problem above is that you are combining your functions in the wrong way when trying to create the wrapper play_game() function.

To create a wrapper function you want to first create the individual steps, then just call them in order. Instead you are defining functions inside of other functions, which complicates your code.

Move the play_game() function to the end after you create all of the step functions:

play_game <- function()
{
  new.game <- create_game()
  first.pick <- select_door()
  opened.door <- open_goat_door( new.game, first.pick )
  final.pick.stay <- change_door( stay=T, opened.door, first.pick )
  final.pick.switch <- change_door( stay=F, opened.door, first.pick )
  outcome.stay <- determine_winner( final.pick.stay, new.game  )
  outcome.switch <- determine_winner( final.pick.switch, new.game )

  strategy <- c("stay","switch")
  outcome <- c(outcome.stay,outcome.switch)
  game.results <- data.frame( strategy, outcome,
                              stringsAsFactors=F )
  return( game.results )
}
jacobmorgan05 commented 7 months ago

Oh ok that makes sense. I will try that when I get home from work and see if that fixes the problem.

lecy commented 7 months ago

One other issue I see - when you transition from the first game setup (always three doors and one car) to the generalized version you are updating some functions. For example, open_goat_door() becomes open_doors() since you are no longer opening a single goat door.

Make sure your play_game() function reflects these changes.

# defining function here: 
open_doors <- function( game, a.pick )

# note you are using old open_goat_door() function in play_game() wrapper: 

play_game <- function()
{
  new.game <- create_game()
  first.pick <- select_door()
  opened.door <- open_goat_door( new.game, first.pick )
  final.pick.stay <- change_door( stay=T, opened.door, first.pick )
  final.pick.switch <- change_door( stay=F, opened.door, first.pick )
  outcome.stay <- determine_winner( final.pick.stay, new.game  )
  outcome.switch <- determine_winner( final.pick.switch, new.game )

  strategy <- c("stay","switch")
  outcome <- c(outcome.stay,outcome.switch)
  game.results <- data.frame( strategy, outcome,
                              stringsAsFactors=F )
  return( game.results )
}

You need to update the workflow as well to account for the new argument requirements in the new functions. Your wrapper function in Part 2 needs a couple of values to get started (the goats and cars to set up the game). The other objects needed in subsequent steps can be created from those preliminary arguments. Recall the cookie recipe example:

make_cookies <- function( butter=0.33, sugar=0.5, eggs=1, flour=2, temp=375 )
{
   dry.goods <- combine( flour, sugar )
   batter <- mix( dry.goods, butter, eggs )
   cookies <- bake( batter, temp, time=10 )
   return( cookies )
}

Here make_cookies() is a wrapper function for all of the steps (which would be defined elsewhere). The raw inputs are butter, sugar, eggs, flour, and the oven temp value. Note that dry.goods and batter are objects created by the combine() and mix() steps, but you need those intermediate objects in order for the workflow to work.

Make a simple list of arguments needed for each function and review your code to make sure the arguments are flowing through the workflow properly.

# input B
# output C
step_one <- function( B )
{ 
  C <- function(B)   # use input B to create output C
  return(C) 
} 

# inputs A, C
# output D
step_two <- function( A, C )
{ 
  D <- A + C 
  return(D) 
}

wrapper_function <- function( A, B ) {
  C <- step_one( B )
  D <- step_two( A, C )
  return( D )
}

a <- # some tangible value
b <- # some tangible value 
wrapper_function( A=a, B=b )
graph TD;
    B-->step_one;
    step_one-->C;
    A-->step_two;
    C-->step_two;
    step_two-->D;
lecy commented 7 months ago

Note on Function Scope

Last note - you were getting the error "can't find open_goat_door()" even though you have it defined in your code was because you defined it within the play_game() function.

play_game <- function()
{
  open_goat_door <- function( game, a.pick )
  { ... }

  return( game.results )
}

This is a good example of function scope. What happens inside of functions stays inside of functions.

square_it <- function( x ) {
  x <- x^2
  return( x )
}

x <- 5
square_it( x )  
[1] 25
x
[1] 5

The variable X inside the function does not impact the variable X inside the global environment. Otherwise function calls would frequently interact with data in your environment and cause havoc.

That also pertains to defining functions inside of the wrapper functions. In the way you implemented play_game() the open_goat_door() function can ONLY be called inside of play_game(). As soon as the function finishes running the open_goat_door() function is deleted and only the game.results object that is returned from the function would remain.

Defining the step functions outside of play_game() means they can be called independently. You can use open_goat_door() inside of play_game(), but you can also call it on its own, or use it in another function.

open_goat_door <- function( game, a.pick )
{ ... }

play_game <- function()
{
  ... 
  opened.door <- open_goat_door( ... )
  ...
  return( game.results )
}
jacobmorgan05 commented 7 months ago

Thanks Jesse, this is really helpful insight. I'll apply your notes when I get home. I submitted the original code but didn't run the code block for pt 1 because that impacted the knit. Would you like me to resubmit tonight, or should I keep the original submission?

Thanks!

lecy commented 7 months ago

Resubmit please. I haven't sent solutions to Lab2 yet, so I would accept it.

jacobmorgan05 commented 7 months ago

Thanks, Jesse, I believe I fixed the issue since it is now knitting. I'll make sure to review solutions once they are posted