├── .gitignore ├── Base_Graphics ├── customTests.R ├── initLesson.R └── lesson.yaml ├── Basic_Building_Blocks ├── customTests.R └── lesson.yaml ├── Dates_and_Times ├── customTests.R ├── eedata.csv ├── initLesson.R └── lesson.yaml ├── Docker └── Dockerfile ├── Functions ├── customTests.R ├── initLesson.R ├── lesson.yaml └── scripts │ ├── bin_op.R │ ├── boring_function-correct.R │ ├── boring_function.R │ ├── evaluate.R │ ├── mad_libs.R │ ├── my_mean.R │ ├── remainder.R │ └── telegram.R ├── LICENSE ├── Logic ├── customTests.R └── lesson.yaml ├── Looking_at_Data ├── customTests.R ├── initLesson.R ├── lesson.yaml └── plant-data.txt ├── MANIFEST ├── Matrices_and_Data_Frames ├── customTests.R ├── initLesson.R └── lesson.yaml ├── Missing_Values ├── customTests.R ├── initLesson.R └── lesson.yaml ├── Programando_en_R.Rproj ├── README.md ├── Sequences_of_Numbers ├── customTests.R └── lesson.yaml ├── Simulation ├── customTests.R ├── initLesson.R └── lesson.yaml ├── Subsetting_Vectors ├── customTests.R ├── initLesson.R └── lesson.yaml ├── Vectors ├── customTests.R └── lesson.yaml ├── Workspace_and_Files └── lesson.yaml ├── instalar_curso.R ├── lapply_and_sapply ├── customTests.R ├── flag.data.txt ├── flag.names.txt ├── initLesson.R └── lesson.yaml └── vapply_and_tapply ├── customTests.R ├── initLesson.R └── lesson.yaml /.gitignore: -------------------------------------------------------------------------------- 1 | .Rproj.user 2 | .Rhistory 3 | .RData 4 | -------------------------------------------------------------------------------- /Base_Graphics/customTests.R: -------------------------------------------------------------------------------- 1 | # So swirl does not repeat execution of commands 2 | # AUTO_DETECT_NEWVAR <- FALSE 3 | 4 | expr_creates_var <- function(correctName=NULL){ 5 | e <- get("e", parent.frame()) 6 | # TODO: Eventually make auto-detection of new variables an option. 7 | # Currently it can be set in customTests.R 8 | delta <- if(!customTests$AUTO_DETECT_NEWVAR){ 9 | safeEval(e$expr, e) 10 | } else { 11 | e$delta 12 | } 13 | if(is.null(correctName)){ 14 | results <- expectThat(length(delta) >= 1, 15 | testthat::is_true(), 16 | label=paste(deparse(e$expr), 17 | "does not create a variable.")) 18 | } else { 19 | results <- expectThat(correctName %in% names(delta), 20 | testthat::is_true(), 21 | label=paste(deparse(e$expr), 22 | "does not create a variable named", 23 | correctName)) 24 | } 25 | if(results$passed){ 26 | e$newVar <- e$val 27 | e$newVarName <- names(delta)[1] 28 | e$delta <- mergeLists(delta, e$delta) 29 | } else { 30 | e$delta <- list() 31 | } 32 | return(results$passed) 33 | } 34 | 35 | # Returns TRUE if the user has calculated a value equal to that calculated by the given expression. 36 | calculates_same_value <- function(expr){ 37 | e <- get("e", parent.frame()) 38 | # Calculate what the user should have done. 39 | eSnap <- cleanEnv(e$snapshot) 40 | val <- eval(parse(text=expr), eSnap) 41 | passed <- isTRUE(all.equal(val, e$val)) 42 | if(!passed)e$delta <- list() 43 | return(passed) 44 | } 45 | 46 | omnitest <- function(correctExpr=NULL, correctVal=NULL, strict=FALSE){ 47 | e <- get("e", parent.frame()) 48 | # Trivial case 49 | if(is.null(correctExpr) && is.null(correctVal))return(TRUE) 50 | # Testing for correct expression only 51 | if(!is.null(correctExpr) && is.null(correctVal)){ 52 | passed <- expr_identical_to(correctExpr) 53 | if(!passed)e$delta <- list() 54 | return(passed) 55 | } 56 | # Testing for both correct expression and correct value 57 | # Value must be character or single number 58 | valGood <- NULL 59 | if(!is.null(correctVal)){ 60 | if(is.character(e$val)){ 61 | valResults <- expectThat(e$val, 62 | is_equivalent_to(correctVal, label=correctVal), 63 | label=(e$val)) 64 | if(is(e, "dev") && !valResults$passed)swirl_out(valResults$message) 65 | valGood <- valResults$passed 66 | # valGood <- val_matches(correctVal) 67 | } else if(!is.na(e$val) && is.numeric(e$val) && length(e$val) == 1){ 68 | cval <- try(as.numeric(correctVal), silent=TRUE) 69 | valResults <- expectThat(e$val, 70 | equals(cval, label=correctVal), 71 | label=toString(e$val)) 72 | if(is(e, "dev") && !valResults$passed)swirl_out(valResults$message) 73 | valGood <- valResults$passed 74 | } 75 | } 76 | exprGood <- ifelse(is.null(correctExpr), TRUE, expr_identical_to(correctExpr)) 77 | if(valGood && exprGood){ 78 | return(TRUE) 79 | } else if (valGood && !exprGood && !strict){ 80 | swirl_out("That's not the expression I expected but it works.") 81 | swirl_out("I've executed the correct expression in case the result is needed in an upcoming question.") 82 | eval(parse(text=correctExpr),globalenv()) 83 | return(TRUE) 84 | } else { 85 | e$delta <- list() 86 | return(FALSE) 87 | } 88 | } 89 | 90 | match_call <- function(correct_call = NULL) { 91 | e <- get("e", parent.frame()) 92 | # Trivial case 93 | if(is.null(correct_call)) return(TRUE) 94 | # Get full correct call 95 | full_correct_call <- expand_call(correct_call) 96 | # Expand user's expression 97 | expr <- deparse(e$expr) 98 | full_user_expr <- expand_call(expr) 99 | # Compare function calls with full arg names 100 | identical(full_correct_call, full_user_expr) 101 | } 102 | 103 | # Utility function for match_call answer test 104 | # Fills out a function call with full argument names 105 | expand_call <- function(call_string) { 106 | # Quote expression 107 | qcall <- parse(text=call_string)[[1]] 108 | # If expression is not greater than length 1... 109 | if(length(qcall) <= 1) return(qcall) 110 | # See if it's an assignment 111 | is_assign <- is(qcall, "<-") 112 | # If assignment, process righthandside 113 | if(is_assign) { 114 | # Get righthand side 115 | rhs <- qcall[[3]] 116 | # If righthand side is not a call, can't use match.fun() 117 | if(!is.call(rhs)) return(qcall) 118 | # Get function from function name 119 | fun <- match.fun(rhs[[1]]) 120 | # match.call() does not support primitive functions 121 | if(is.primitive(fun)) return(qcall) 122 | # Get expanded call 123 | full_rhs <- match.call(fun, rhs) 124 | # Full call 125 | qcall[[3]] <- full_rhs 126 | } else { # If not assignment, process whole thing 127 | # Get function from function name 128 | fun <- match.fun(qcall[[1]]) 129 | # match.call() does not support primitive functions 130 | if(is.primitive(fun)) return(qcall) 131 | # Full call 132 | qcall <- match.call(fun, qcall) 133 | } 134 | # Return expanded function call 135 | qcall 136 | } 137 | 138 | # Returns TRUE if e$expr matches any of the expressions given 139 | # (as characters) in the argument. 140 | ANY_of_exprs <- function(...){ 141 | e <- get("e", parent.frame()) 142 | any(sapply(c(...), function(expr)omnitest(expr))) 143 | } 144 | 145 | 146 | 147 | notify <- function() { 148 | e <- get("e", parent.frame()) 149 | if(e$val == "No") return(TRUE) 150 | 151 | good <- FALSE 152 | while(!good) { 153 | # Get info 154 | name <- readline_clean("What is your full name? ") 155 | address <- readline_clean("What is the email address of the person you'd like to notify? ") 156 | 157 | # Repeat back to them 158 | message("\nDoes everything look good?\n") 159 | message("Your name: ", name, "\n", "Send to: ", address) 160 | 161 | yn <- select.list(c("Yes", "No"), graphics = FALSE) 162 | if(yn == "Yes") good <- TRUE 163 | } 164 | 165 | # Get course and lesson names 166 | course_name <- attr(e$les, "course_name") 167 | lesson_name <- attr(e$les, "lesson_name") 168 | 169 | subject <- paste(name, "just completed", course_name, "-", lesson_name) 170 | body = "" 171 | 172 | # Send email 173 | swirl:::email(address, subject, body) 174 | 175 | hrule() 176 | message("I just tried to create a new email with the following info:\n") 177 | message("To: ", address) 178 | message("Subject: ", subject) 179 | message("Body: ") 180 | 181 | message("\nIf it didn't work, you can send the same email manually.") 182 | hrule() 183 | 184 | # Return TRUE to satisfy swirl and return to course menu 185 | TRUE 186 | } 187 | 188 | readline_clean <- function(prompt = "") { 189 | wrapped <- strwrap(prompt, width = getOption("width") - 2) 190 | mes <- stringr::str_c("| ", wrapped, collapse = "\n") 191 | message(mes) 192 | readline() 193 | } 194 | 195 | hrule <- function() { 196 | message("\n", paste0(rep("#", getOption("width") - 2), collapse = ""), "\n") 197 | } 198 | -------------------------------------------------------------------------------- /Base_Graphics/initLesson.R: -------------------------------------------------------------------------------- 1 | ### MAY END UP USING THIS AT SOME POINT... ### 2 | 3 | # Code used to create dataset 4 | # dob_start <- as.Date('1950-01-01') 5 | # dob_end <- as.Date('1994-01-01') 6 | # hire_start <- as.Date('1985-01-01') 7 | # hire_end <- as.Date('1994-01-01') 8 | # poss_dobs <- seq(dob_start, dob_end, 'days') 9 | # poss_hires <- seq(hire_start, hire_end, 'days') 10 | # set.seed(5234) 11 | # dob <- sample(poss_dobs, 99, replace=TRUE) 12 | # set.seed(1234) 13 | # hire_date <- sample(poss_hires, 99, replace=TRUE) 14 | # eedata <- data.frame(ee_num = 1:99, dob, hire_date) 15 | # write.csv(eedata, file='R_Programming/Dates_and_Times/eedata.csv', 16 | # row.names=FALSE) 17 | # 18 | # .path2data <- file.path(path.package('swirl'), 'Courses', 'R_Programming', 19 | # 'Dates_and_Times', 'eedata.csv') 20 | # eedata <- read.csv(.path2data, as.is=TRUE) 21 | # eedata$dob <- as.Date(eedata$dob) 22 | # eedata$hire_date <- as.Date(eedata$hire_date) 23 | 24 | marital<-matrix(c(652,1537,598,242,36,46,38,21,218,327,106,67),nrow = 3, byrow = T) 25 | colnames(marital)<-c("0","1-150","151-300",">300") 26 | rownames(marital)<-c("Married","Prev.Married","Single") -------------------------------------------------------------------------------- /Basic_Building_Blocks/customTests.R: -------------------------------------------------------------------------------- 1 | notify <- function() { 2 | e <- get("e", parent.frame()) 3 | if(e$val == "No") return(TRUE) 4 | 5 | good <- FALSE 6 | while(!good) { 7 | # Get info 8 | name <- readline_clean("What is your full name? ") 9 | address <- readline_clean("What is the email address of the person you'd like to notify? ") 10 | 11 | # Repeat back to them 12 | message("\nDoes everything look good?\n") 13 | message("Your name: ", name, "\n", "Send to: ", address) 14 | 15 | yn <- select.list(c("Yes", "No"), graphics = FALSE) 16 | if(yn == "Yes") good <- TRUE 17 | } 18 | 19 | # Get course and lesson names 20 | course_name <- attr(e$les, "course_name") 21 | lesson_name <- attr(e$les, "lesson_name") 22 | 23 | subject <- paste(name, "just completed", course_name, "-", lesson_name) 24 | body = "" 25 | 26 | # Send email 27 | swirl:::email(address, subject, body) 28 | 29 | hrule() 30 | message("I just tried to create a new email with the following info:\n") 31 | message("To: ", address) 32 | message("Subject: ", subject) 33 | message("Body: ") 34 | 35 | message("\nIf it didn't work, you can send the same email manually.") 36 | hrule() 37 | 38 | # Return TRUE to satisfy swirl and return to course menu 39 | TRUE 40 | } 41 | 42 | readline_clean <- function(prompt = "") { 43 | wrapped <- strwrap(prompt, width = getOption("width") - 2) 44 | mes <- stringr::str_c("| ", wrapped, collapse = "\n") 45 | message(mes) 46 | readline() 47 | } 48 | 49 | hrule <- function() { 50 | message("\n", paste0(rep("#", getOption("width") - 2), collapse = ""), "\n") 51 | } 52 | -------------------------------------------------------------------------------- /Basic_Building_Blocks/lesson.yaml: -------------------------------------------------------------------------------- 1 | - Class: meta 2 | Course: Programando en R 3 | Lesson: Conceptos Básicos 4 | Author: Nick Carchedi 5 | Type: Standard 6 | Organization: JHU Biostat 7 | Version: 2.2.0 8 | 9 | - Class: text 10 | Output: En esta lección, vamos a explorar algunos elementos básicos de la programación en el lenguaje R. 11 | 12 | - Class: text 13 | Output: Si en algún momento desea obtener más información sobre un tema concreto relacionado con 14 | R, puede escribir help.start() en el indicador >, se abrirá un menú de recursos (ya sea dentro o RStudio su navegador web por defecto, dependiendo de su configuración). 15 | Como alternativa, una simple búsqueda en Internet a menudo da la respuesta que estás buscando. 16 | 17 | - Class: cmd_question 18 | Output: En su forma más simple, R puede ser utilizado como una calculadora interactiva. Escribe 5 + 7 y pulsa Intro. 19 | CorrectAnswer: 5 + 7 20 | AnswerTests: omnitest(correctExpr='5 + 7') 21 | Hint: Escribe 5 + 7 y pulsa Intro. 22 | 23 | - Class: text 24 | Output: R simplemente imprime el resultado de 12 por defecto. Sin embargo, R es un lenguaje de programación y a menudo la razón por la que utiliza un lenguaje de programación, en oposición a una calculadora, es para automatizar algunos procesos o evitar repeticiones innecesarias. 25 | 26 | - Class: text 27 | Output: En este caso, es posible que desee utilizar nuestro resultado de arriba en un segundo cálculo. En lugar de volver a escribir 5 + 7 cada vez que lo necesitamos, podemos simplemente crear una nueva variable que almacena el resultado. 28 | 29 | - Class: text 30 | Output: 'La forma en que asigna un valor a una variable en R es mediante el uso del operador de asignación, que es sólo un símbolo ''menor que'' seguido de un signo ''menos''. Eso se parece a esto: <-' 31 | 32 | - Class: text 33 | Output: Piense en el operador de asignación como una flecha. Usted está asignando el valor en el lado derecho de la flecha para el nombre de la variable en el lado izquierdo de la flecha. 34 | 35 | - Class: cmd_question 36 | Output: Para asignar el resultado de 5 + 7 a una nueva variable llamada x, escriba x <- 5 + 7. Esto puede leerse como 'x toma el valor de 5 más 7'. Dese una oportunidad ahora. 37 | CorrectAnswer: x <- 5 + 7 38 | AnswerTests: any_of_exprs('x <- 5 + 7', 'x <- 7 + 5') 39 | Hint: Escriba x <- 5 + 7. Es importante incluir un único espacio a cada lado de el operador de asignación, pero no ponga un espacio entre el `<` y el `-` que forman la flecha. 40 | 41 | - Class: text 42 | Output: Se dará cuenta de que R no imprime el resultado de 12 en esta ocasión. cuando se utiliza el operador de asignación, R asume que no quieres ver el resultado inmediatamente, sino que tiene la intención de utilizar el resultado para otra cosa más adelante. 43 | 44 | - Class: cmd_question 45 | Output: Para ver el contenido de la variable x, simplemente escriba x y pulse Intro. Intentalo ahora. 46 | CorrectAnswer: x 47 | AnswerTests: omnitest(correctExpr='x') 48 | Hint: Escribe x y pulsa Intro. Esto imprimirá automáticamente el valor de x. 49 | 50 | - Class: cmd_question 51 | Output: Ahora, almacene el resultado de x - 3 en una variable nueva llamada y. 52 | CorrectAnswer: y <- x - 3 53 | AnswerTests: omnitest(correctExpr='y <- x - 3') 54 | Hint: Escriba y <- x - 3 y pulse Intro. Si usted utiliza x - 3 o x-3 es de preferencia personal, pero es buena costumbre de incluir un espacio a cada lado del operador de asignación. 55 | 56 | - Class: cmd_question 57 | Output: ¿Cuál es el valor de y? Escriba y para averiguarlo. 58 | CorrectAnswer: 'y' 59 | AnswerTests: omnitest(correctExpr='y') 60 | Hint: Escriba y y presione Intro. 61 | 62 | - Class: text 63 | Output: Ahora, vamos a crear una pequeña colección de números llamados un vector. Cualquier objeto que contiene datos se denomina una estructura de datos numéricos y los vectores son de las más simples tipos de estructuras de datos en R. De hecho, incluso un solo número se considera un vector de longitud uno. 64 | 65 | - Class: cmd_question 66 | Output: La forma más fácil de crear un vector es con la función c(), que se usa para "concatenar" o "combinar". Para crear un vector que contiene los números 1.1, 9 y 3.14, escriba c(1.1, 9, 3.14). Pruébalo ahora y guarde el resultado en una variable llamada z. 67 | CorrectAnswer: z <- c(1.1, 9, 3.14) 68 | AnswerTests: omnitest(correctExpr='z <- c(1.1, 9, 3.14)') 69 | Hint: Ingresando z <- c (1.1, 9, 3.14) asignará el vector (1.1, 9, 3.14) a un nueva variable llamada z. No es necesario Incluir espacios individuales después de las comas en el vector, pero ayuda a que su código se vea menos desordenado y más legible. 70 | 71 | - Class: cmd_question 72 | Output: En cualquier momento usted puede tener preguntas acerca de una función en particular, puede acceder a los archivos de ayuda incorporada de R a través del comando `?`. Por ejemplo, si desea más información de la función c(), escriba ?c sin los paréntesis que normalmente siguen al nombre de una función. Dese una oportunidad. 73 | CorrectAnswer: ?c 74 | AnswerTests: omnitest(correctExpr='?c') 75 | Hint: Escriba ?c y pulse Intro. Con ello se abre el archivo de ayuda para la función c(). 76 | 77 | - Class: cmd_question 78 | Output: Escriba z para ver su contenido. Observe que no hay comas separando los valores en la salida. 79 | CorrectAnswer: z 80 | AnswerTests: omnitest(correctExpr='z') 81 | Hint: Escriba z y pulse Intro para ver su contenido. 82 | 83 | - Class: cmd_question 84 | Output: Usted puede combinar vectores para hacer un nuevo vector. Crear un nuevo vector que contiene z, 555, entonces z de nuevo en ese orden. No asigne este vector a una nueva variable, de modo que sólo podemos ver el resultado inmediatamente. 85 | CorrectAnswer: c(z, 555, z) 86 | AnswerTests: omnitest(correctExpr='c(z, 555, z)') 87 | Hint: Escriba c (z, 555, z). No crear una nueva variable. Sólo queremos ver el resultado. 88 | 89 | - Class: cmd_question 90 | Output: 'Vectores numéricos se puede utilizar en expresiones aritméticas. Escriba lo siguiente para ver qué pasa: z * 2 + 100.' 91 | CorrectAnswer: z * 2 + 100 92 | AnswerTests: omnitest(correctExpr='z * 2 + 100') 93 | Hint: Introduzca z * 2 + 100, sin asignar el resultado a una variable. El símbolo `*` se utiliza para la multiplicación y comparte una tecla con el número 8 en muchos teclados. 94 | 95 | - Class: text 96 | Output: En primer lugar, R multiplica cada uno de los tres elementos en z por 2. Entonces se añadieron 100 a cada elemento para obtener el resultado que ves arriba. 97 | 98 | - Class: text 99 | Output: Otros operadores aritméticos comunes son `+`, `-`, `/` y `^` (donde x ^ 2 significa 'x al cuadrado"). Para tomar la raíz cuadrada, utilice la función sqrt() y tomar el valor absoluto, utilice la función abs(). 100 | 101 | - Class: cmd_question 102 | Output: Tome la raíz cuadrada de z - 1 y asignarlo a una nueva variable llamada my_sqrt. 103 | CorrectAnswer: my_sqrt <- sqrt(z - 1) 104 | AnswerTests: omnitest(correctExpr='my_sqrt <- sqrt(z - 1)') 105 | Hint: Asigne el resultado de sqrt (z - 1) a una variable llamada my_sqrt. 106 | 107 | - Class: mult_question 108 | Output: Antes de ver el contenido de la variable my_sqrt, ¿qué crees que contiene? 109 | CorrectAnswer: un vector de longitud 3 110 | AnswerChoices: un vector de longitud 3; un solo número (es decir, un vector de longitud 1); un vector de longitud 0 (es decir, un vector vacío) 111 | AnswerTests: omnitest(correctVal='un vector de longitud 3') 112 | Hint: 'Piensa en cómo R manejó la otra operación ''vectorizada'': elemento por elemento.' 113 | 114 | - Class: cmd_question 115 | Output: Imprime el contenido de my_sqrt. 116 | CorrectAnswer: my_sqrt 117 | AnswerTests: omnitest(correctExpr='my_sqrt') 118 | Hint: Sólo tienes que escribir my_sqrt y pulse Intro para ver su valor. 119 | 120 | - Class: text 121 | Output: Como habrás adivinado, R primero resta 1 de cada elemento de la z, luego tomó la raíz cuadrada de cada elemento. Esto le deja con un vector de la misma longitud que el vector z inicial. 122 | 123 | - Class: cmd_question 124 | Output: Ahora, cree una variable llamada nueva my_div que obtiene el valor de z dividido por my_sqrt. 125 | CorrectAnswer: my_div <- z / my_sqrt 126 | AnswerTests: omnitest(correctExpr='my_div <- z / my_sqrt') 127 | Hint: Introduzca my_div <- z / my_sqrt. No se requieren los espacios a ambos lados del signo `/`, pero a menudo puede mejorar la legibilidad haciendo código aparece más despejado. Al final, es una preferencia personal. 128 | 129 | - Class: mult_question 130 | Output: ¿Cuál crees que es la declaración verdadera? 131 | CorrectAnswer: El primer elemento de my_div es igual al primer elemento de z dividido por el primer elemento de my_sqrt, y así sucesivamente ... 132 | AnswerChoices: El primer elemento de my_div es igual al primer elemento de z dividido por el primer elemento de my_sqrt, y así sucesivamente ...; my_div es un solo número (es decir, un vector de longitud 1); my_div es indefinido 133 | AnswerTests: omnitest(correctVal='El primer elemento de my_div es igual al primer elemento de z dividido por el primer elemento de my_sqrt, y así sucesivamente ...') 134 | Hint: Piense acerca de cómo R maneja las otras operaciones 'vectorizadas' como `+` y `*`. 135 | 136 | - Class: cmd_question 137 | Output: Adelante e imprimir el contenido de my_div. 138 | CorrectAnswer: my_div 139 | AnswerTests: omnitest(correctExpr='my_div') 140 | Hint: Escriba my_div y pulse Intro para ver su contenido. 141 | 142 | - Class: text 143 | Output: Cuando se le presenten dos vectores de la misma longitud, R simplemente realiza la operación aritmética especificada (`+`, `-`, `*`, etc.) elemento elemento por. Si los vectores son de diferentes longitudes, R 'recicla' el vector más corto hasta que es la misma longitud que el vector más largo. 144 | 145 | - Class: text 146 | Output: Cuando hicimos z * 2 + 100 en nuestro ejemplo anterior, z era un vector de longitud 3, pero técnicamente 2 y 100 son cada uno de vectores de longitud 1. 147 | 148 | - Class: text 149 | Output: Detrás de las escenas, R es reciclar, el 2 para hacerlo un vector de 2s y el 100 para hacer un vector de 100s. En otras palabras, cuando usted pide a R calcular z * 2 + 100, lo que realmente se calcula es z * c(2, 2, 2) + c(100, 100, 100). 150 | 151 | - Class: cmd_question 152 | Output: Para ver otro ejemplo de cómo funciona este vector «reciclado», trate de sumar c(1, 2, 3, 4) y c(0, 10). No te preocupes por guardar el resultado en una nueva variable. 153 | CorrectAnswer: c(1, 2, 3, 4) + c(0, 10) 154 | AnswerTests: omnitest(correctExpr='c(1, 2, 3, 4) + c(0, 10)') 155 | Hint: Escriba c(1, 2, 3, 4) + c(0, 10) en la consola para ver cómo R suma dos vectores de diferente longitud. No asigne el resultado a una variable. 156 | 157 | - Class: text 158 | Output: Si la longitud del vector más corto no divide exactamente a la longitud del vector más largo, R seguirá aplicando el método de «reciclado», pero lanzará una advertencia para hacerle saber que algo sospechoso podría estar pasando. 159 | 160 | - Class: cmd_question 161 | Output: Intente c(1, 2, 3, 4) + c(0, 10, 100) para ver un ejemplo. 162 | CorrectAnswer: c(1, 2, 3, 4) + c(0, 10, 100) 163 | AnswerTests: omnitest(correctExpr='c(1, 2, 3, 4) + c(0, 10, 100)') 164 | Hint: Escriba c(1, 2, 3, 4) + c(0, 10, 100) para ver cómo maneja R la suma de dos vectores, cuando la longitud del vector más corto lo repite uniformemente en la longitud del vector más largo. No te preocupes por asignar el resultado a una variable. 165 | 166 | - Class: text 167 | Output: Antes de concluir esta lección, me gustaría mostrarte un par de trucos para ahorrar tiempo. 168 | 169 | - Class: text 170 | Output: A principios de la lección, z multiplica * 2 + 100. Supongamos que has cometido un error y que querías sumar 1000 en lugar de 100. Usted podría volver a escribir la expresión, o ... 171 | 172 | - Class: cmd_question 173 | Output: En muchos entornos de programación, la tecla flecha hacia arriba recorre a través de los comandos anteriores. Trate de teclear la flecha hacia arriba en el teclado hasta que se llegue a este comando (z * 2 + 100), a continuación, cambiae de 100 a 1000 y pulse Enter. Si la flecha hacia arriba no funciona para ti, sólo tienes que escribir el comando corregido. 174 | CorrectAnswer: z * 2 + 1000 175 | AnswerTests: omnitest(correctExpr='z * 2 + 1000') 176 | Hint: Si su entorno no admite la función de flecha hacia arriba, y luego sólo tienes que escribir el comando corregido para seguir adelante. 177 | 178 | - Class: text 179 | Output: Por último, vamos a suponer que desea ver el contenido de una variable que ha creado anteriormente, pero parece que no puede recordar si usted la nombró como my_div o myDiv. Podrías probar ambos y ver lo que funciona, o ... 180 | 181 | - Class: cmd_question 182 | Output: Puede escribir las dos primeras letras del nombre de la variable, y luego presionar la tecla Tab (posiblemente más de una vez). La mayoría de los entornos de programación proporcionará una lista de las variables que ha creado que comiencen con "mi". Esto se llama auto-completado y puede ser muy útil cuando se tienen muchas variables en el espacio de trabajo. Dese una oportunidad. (Si el autocompletado no funciona para ti, sólo tienes que escribir my_div y pulse Intro.) 183 | CorrectAnswer: my_div 184 | AnswerTests: omnitest(correctExpr='my_div') 185 | Hint: Si su entorno de programación no soporta auto-realización, sólo tienes que escribir my_div y pulse Enter para continuar. 186 | 187 | 188 | -------------------------------------------------------------------------------- /Dates_and_Times/customTests.R: -------------------------------------------------------------------------------- 1 | # So swirl does not repeat execution of commands 2 | # AUTO_DETECT_NEWVAR <- FALSE 3 | 4 | expr_creates_var <- function(correctName=NULL){ 5 | e <- get("e", parent.frame()) 6 | # TODO: Eventually make auto-detection of new variables an option. 7 | # Currently it can be set in customTests.R 8 | delta <- if(!customTests$AUTO_DETECT_NEWVAR){ 9 | safeEval(e$expr, e) 10 | } else { 11 | e$delta 12 | } 13 | if(is.null(correctName)){ 14 | results <- expectThat(length(delta) >= 1, 15 | testthat::is_true(), 16 | label=paste(deparse(e$expr), 17 | "does not create a variable.")) 18 | } else { 19 | results <- expectThat(correctName %in% names(delta), 20 | testthat::is_true(), 21 | label=paste(deparse(e$expr), 22 | "does not create a variable named", 23 | correctName)) 24 | } 25 | if(results$passed){ 26 | e$newVar <- e$val 27 | e$newVarName <- names(delta)[1] 28 | e$delta <- mergeLists(delta, e$delta) 29 | } else { 30 | e$delta <- list() 31 | } 32 | return(results$passed) 33 | } 34 | 35 | # Returns TRUE if the user has calculated a value equal to that calculated by the given expression. 36 | calculates_same_value <- function(expr){ 37 | e <- get("e", parent.frame()) 38 | # Calculate what the user should have done. 39 | eSnap <- cleanEnv(e$snapshot) 40 | val <- eval(parse(text=expr), eSnap) 41 | passed <- isTRUE(all.equal(val, e$val)) 42 | if(!passed)e$delta <- list() 43 | return(passed) 44 | } 45 | 46 | omnitest <- function(correctExpr=NULL, correctVal=NULL, strict=FALSE){ 47 | e <- get("e", parent.frame()) 48 | # Trivial case 49 | if(is.null(correctExpr) && is.null(correctVal))return(TRUE) 50 | # Testing for correct expression only 51 | if(!is.null(correctExpr) && is.null(correctVal)){ 52 | passed <- expr_identical_to(correctExpr) 53 | if(!passed)e$delta <- list() 54 | return(passed) 55 | } 56 | # Testing for both correct expression and correct value 57 | # Value must be character or single number 58 | valGood <- NULL 59 | if(!is.null(correctVal)){ 60 | if(is.character(e$val)){ 61 | valResults <- expectThat(e$val, 62 | is_equivalent_to(correctVal, label=correctVal), 63 | label=(e$val)) 64 | if(is(e, "dev") && !valResults$passed)swirl_out(valResults$message) 65 | valGood <- valResults$passed 66 | # valGood <- val_matches(correctVal) 67 | } else if(!is.na(e$val) && is.numeric(e$val) && length(e$val) == 1){ 68 | cval <- try(as.numeric(correctVal), silent=TRUE) 69 | valResults <- expectThat(e$val, 70 | equals(cval, label=correctVal), 71 | label=toString(e$val)) 72 | if(is(e, "dev") && !valResults$passed)swirl_out(valResults$message) 73 | valGood <- valResults$passed 74 | } 75 | } 76 | exprGood <- ifelse(is.null(correctExpr), TRUE, expr_identical_to(correctExpr)) 77 | if(valGood && exprGood){ 78 | return(TRUE) 79 | } else if (valGood && !exprGood && !strict){ 80 | swirl_out("That's not the expression I expected but it works.") 81 | swirl_out("I've executed the correct expression in case the result is needed in an upcoming question.") 82 | eval(parse(text=correctExpr),globalenv()) 83 | return(TRUE) 84 | } else { 85 | e$delta <- list() 86 | return(FALSE) 87 | } 88 | } 89 | 90 | match_call <- function(correct_call = NULL) { 91 | e <- get("e", parent.frame()) 92 | # Trivial case 93 | if(is.null(correct_call)) return(TRUE) 94 | # Get full correct call 95 | full_correct_call <- expand_call(correct_call) 96 | # Expand user's expression 97 | expr <- deparse(e$expr) 98 | full_user_expr <- expand_call(expr) 99 | # Compare function calls with full arg names 100 | identical(full_correct_call, full_user_expr) 101 | } 102 | 103 | # Utility function for match_call answer test 104 | # Fills out a function call with full argument names 105 | expand_call <- function(call_string) { 106 | # Quote expression 107 | qcall <- parse(text=call_string)[[1]] 108 | # If expression is not greater than length 1... 109 | if(length(qcall) <= 1) return(qcall) 110 | # See if it's an assignment 111 | is_assign <- is(qcall, "<-") 112 | # If assignment, process righthandside 113 | if(is_assign) { 114 | # Get righthand side 115 | rhs <- qcall[[3]] 116 | # If righthand side is not a call, can't use match.fun() 117 | if(!is.call(rhs)) return(qcall) 118 | # Get function from function name 119 | fun <- match.fun(rhs[[1]]) 120 | # match.call() does not support primitive functions 121 | if(is.primitive(fun)) return(qcall) 122 | # Get expanded call 123 | full_rhs <- match.call(fun, rhs) 124 | # Full call 125 | qcall[[3]] <- full_rhs 126 | } else { # If not assignment, process whole thing 127 | # Get function from function name 128 | fun <- match.fun(qcall[[1]]) 129 | # match.call() does not support primitive functions 130 | if(is.primitive(fun)) return(qcall) 131 | # Full call 132 | qcall <- match.call(fun, qcall) 133 | } 134 | # Return expanded function call 135 | qcall 136 | } 137 | 138 | # Returns TRUE if e$expr matches any of the expressions given 139 | # (as characters) in the argument. 140 | ANY_of_exprs <- function(...){ 141 | e <- get("e", parent.frame()) 142 | any(sapply(c(...), function(expr)omnitest(expr))) 143 | } 144 | 145 | 146 | 147 | notify <- function() { 148 | e <- get("e", parent.frame()) 149 | if(e$val == "No") return(TRUE) 150 | 151 | good <- FALSE 152 | while(!good) { 153 | # Get info 154 | name <- readline_clean("What is your full name? ") 155 | address <- readline_clean("What is the email address of the person you'd like to notify? ") 156 | 157 | # Repeat back to them 158 | message("\nDoes everything look good?\n") 159 | message("Your name: ", name, "\n", "Send to: ", address) 160 | 161 | yn <- select.list(c("Yes", "No"), graphics = FALSE) 162 | if(yn == "Yes") good <- TRUE 163 | } 164 | 165 | # Get course and lesson names 166 | course_name <- attr(e$les, "course_name") 167 | lesson_name <- attr(e$les, "lesson_name") 168 | 169 | subject <- paste(name, "just completed", course_name, "-", lesson_name) 170 | body = "" 171 | 172 | # Send email 173 | swirl:::email(address, subject, body) 174 | 175 | hrule() 176 | message("I just tried to create a new email with the following info:\n") 177 | message("To: ", address) 178 | message("Subject: ", subject) 179 | message("Body: ") 180 | 181 | message("\nIf it didn't work, you can send the same email manually.") 182 | hrule() 183 | 184 | # Return TRUE to satisfy swirl and return to course menu 185 | TRUE 186 | } 187 | 188 | readline_clean <- function(prompt = "") { 189 | wrapped <- strwrap(prompt, width = getOption("width") - 2) 190 | mes <- stringr::str_c("| ", wrapped, collapse = "\n") 191 | message(mes) 192 | readline() 193 | } 194 | 195 | hrule <- function() { 196 | message("\n", paste0(rep("#", getOption("width") - 2), collapse = ""), "\n") 197 | } 198 | -------------------------------------------------------------------------------- /Dates_and_Times/eedata.csv: -------------------------------------------------------------------------------- 1 | "ee_num","dob","hire_date" 2 | 1,1988-04-07,1986-01-09 3 | 2,1980-06-25,1990-08-09 4 | 3,1962-02-23,1990-06-27 5 | 4,1981-10-22,1990-08-12 6 | 5,1974-01-08,1992-10-01 7 | 6,1990-09-01,1990-10-07 8 | 7,1958-04-22,1985-02-01 9 | 8,1963-08-30,1987-02-04 10 | 9,1978-09-02,1990-12-31 11 | 10,1990-12-29,1989-08-18 12 | 11,1957-09-09,1991-03-31 13 | 12,1992-01-17,1989-11-27 14 | 13,1969-02-26,1987-07-19 15 | 14,1984-10-27,1993-04-25 16 | 15,1957-04-28,1987-08-20 17 | 16,1981-11-04,1992-07-16 18 | 17,1965-10-19,1987-07-31 19 | 18,1974-02-02,1987-05-28 20 | 19,1979-09-06,1986-09-06 21 | 20,1958-11-20,1987-02-03 22 | 21,1990-02-07,1987-11-08 23 | 22,1986-08-12,1987-09-23 24 | 23,1965-11-10,1986-06-07 25 | 24,1973-02-07,1985-05-12 26 | 25,1961-05-21,1986-12-21 27 | 26,1988-08-25,1992-04-19 28 | 27,1954-09-25,1989-09-25 29 | 28,1968-10-23,1993-03-27 30 | 29,1993-03-29,1992-06-26 31 | 30,1983-06-01,1985-05-31 32 | 31,1962-03-05,1989-02-08 33 | 32,1973-12-16,1987-05-22 34 | 33,1972-06-06,1987-09-29 35 | 34,1969-05-14,1989-07-27 36 | 35,1972-10-29,1986-08-19 37 | 36,1952-10-11,1991-11-03 38 | 37,1982-11-18,1986-10-24 39 | 38,1977-11-27,1987-05-01 40 | 39,1957-03-29,1993-12-07 41 | 40,1974-05-20,1992-04-08 42 | 41,1961-01-09,1989-12-25 43 | 42,1990-11-28,1990-10-27 44 | 43,1957-09-07,1987-10-23 45 | 44,1983-10-25,1990-08-07 46 | 45,1990-05-26,1987-12-21 47 | 46,1959-01-22,1989-07-09 48 | 47,1968-10-09,1991-02-05 49 | 48,1958-11-18,1989-05-14 50 | 49,1954-08-24,1987-03-14 51 | 50,1963-03-25,1991-11-22 52 | 51,1953-02-01,1985-08-31 53 | 52,1961-11-30,1987-10-16 54 | 53,1972-10-06,1991-06-17 55 | 54,1964-10-18,1989-07-17 56 | 55,1984-08-27,1986-05-19 57 | 56,1962-09-22,1989-07-15 58 | 57,1968-12-17,1989-06-13 59 | 58,1989-04-16,1991-10-06 60 | 59,1968-08-18,1986-07-29 61 | 60,1977-07-17,1992-08-21 62 | 61,1960-09-14,1992-10-14 63 | 62,1984-12-16,1985-05-18 64 | 63,1982-11-22,1987-11-09 65 | 64,1985-07-05,1985-02-15 66 | 65,1965-04-23,1987-02-25 67 | 66,1969-01-25,1991-05-12 68 | 67,1989-03-09,1987-10-11 69 | 68,1967-05-24,1989-07-31 70 | 69,1963-01-17,1985-06-19 71 | 70,1958-12-03,1990-01-31 72 | 71,1990-11-21,1986-02-04 73 | 72,1972-07-22,1993-01-14 74 | 73,1992-07-25,1985-02-18 75 | 74,1978-09-20,1992-01-19 76 | 75,1961-01-08,1985-10-23 77 | 76,1950-08-11,1989-09-04 78 | 77,1952-07-28,1988-06-17 79 | 78,1971-03-28,1985-08-19 80 | 79,1970-08-08,1987-11-21 81 | 80,1982-10-02,1991-01-08 82 | 81,1958-05-15,1993-05-05 83 | 82,1970-05-19,1989-04-01 84 | 83,1980-03-30,1986-04-14 85 | 84,1982-11-07,1989-11-25 86 | 85,1960-09-02,1986-10-08 87 | 86,1959-03-24,1993-02-02 88 | 87,1955-02-23,1988-07-04 89 | 88,1971-10-29,1987-10-20 90 | 89,1968-08-01,1986-06-11 91 | 90,1993-12-20,1993-01-25 92 | 91,1974-01-12,1986-07-02 93 | 92,1954-01-20,1993-02-08 94 | 93,1973-12-20,1986-03-17 95 | 94,1983-03-25,1986-03-09 96 | 95,1954-05-14,1985-12-13 97 | 96,1954-02-05,1989-08-10 98 | 97,1993-06-02,1987-09-15 99 | 98,1980-05-31,1985-03-29 100 | 99,1965-02-23,1987-10-16 101 | -------------------------------------------------------------------------------- /Dates_and_Times/initLesson.R: -------------------------------------------------------------------------------- 1 | ### MAY END UP USING THIS AT SOME POINT... ### 2 | 3 | # Code used to create dataset 4 | # dob_start <- as.Date('1950-01-01') 5 | # dob_end <- as.Date('1994-01-01') 6 | # hire_start <- as.Date('1985-01-01') 7 | # hire_end <- as.Date('1994-01-01') 8 | # poss_dobs <- seq(dob_start, dob_end, 'days') 9 | # poss_hires <- seq(hire_start, hire_end, 'days') 10 | # set.seed(5234) 11 | # dob <- sample(poss_dobs, 99, replace=TRUE) 12 | # set.seed(1234) 13 | # hire_date <- sample(poss_hires, 99, replace=TRUE) 14 | # eedata <- data.frame(ee_num = 1:99, dob, hire_date) 15 | # write.csv(eedata, file='R_Programming/Dates_and_Times/eedata.csv', 16 | # row.names=FALSE) 17 | # 18 | # .path2data <- file.path(path.package('swirl'), 'Courses', 'R_Programming', 19 | # 'Dates_and_Times', 'eedata.csv') 20 | # eedata <- read.csv(.path2data, as.is=TRUE) 21 | # eedata$dob <- as.Date(eedata$dob) 22 | # eedata$hire_date <- as.Date(eedata$hire_date) 23 | -------------------------------------------------------------------------------- /Dates_and_Times/lesson.yaml: -------------------------------------------------------------------------------- 1 | - Class: meta 2 | Course: Programando en R 3 | Lesson: Fechas y Horas 4 | Author: Nick Carchedi 5 | Type: Standard 6 | Organization: JHU Biostat 7 | Version: 2.2.11 8 | 9 | - Class: text 10 | Output: R tiene una manera especial de representar fechas y horas, lo cual puede ser útil si se trabaja con datos que muestran cómo algo cambia con el tiempo (es decir, datos de series de tiempo) o si sus datos contienen alguna otra información temporal, como fechas de nacimiento. 11 | 12 | - Class: text 13 | Output: Las fechas están representados por la clase 'Date' y los tiempos están representados por las clases 'POSIXct' y 'POSIXlt'. Internamente, las fechas se almacenan como el número de días desde 01/01/1970 y los tiempos como el número de segundos desde 01/01/1970 (para 'POSIXct') o como una lista de segundos, minutos, horas, etc (para 'POSIXlt'). 14 | 15 | - Class: cmd_question 16 | Output: Comencemos usando d1 <- Sys.Date() para obtener la fecha actual y almacenarla en la variable d1. (Esto es la letra 'd' y el número 1). 17 | CorrectAnswer: d1 <- Sys.Date() 18 | AnswerTests: omnitest(correctExpr='d1 <- Sys.Date()') 19 | Hint: Escriba d1 <- Sys.Date() para obtener la fecha actual y almacenarla en una nueva variable llamada d1. 20 | 21 | - Class: cmd_question 22 | Output: Utilice la función class() para confirmar que d1 es un objeto 'Date'. 23 | CorrectAnswer: class(d1) 24 | AnswerTests: omnitest(correctExpr='class(d1)') 25 | Hint: class(d1) le dirá la clase de d1. 26 | 27 | - Class: cmd_question 28 | Output: Podemos utilizar la función unclass() para ver como luce internamente la variable d1. Inténtalo. 29 | CorrectAnswer: unclass(d1) 30 | AnswerTests: omnitest(correctExpr='unclass(d1)') 31 | Hint: Utilice unclass(d1) para ver como es d1 internamente. 32 | 33 | - Class: text 34 | Output: Ese es el número exacto de días desde el 01/01/1970! 35 | 36 | - Class: cmd_question 37 | Output: in embargo, si imprime d1 en la consola, obtendrá la fecha de hoy en el formato AÑO-MES-DIA (Por defecto, cuando R imprime o recibe por parámetros las fechas, lo hace en el formato AÑO-MES-DIA). Dese una oportunidad. 38 | CorrectAnswer: d1 39 | AnswerTests: omnitest(correctExpr='d1') 40 | Hint: Escriba d1 para imprimir su contenido. 41 | 42 | - Class: cmd_question 43 | Output: ¿Qué pasa si tenemos que hacer referencia a una fecha anterior a 01/01/1970? Cree una variable d2 que contenga as.Date("1969-01-01"). 44 | CorrectAnswer: d2 <- as.Date("1969-01-01") 45 | AnswerTests: omnitest(correctExpr='d2 <- as.Date("1969-01-01")') 46 | Hint: Pruebe con d2 <- as.Date("1969-01-01"). 47 | 48 | - Class: cmd_question 49 | Output: Ahora utilice unclass() de nuevo para ver como se almacena d2 internamente. 50 | CorrectAnswer: unclass(d2) 51 | AnswerTests: omnitest(correctExpr='unclass(d2)') 52 | Hint: unclass(d2) le mostrará como d2 luce internamente. 53 | 54 | - Class: text 55 | Output: Como usted pudo haber esperado, se obtiene un número negativo. En este caso, es -365, dado que 01/01/1969 está exactamente a un año calendario (es decir, 365 días) antes de 01/01/1970. 56 | 57 | - Class: cmd_question 58 | Output: Ahora, vamos a echar un vistazo a cómo R almacena las horas. Puede acceder a la fecha y la hora actual usando la función Sys.time() sin argumentos. Haga esto y guarde el resultado en una variable llamada t1. 59 | CorrectAnswer: t1 <- Sys.time() 60 | AnswerTests: omnitest(correctExpr='t1 <- Sys.time()') 61 | Hint: t1 <- Sys.time() almacenará la fecha y la hora actual en una variable llamada t1. 62 | 63 | - Class: cmd_question 64 | Output: Vea el contenido de t1. 65 | CorrectAnswer: t1 66 | AnswerTests: omnitest(correctExpr='t1') 67 | Hint: Escriba t1 para ver su contenido. 68 | 69 | - Class: cmd_question 70 | Output: Y compruebe la clase de t1 con class(). 71 | CorrectAnswer: class(t1) 72 | AnswerTests: omnitest(correctExpr='class(t1)') 73 | Hint: Vea la clase de t1 con la class(t1). 74 | 75 | - Class: cmd_question 76 | Output: omo se mencionó anteriormente, POSIXct es sólo una de las dos formas en que R representa la información de tiempo. (Puede pasar por alto el segundo valor de arriba, POSIXt, que sólo funciona como un lenguaje común entre POSIXct y POSIXlt.) Utilice unclass() para ver lo que luce t1 internamente - el número grande son los segundos desde el comienzo de 1970. 77 | CorrectAnswer: unclass(t1) 78 | AnswerTests: omnitest(correctExpr='unclass(t1)') 79 | Hint: Utilice unclass(t1) para ver cuántos segundos han pasado desde el inicio de 1970. 80 | 81 | - Class: cmd_question 82 | Output: Por defecto, Sys.time() devuelve un objeto de la clase POSIXct, pero podemos convertir el resultado a POSIXlt con as.POSIXlt(Sys.time()). Dese una oportunidad y almacene el resultado en t2. 83 | CorrectAnswer: t2 <- as.POSIXlt(Sys.time()) 84 | AnswerTests: omnitest(correctExpr='t2 <- as.POSIXlt(Sys.time())') 85 | Hint: t2 <- as.POSIXlt(Sys.time()) convertirá el resultado de Sys.time a 'POSIXlt' y almacena el resultado en t2. 86 | 87 | - Class: cmd_question 88 | Output: Compruebe la clase de t2. 89 | CorrectAnswer: class(t2) 90 | AnswerTests: omnitest(correctExpr='class(t2)') 91 | Hint: Escriba class(t2) para ver su clase. 92 | 93 | - Class: cmd_question 94 | Output: Ahora vea su contenido. 95 | CorrectAnswer: t2 96 | AnswerTests: omnitest(correctExpr='t2') 97 | Hint: Escriba t2 para ver su contenido. 98 | 99 | - Class: cmd_question 100 | Output: El formato impreso de t2 es idéntico al de t1. Ahora escriba unclass(t2) para ver en qué se diferencian internamente. 101 | CorrectAnswer: unclass(t2) 102 | AnswerTests: omnitest(correctExpr='unclass(t2)') 103 | Hint: Utilice unclass(t2) para ver su estructura interna. 104 | 105 | - Class: cmd_question 106 | Output: t2, como todos los objetos POSIXlt, es sólo una lista de los valores que componen la fecha y la hora. Utilice str(unclass(t2)) para tener una visión más compacta. 107 | CorrectAnswer: str(unclass(t2)) 108 | AnswerTests: omnitest(correctExpr='str(unclass(t2))') 109 | Hint: Utilice str(unclass(t2)) para ver su estructura interna de una manera más compacta. 110 | 111 | - Class: cmd_question 112 | Output: Sí por ejemplo, queremos sólo los minutos de la hora almacenada en t2, podemos acceder a ellos con t2$min. Intentalo. 113 | CorrectAnswer: t2$min 114 | AnswerTests: omnitest(correctExpr='t2$min') 115 | Hint: t2$min le dará el número de minutos de la hora almacenada en t2. 116 | 117 | - Class: text 118 | Output: Ahora que hemos explorado los tres tipos de objetos de fecha y hora , echemos un vistazo a algunas funciones que extraen información útil de cualquiera de estos objetos -- weekdays(), months(), y quarters(). 119 | 120 | - Class: cmd_question 121 | Output: La función weekdays() devolverá el día de la semana de cualquier objeto de tipo fecha o hora. Pruébelo en d1, que es el objeto Date que contiene la fecha de hoy. 122 | CorrectAnswer: weekdays(d1) 123 | AnswerTests: omnitest(correctExpr='weekdays(d1)') 124 | Hint: Pruebe los días de weekdays(d1) para obtener el día de la semana. 125 | 126 | - Class: cmd_question 127 | Output: La función de los months() también funciona en cualquier objeto tipo fecha u hora. Pruébalo en t1, que es el objeto POSIXct que contiene la hora actual (bueno, era la hora actual cuando lo creó). 128 | CorrectAnswer: months(t1) 129 | AnswerTests: omnitest(correctExpr='months(t1)') 130 | Hint: months(t1) le dará el mes en curso. 131 | 132 | - Class: cmd_question 133 | Output: La función quarters() devuelve el trimestre del año (Q1-Q4) de cualquier objeto del tipo fecha u hora. Pruébalo en t2, que es el objeto POSIXlt que contiene la hora en la que se creó. 134 | CorrectAnswer: quarters(t2) 135 | AnswerTests: omnitest(correctExpr='quarters(t2)') 136 | Hint: quarters(t2) le dará el trimestre actual. 137 | 138 | - Class: text 139 | Output: A menudo, las fechas y horas en un conjunto de datos estarán en un formato que R no reconoce. La función strptime() puede ser útil en esta situación. 140 | 141 | - Class: text 142 | Output: strptime() convierte vectores de caracteres al formato POSIXlt. En ese sentido, es similar a as.POSIXlt(), excepto que la entrada no tiene que estar en un formato especial (AAAA-MM-DD). 143 | 144 | - Class: cmd_question 145 | Output: 'Para ver cómo funciona, almacene la cadena de caracteres siguiente en una variable llamada t3: "17 de octubre de 1986 08:24" (con las comillas).' 146 | CorrectAnswer: t3 <- "17 de octubre de 1986 08:24" 147 | AnswerTests: omnitest(correctExpr='t3 <- "17 de octubre de 1986 08:24"') 148 | Hint: Guarde "17 de octubre de 1986 08:24" (incluyendo las comillas) en una nueva variable llamada t3. 149 | 150 | - Class: cmd_question 151 | Output: 'Ahora, use strptime(t3, "%d de %B de %Y %H:%M") para ayudar a R a convertir nuestro objeto de fecha/hora a un formato que el pueda entender. Asigne el resultado de una nueva variable llamada t4. (Usted puede abrir la documentación para strptime() si quisiera saber más acerca de cómo funciona).' 152 | CorrectAnswer: t4 <- strptime(t3, "%d de %B de %Y %H:%M") 153 | AnswerTests: omnitest(correctExpr='t4 <- strptime(t3, "%d de %B de %Y %H:%M")') 154 | Hint: 't4 <- strptime(t3, "%d de %B de %Y %H:%M") convertirá nuestro objeto de fecha/hora a un formato que entiende R' 155 | 156 | - Class: cmd_question 157 | Output: Imprime el contenido de t4. 158 | CorrectAnswer: t4 159 | AnswerTests: omnitest(correctExpr='t4') 160 | Hint: Escriba t4 para imprimir su contenido. 161 | 162 | - Class: cmd_question 163 | Output: Este es el formato esperamos. Ahora, vamos a ver su clase con class(). 164 | CorrectAnswer: class(t4) 165 | AnswerTests: omnitest(correctExpr='class(t4)') 166 | Hint: Escribe class(t4) para comprobar su clase. 167 | 168 | - Class: text 169 | Output: Por último, hay una serie de operaciones que se pueden realizar en las fechas y horas, incluidas las operaciones aritméticas (+ y -) y las de comparaciones (<, ==, etc.) 170 | 171 | - Class: cmd_question 172 | Output: "La variable t1 contiene el tiempo en el que se creó (recordemos que utilizó Sys.time()) Confirme que ha pasado algún tiempo desde que creó t1 utilizando el operador 'mayor que' para compararlo con la hora actual. : Sys.time() > t1" 173 | CorrectAnswer: Sys.time() > t1 174 | AnswerTests: omnitest(correctExpr='Sys.time() > t1') 175 | Hint: Sys.time() > t1 le dirá que el momento actual es posterior de la hora que figura en t1 (que era la hora actual cuando lo creó). 176 | 177 | - Class: cmd_question 178 | Output: Así que sabemos que ha pasado algún tiempo, pero ¿cuánto? Trate restando t1 de la hora actual con Sys.time() - t1. No olvide los paréntesis al final de Sys.time(), ya que es una función. 179 | CorrectAnswer: Sys.time() - t1 180 | AnswerTests: omnitest(correctExpr='Sys.time() - t1') 181 | Hint: Sys.time() - t1 le dará la cantidad de tiempo que ha pasado desde que se creó t1. 182 | 183 | - Class: text 184 | Output: En la misma línea de pensamiento se aplica la suma y los otros operadores de comparación. Si desea más control sobre las unidades, al calcular la diferencia de tiempo anterior puede utilizar la función difftime(), la cual le permite especificar el parámetro 'units'. 185 | 186 | - Class: cmd_question 187 | Output: Use difftime(Sys.time(), t1, units = 'days') para encontrar la cantidad de tiempo en días que ha pasado desde que creó t1. 188 | CorrectAnswer: difftime(Sys.time(), t1, units = 'days') 189 | AnswerTests: match_call("difftime(Sys.time(), t1, units = 'days')") 190 | Hint: difftime(Sys.time(), t1, units = 'days') le dirá cuántos días han pasado desde que se creó t1 (que ojala que sea menos de 1!) 191 | 192 | - Class: text 193 | Output: En esta lección, ha aprendido a trabajar con fechas y horas en R. Si bien es importante comprender los fundamentos, si usted se encuentra trabajando con las fechas y horas a menudo, es posible que desee comprobar el paquete lubridate desarrollado por Hadley Wickham. 194 | 195 | 196 | -------------------------------------------------------------------------------- /Docker/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM rocker/rstudio:4.0.0 2 | 3 | ARG PASSWORD=curso 4 | ARG DISABLE_AUTH=true 5 | 6 | MAINTAINER "Jose R Sosa" josersosa@gmail.com 7 | 8 | RUN apt-get update \ 9 | && apt-get install -y --no-install-recommends \ 10 | zlib1g-dev \ 11 | && install2.r --error \ 12 | devtools \ 13 | swirl \ 14 | && R -e "swirl::install_course_github('josersosa','Programando_en_R')" 15 | 16 | #COPY .Rprofile /home/rstudio/ 17 | #RUN chown rstudio:rstudio /home/rstudio/.Rprofile 18 | -------------------------------------------------------------------------------- /Functions/customTests.R: -------------------------------------------------------------------------------- 1 | test_func1 <- function() { 2 | try({ 3 | func <- get('boring_function', globalenv()) 4 | t1 <- identical(func(9), 9) 5 | t2 <- identical(func(4), 4) 6 | t3 <- identical(func(0), 0) 7 | ok <- all(t1, t2, t3) 8 | }, silent = TRUE) 9 | exists('ok') && isTRUE(ok) 10 | } 11 | 12 | test_func2 <- function() { 13 | try({ 14 | func <- get('my_mean', globalenv()) 15 | t1 <- identical(func(9), mean(9)) 16 | t2 <- identical(func(1:10), mean(1:10)) 17 | t3 <- identical(func(c(-5, -2, 4, 10)), mean(c(-5, -2, 4, 10))) 18 | ok <- all(t1, t2, t3) 19 | }, silent = TRUE) 20 | exists('ok') && isTRUE(ok) 21 | } 22 | 23 | test_func3 <- function() { 24 | try({ 25 | func <- get('remainder', globalenv()) 26 | t1 <- identical(func(9, 4), 9 %% 4) 27 | t2 <- identical(func(divisor = 5, num = 2), 2 %% 5) 28 | t3 <- identical(func(5), 5 %% 2) 29 | ok <- all(t1, t2, t3) 30 | }, silent = TRUE) 31 | exists('ok') && isTRUE(ok) 32 | } 33 | 34 | test_func4 <- function() { 35 | try({ 36 | func <- get('evaluate', globalenv()) 37 | t1 <- identical(func(sum, c(2, 4, 7)), 13) 38 | t2 <- identical(func(median, c(9, 200, 100)), 100) 39 | t3 <- identical(func(floor, 12.1), 12) 40 | ok <- all(t1, t2, t3) 41 | }, silent = TRUE) 42 | exists('ok') && isTRUE(ok) 43 | } 44 | 45 | test_func5 <- function() { 46 | try({ 47 | func <- get('telegram', globalenv()) 48 | t1 <- identical(func("Good", "morning"), "START Good morning STOP") 49 | t2 <- identical(func("hello", "there", "sir"), "START hello there sir STOP") 50 | t3 <- identical(func(), "START STOP") 51 | ok <- all(t1, t2, t3) 52 | }, silent = TRUE) 53 | exists('ok') && isTRUE(ok) 54 | } 55 | 56 | test_func6 <- function() { 57 | try({ 58 | func <- get('mad_libs', globalenv()) 59 | t1 <- identical(func(lugar = "Baltimore", adjetivo = "smelly", sustantivo = "Roger Peng statue"), "Noticias desde Baltimore en la actualidad, donde los estudiantes smelly salieron a las calles en protesta por el nuevo Roger Peng statue que se está instalando en el campus.") 60 | t2 <- identical(func(lugar = "Washington", adjetivo = "angry", sustantivo = "Shake Shack"), "Noticias desde Washington en la actualidad, donde los estudiantes angry salieron a las calles en protesta por el nuevo Shake Shack que se está instalando en el campus.") 61 | ok <- all(t1, t2) 62 | }, silent = TRUE) 63 | exists('ok') && isTRUE(ok) 64 | } 65 | 66 | test_func7 <- function() { 67 | try({ 68 | func <- get('%p%', globalenv()) 69 | t1 <- identical(func("Good", "job!"), "Good job!") 70 | t2 <- identical(func("one", func("two", "three")), "one two three") 71 | ok <- all(t1, t2) 72 | }, silent = TRUE) 73 | exists('ok') && isTRUE(ok) 74 | } 75 | 76 | test_eval1 <- function(){ 77 | try({ 78 | e <- get("e", parent.frame()) 79 | expr <- e$expr 80 | t1 <- identical(expr[[3]], 6) 81 | expr[[3]] <- 7 82 | t2 <- identical(eval(expr), 8) 83 | ok <- all(t1, t2) 84 | }, silent = TRUE) 85 | exists('ok') && isTRUE(ok) 86 | } 87 | 88 | test_eval2 <- function(){ 89 | try({ 90 | e <- get("e", parent.frame()) 91 | expr <- e$expr 92 | t1 <- identical(expr[[3]], quote(c(8, 4, 0))) 93 | t2 <- identical(expr[[1]], quote(evaluate)) 94 | expr[[3]] <- c(5, 6) 95 | t3 <- identical(eval(expr), 5) 96 | ok <- all(t1, t2, t3) 97 | }, silent = TRUE) 98 | exists('ok') && isTRUE(ok) 99 | } 100 | 101 | test_eval3 <- function(){ 102 | try({ 103 | e <- get("e", parent.frame()) 104 | expr <- e$expr 105 | t1 <- identical(expr[[3]], quote(c(8, 4, 0))) 106 | t2 <- identical(expr[[1]], quote(evaluate)) 107 | expr[[3]] <- c(5, 6) 108 | t3 <- identical(eval(expr), 6) 109 | ok <- all(t1, t2, t3) 110 | }, silent = TRUE) 111 | exists('ok') && isTRUE(ok) 112 | } -------------------------------------------------------------------------------- /Functions/initLesson.R: -------------------------------------------------------------------------------- 1 | # Put initialization code in this file. 2 | -------------------------------------------------------------------------------- /Functions/scripts/bin_op.R: -------------------------------------------------------------------------------- 1 | # La sintaxis para la creación de nuevos operadores binarios en R es 2 | # diferente a todo lo demás en R, pero le permite definir una nueva 3 | # sintaxis en su función. Yo solo le recomendaría hacer su propio 4 | # operador binario si usted planea usarlo muy a menudo! 5 | # 6 | # Los operadores binarios definidos por el usuario tienen la siguiente 7 | # sintaxis: [lo que sea]% 8 | # Donde [lo que sea] representa cualquier nombre de variable válido. 9 | # 10 | # Digamos que quería definir un operador binario que multiplica dos números 11 | # y después se suma uno a el producto. Una implementación de este 12 | # operador es la siguiente: 13 | # 14 | # "%mult_add_one%" <- function(left, right){ # Observe las comillas! 15 | # left * right + 1 16 | # } 17 | # 18 | # Yo podría entonces utilizar este operador binario como `4 %mult_add_one% 5` que se 19 | # evaluaría en 21. 20 | # 21 | # Escriba su operador binario desde cero! Su operador 22 | # debe llamarse %p% de manera que la expresión: 23 | # 24 | # "Good" %p% "job!" 25 | # 26 | # Evaluará en: "Good job!" 27 | 28 | "%p%" <- function(){ # Remember to add arguments! 29 | 30 | } 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /Functions/scripts/boring_function-correct.R: -------------------------------------------------------------------------------- 1 | boring_function <- function(x) { 2 | x 3 | } 4 | -------------------------------------------------------------------------------- /Functions/scripts/boring_function.R: -------------------------------------------------------------------------------- 1 | # Estás a punto de escribir su primera función! Simplemente asigna un valor 2 | # valor a una variable con el operador de asignación, su función de 3 | # asignación puede ser de la siguiente forma: 4 | # 5 | # function_name <- function(arg1, arg2) { 6 | # # Manipular argumentos de alguna manera 7 | # # Devuelve un valor 8 | # } 9 | # 10 | # El "nombre de variable" que asigne asumirá el valor en el nombre de su 11 | # función. arg1 y arg2 representan los argumentos de la función. 12 | # Puede manipular los argumentos que especifique dentro de la función. 13 | # Después de codificar la función, la puede utilizar el escribiendo: 14 | # 15 | # function_name(valor1, valor2) 16 | # 17 | # A continuación vamos a crear una función llamada boring_function. 18 | # Esta función toma el argumento `x` como entrada y devuelve el valor 19 | # de x sin modificarlo. Elimine el símbolo de numeral frente a la x 20 | # para hacer funcionar la función! Asegúrate de guardar esta secuencia 21 | # de comandos y escriba submit() en la consola después de realizar y 22 | # salvar los cambios: 23 | 24 | boring_function <- function(x) { 25 | #x 26 | } 27 | -------------------------------------------------------------------------------- /Functions/scripts/evaluate.R: -------------------------------------------------------------------------------- 1 | # Se puede pasar funciones como argumentos a otras funciones al igual 2 | # que usted puede pasar datos a funciones. Digamos que usted define 3 | # las siguientes funciones: 4 | # 5 | # add_two_numbers <- function(num1, num2){ 6 | # num1 + num2 7 | # } 8 | # 9 | # multiply_two_numbers <- function(num1, num2){ 10 | # num1 * num2 11 | # } 12 | # 13 | # some_function <- function(func){ 14 | # func(2, 4) 15 | # } 16 | # 17 | # Como se puede ver se utiliza el nombre de argumento "func" como una 18 | # función dentro de "some_function()." Al pasar funciones como argumentos 19 | # some_function(add_two_numbers) se evaluará en 6, mientras que 20 | # some_function(multiply_two_numbers) se evaluará en 8. 21 | # 22 | # Finalize la definición de la función de abajo de modo que si una función 23 | # se pasa en el argumento "func" y algunos datos (como un vector) se 24 | # pasan al argumento dat, la función evaluate() devolverá el resultado 25 | # de func al que se le pasa argumento dat . 26 | # 27 | # Sugerencias: Este ejercicio es un poco difícil así que le voy a dar 28 | # algunos ejemplos de cómo evaluate() debe actuar: 29 | # 1. evaluate(sum, c(2, 4, 6)) se debe evaluar en 12 30 | # 2. evaluate(median, c(7, 40, 9)) se debe evaluar en 9 31 | # 3. evaluate(floor, 11.1) se debe evaluar en 11 32 | 33 | evaluate <- function(func, dat){ 34 |   # Escriba su código aquí! 35 |   # Recuerde: la última expresión evaluada será el valor devuelto por la función! 36 | } 37 | -------------------------------------------------------------------------------- /Functions/scripts/mad_libs.R: -------------------------------------------------------------------------------- 1 | # Vamos a explorar cómo "desempaquetar" los argumentos de una elipsis 2 | # cuando se utiliza como un argumento en una función. A continuación 3 | # tengo una función de ejemplo donde se supone que se sumarán los dos 4 | # argumentos con nombre explícitamente llamados alfa y beta. 5 | # 6 | # add_alpha_and_beta <- function(...){ 7 | # # En primer lugar tenemos que capturar los puntos suspensivos en el 8 | # # interior de una lista y luego asignar la lista a una variable. 9 | # # Nombraremos a esta variable `args`. 10 | # 11 | # args <- list(...) 12 | # 13 | # # Vamos ahora va a suponer que hay dos argumentos con nombre dentro 14 | # # de args con los llamados `alpha` y` beta.` Podemos extraer los 15 | # # argumentos con nombre de la lista args utilizado el nombre del 16 | # # argumento y los dobles corchetes. Las variables `args` son 17 | # # simplemente una lista normal después de todo! 18 | # 19 | # alpha <- args[["alpha"]] 20 | # beta <- args[["beta"]] 21 | # 22 | # # Entonces, retornamos la suma de alfa y beta. 23 | # 24 | # alpha + beta 25 | # } 26 | # 27 | # ¿Alguna vez has usado Mad Libs antes? La función de abajo construye una 28 | # frase a partir partes del discurso que usted debe proporcionar como 29 | # argumentos. Escribí la mayor parte de la función, pero tendrás que 30 | # desempaquetar los argumentos adecuados de la elipsis . 31 | 32 | mad_libs <- function(...){ 33 |   # Haga el desempaquetado de su argumento aquí! 34 |    35 |   # No modifique ningún código debajo de este comentario. 36 |   # Tenga en cuenta las variables que se necesitan en orden, para hacer que el 37 |   # código de abajo sea funcional! 38 | paste("Noticias desde", lugar, "en la actualidad, donde los estudiantes", adjetivo, "salieron a las calles en protesta por el nuevo", sustantivo, "que se está instalando en el campus.") 39 | } 40 | 41 | -------------------------------------------------------------------------------- /Functions/scripts/my_mean.R: -------------------------------------------------------------------------------- 1 | # Usted es libre de implementar la función my_mean de la forma que desee, 2 | # siempre y cuando devuelva el promedio de todos los números en 3 | # contenidos en `my_vector`. 4 | # 5 | # Sugerencia #1: sum() devuelve la suma de un vector. 6 | # Ejemplo: suma(c(1, 2, 3)) evalúa en 6 7 | # 8 | # Sugerencia #2: length() devuelve el tamaño de un vector. 9 | # Ejemplo: length(c(1, 2, 3)) se evalúa como 3 10 | # 11 | # Sugerencia #3: La media de todos los números en un vector es igual a 12 | # la suma de todos los números en el vector dividido por el tamaño del 13 | # vector. 14 | # 15 | # Nota para que usted se sienta súper inteligente: Por favor, no use 16 | # la función mean() al escribir esta función. Estamos tratando de 17 | # enseñarte algo ¡Aquí! 18 | # 19 | # Asegúrese de guardar este script y escriba submit() en la consola 20 | # después de guardar sus cambios. 21 | 22 | my_mean <- function(my_vector) { 23 |   # Escriba su código aquí! 24 |   # Recuerde: la última expresión evaluada será el valor devuelto! 25 | } 26 | -------------------------------------------------------------------------------- /Functions/scripts/remainder.R: -------------------------------------------------------------------------------- 1 | # Déjame mostrarte un ejemplo de una función que voy a comenzar llamado 2 | # increment(). La mayoría de las veces vamos a querer utilizar esta 3 | # función para aumentar el valor del número por uno. Esta función 4 | # llevará a dos argumentos: "number" y "by" donde "number" es el dígito 5 | # que queremos incrementar y "by" es la cantidad por la que queremos 6 | # incrementar a "number". Para esto hemos escrito la siguiente función. 7 | # 8 | # increment <- function(number, by = 1){ 9 | # number + by 10 | # } 11 | # 12 | # Si usted echa un vistazo entre los paréntesis se puede ver que hemos 13 | # establecido "by" igual a 1. Esto significa que el argumento "by" 14 | # tendrá un valor predeterminado de 1. 15 | # 16 | # Ahora podemos usar la función increment, sin proporcionar un valor 17 | # para "by": increment(5) se evaluará en 6. 18 | # 19 | # Sin embargo si queremos ofrecer un valor para el argumento "by", 20 | # todavía se puede! la expresión: increment(5, 2) se evaluarán en 7. 21 | # 22 | # Usted debe a escribir una función llamada "remainder". remainder() 23 | # se tomará dos argumentos: "num" y "divisor", donde "num" será dividido 24 | # por "divisor" y se devuelve el reciduo de la divición entera. Imagina 25 | # que por lo general quiere saber el reciduo cuando se divide por 2, por 26 | # lo que establece el valor por defecto de "divisor" a 2. Por favor, 27 | # asegúrese de que "num" es el primer argumento y "divisor" es el segundo 28 | # argumento. 29 | # 30 | # Sugerencia # 1: Puede utilizar el operador módulo %% para encontrar el 31 | # reciduo de la división. 32 | # Ej: 7 %% 4 se evalúa en 3. 33 | # 34 | # Recuerde que debe establecer los valores predeterminados apropiados! 35 | # Asegúrese de guardar este script y escriba de submit() en la consola 36 | # después de escribir la función. 37 | 38 | remainder <- function(num, divisor) { 39 | # Escriba su código aquí! 40 | # Recuerde: la última expresión evaluada será el valor devuelto! 41 | } 42 | -------------------------------------------------------------------------------- /Functions/scripts/telegram.R: -------------------------------------------------------------------------------- 1 | # Los puntos suspensivos se pueden utilizar para transmitir argumentos a 2 | # otras funciones que esten dentro de la función que estémos escribiendo. 3 | # Por lo general, una función que tiene la elipsis como un argumento, la 4 | # tiene como el último argumento. El uso de tal función se vería así: 5 | # 6 | # ellipses_func (arg1, arg2 = TRUE, ...) 7 | # 8 | # En el ejemplo anterior arg1 no tiene ningún valor por defecto, por lo 9 | # que su valor debe ser proporcionado en la llamada a la función, arg2 10 | # tiene un valor por defecto, los otros argumentos puede venir después 11 | # de arg2 dependiendo de cómo estén definidos en la documentación de 12 | # ellipses_func(). Interesante es la definición de la función paste() 13 | # como vemos a continuación: 14 | # 15 | # paste(..., sep = " ", collapse = NULL) 16 | # 17 | # Tenga en cuenta que los puntos suspensivos son el primer argumento, y 18 | # todos los demás argumentos que vienen después de las elipsis tienen 19 | # valores por defecto. Esta es una regla estricta en la programación de 20 | # R: todos los argumentos después de una elipsis deben tener valores 21 | # predeterminados. Eche un vistazo a la función simon_says a continuación: 22 | # 23 | # simon_says <- function(...){ 24 | # paste("Simon says:", ...) 25 | # } 26 | # 27 | # La función simon_says funciona igual que la función de paste, excepto 28 | # que eal comienzo de cada cadena se le antepone la cadena "Simón dice:" 29 | # 30 | # Los telegramas solían ser modificados con las palabras de START y STOP 31 | # con el fin de demarcan el comienzo y el final de las oraciones. 32 | # Escriba a continuación una función llamada telegram que dé formato al 33 | # texto del telegrama. Por ejemplo, la expresión 34 | # `telegram("Good", "morning")` 35 | # debe evaluarse como: "START Good morning STOP" 36 | 37 | telegram <- function(...){ 38 | 39 | } 40 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | 203 | -------------------------------------------------------------------------------- /Logic/customTests.R: -------------------------------------------------------------------------------- 1 | notify <- function() { 2 | e <- get("e", parent.frame()) 3 | if(e$val == "No") return(TRUE) 4 | 5 | good <- FALSE 6 | while(!good) { 7 | # Get info 8 | name <- readline_clean("What is your full name? ") 9 | address <- readline_clean("What is the email address of the person you'd like to notify? ") 10 | 11 | # Repeat back to them 12 | message("\nDoes everything look good?\n") 13 | message("Your name: ", name, "\n", "Send to: ", address) 14 | 15 | yn <- select.list(c("Yes", "No"), graphics = FALSE) 16 | if(yn == "Yes") good <- TRUE 17 | } 18 | 19 | # Get course and lesson names 20 | course_name <- attr(e$les, "course_name") 21 | lesson_name <- attr(e$les, "lesson_name") 22 | 23 | subject <- paste(name, "just completed", course_name, "-", lesson_name) 24 | body = "" 25 | 26 | # Send email 27 | swirl:::email(address, subject, body) 28 | 29 | hrule() 30 | message("I just tried to create a new email with the following info:\n") 31 | message("To: ", address) 32 | message("Subject: ", subject) 33 | message("Body: ") 34 | 35 | message("\nIf it didn't work, you can send the same email manually.") 36 | hrule() 37 | 38 | # Return TRUE to satisfy swirl and return to course menu 39 | TRUE 40 | } 41 | 42 | readline_clean <- function(prompt = "") { 43 | wrapped <- strwrap(prompt, width = getOption("width") - 2) 44 | mes <- stringr::str_c("| ", wrapped, collapse = "\n") 45 | message(mes) 46 | readline() 47 | } 48 | 49 | hrule <- function() { 50 | message("\n", paste0(rep("#", getOption("width") - 2), collapse = ""), "\n") 51 | } 52 | -------------------------------------------------------------------------------- /Looking_at_Data/customTests.R: -------------------------------------------------------------------------------- 1 | # So swirl does not repeat execution of commands 2 | # AUTO_DETECT_NEWVAR <- FALSE 3 | 4 | expr_creates_var <- function(correctName=NULL){ 5 | e <- get("e", parent.frame()) 6 | # TODO: Eventually make auto-detection of new variables an option. 7 | # Currently it can be set in customTests.R 8 | delta <- if(!customTests$AUTO_DETECT_NEWVAR){ 9 | safeEval(e$expr, e) 10 | } else { 11 | e$delta 12 | } 13 | if(is.null(correctName)){ 14 | results <- expectThat(length(delta) >= 1, 15 | testthat::is_true(), 16 | label=paste(deparse(e$expr), 17 | "does not create a variable.")) 18 | } else { 19 | results <- expectThat(correctName %in% names(delta), 20 | testthat::is_true(), 21 | label=paste(deparse(e$expr), 22 | "does not create a variable named", 23 | correctName)) 24 | } 25 | if(results$passed){ 26 | e$newVar <- e$val 27 | e$newVarName <- names(delta)[1] 28 | e$delta <- mergeLists(delta, e$delta) 29 | } else { 30 | e$delta <- list() 31 | } 32 | return(results$passed) 33 | } 34 | 35 | # Returns TRUE if the user has calculated a value equal to that calculated by the given expression. 36 | calculates_same_value <- function(expr){ 37 | e <- get("e", parent.frame()) 38 | # Calculate what the user should have done. 39 | eSnap <- cleanEnv(e$snapshot) 40 | val <- eval(parse(text=expr), eSnap) 41 | passed <- isTRUE(all.equal(val, e$val)) 42 | if(!passed)e$delta <- list() 43 | return(passed) 44 | } 45 | 46 | omnitest <- function(correctExpr=NULL, correctVal=NULL, strict=FALSE){ 47 | e <- get("e", parent.frame()) 48 | # Trivial case 49 | if(is.null(correctExpr) && is.null(correctVal))return(TRUE) 50 | # Testing for correct expression only 51 | if(!is.null(correctExpr) && is.null(correctVal)){ 52 | passed <- expr_identical_to(correctExpr) 53 | if(!passed)e$delta <- list() 54 | return(passed) 55 | } 56 | # Testing for both correct expression and correct value 57 | # Value must be character or single number 58 | valGood <- NULL 59 | if(!is.null(correctVal)){ 60 | if(is.character(e$val)){ 61 | valResults <- expectThat(e$val, 62 | is_equivalent_to(correctVal, label=correctVal), 63 | label=(e$val)) 64 | if(is(e, "dev") && !valResults$passed)swirl_out(valResults$message) 65 | valGood <- valResults$passed 66 | # valGood <- val_matches(correctVal) 67 | } else if(!is.na(e$val) && is.numeric(e$val) && length(e$val) == 1){ 68 | cval <- try(as.numeric(correctVal), silent=TRUE) 69 | valResults <- expectThat(e$val, 70 | equals(cval, label=correctVal), 71 | label=toString(e$val)) 72 | if(is(e, "dev") && !valResults$passed)swirl_out(valResults$message) 73 | valGood <- valResults$passed 74 | } 75 | } 76 | exprGood <- ifelse(is.null(correctExpr), TRUE, expr_identical_to(correctExpr)) 77 | if(valGood && exprGood){ 78 | return(TRUE) 79 | } else if (valGood && !exprGood && !strict){ 80 | swirl_out("That's not the expression I expected but it works.") 81 | swirl_out("I've executed the correct expression in case the result is needed in an upcoming question.") 82 | eval(parse(text=correctExpr),globalenv()) 83 | return(TRUE) 84 | } else { 85 | e$delta <- list() 86 | return(FALSE) 87 | } 88 | } 89 | 90 | match_call <- function(correct_call = NULL) { 91 | e <- get("e", parent.frame()) 92 | # Trivial case 93 | if(is.null(correct_call)) return(TRUE) 94 | # Get full correct call 95 | full_correct_call <- expand_call(correct_call) 96 | # Expand user's expression 97 | expr <- deparse(e$expr) 98 | full_user_expr <- expand_call(expr) 99 | # Compare function calls with full arg names 100 | identical(full_correct_call, full_user_expr) 101 | } 102 | 103 | # Utility function for match_call answer test 104 | # Fills out a function call with full argument names 105 | expand_call <- function(call_string) { 106 | # Quote expression 107 | qcall <- parse(text=call_string)[[1]] 108 | # If expression is not greater than length 1... 109 | if(length(qcall) <= 1) return(qcall) 110 | # See if it's an assignment 111 | is_assign <- is(qcall, "<-") 112 | # If assignment, process righthandside 113 | if(is_assign) { 114 | # Get righthand side 115 | rhs <- qcall[[3]] 116 | # If righthand side is not a call, can't use match.fun() 117 | if(!is.call(rhs)) return(qcall) 118 | # Get function from function name 119 | fun <- match.fun(rhs[[1]]) 120 | # match.call() does not support primitive functions 121 | if(is.primitive(fun)) return(qcall) 122 | # Get expanded call 123 | full_rhs <- match.call(fun, rhs) 124 | # Full call 125 | qcall[[3]] <- full_rhs 126 | } else { # If not assignment, process whole thing 127 | # Get function from function name 128 | fun <- match.fun(qcall[[1]]) 129 | # match.call() does not support primitive functions 130 | if(is.primitive(fun)) return(qcall) 131 | # Full call 132 | qcall <- match.call(fun, qcall) 133 | } 134 | # Return expanded function call 135 | qcall 136 | } 137 | 138 | # Returns TRUE if e$expr matches any of the expressions given 139 | # (as characters) in the argument. 140 | ANY_of_exprs <- function(...){ 141 | e <- get("e", parent.frame()) 142 | any(sapply(c(...), function(expr)omnitest(expr))) 143 | } 144 | 145 | 146 | 147 | notify <- function() { 148 | e <- get("e", parent.frame()) 149 | if(e$val == "No") return(TRUE) 150 | 151 | good <- FALSE 152 | while(!good) { 153 | # Get info 154 | name <- readline_clean("What is your full name? ") 155 | address <- readline_clean("What is the email address of the person you'd like to notify? ") 156 | 157 | # Repeat back to them 158 | message("\nDoes everything look good?\n") 159 | message("Your name: ", name, "\n", "Send to: ", address) 160 | 161 | yn <- select.list(c("Yes", "No"), graphics = FALSE) 162 | if(yn == "Yes") good <- TRUE 163 | } 164 | 165 | # Get course and lesson names 166 | course_name <- attr(e$les, "course_name") 167 | lesson_name <- attr(e$les, "lesson_name") 168 | 169 | subject <- paste(name, "just completed", course_name, "-", lesson_name) 170 | body = "" 171 | 172 | # Send email 173 | swirl:::email(address, subject, body) 174 | 175 | hrule() 176 | message("I just tried to create a new email with the following info:\n") 177 | message("To: ", address) 178 | message("Subject: ", subject) 179 | message("Body: ") 180 | 181 | message("\nIf it didn't work, you can send the same email manually.") 182 | hrule() 183 | 184 | # Return TRUE to satisfy swirl and return to course menu 185 | TRUE 186 | } 187 | 188 | readline_clean <- function(prompt = "") { 189 | wrapped <- strwrap(prompt, width = getOption("width") - 2) 190 | mes <- stringr::str_c("| ", wrapped, collapse = "\n") 191 | message(mes) 192 | readline() 193 | } 194 | 195 | hrule <- function() { 196 | message("\n", paste0(rep("#", getOption("width") - 2), collapse = ""), "\n") 197 | } 198 | -------------------------------------------------------------------------------- /Looking_at_Data/initLesson.R: -------------------------------------------------------------------------------- 1 | # Path to data 2 | .datapath <- file.path(path.package('swirl'), 'Courses', 3 | 'Programando_en_R', 'Looking_at_Data', 4 | 'plant-data.txt') 5 | # Read in data 6 | plants <- read.csv(.datapath, strip.white=TRUE, na.strings="") 7 | 8 | # Remove annoying columns 9 | .cols2rm <- c('Accepted.Symbol', 'Synonym.Symbol') 10 | plants <- plants[, !(names(plants) %in% .cols2rm)] 11 | 12 | # Make names pretty 13 | names(plants) <- c('Scientific_Name', 'Duration', 'Active_Growth_Period', 14 | 'Foliage_Color', 'pH_Min', 'pH_Max', 15 | 'Precip_Min', 'Precip_Max', 16 | 'Shade_Tolerance', 'Temp_Min_F') -------------------------------------------------------------------------------- /Looking_at_Data/lesson.yaml: -------------------------------------------------------------------------------- 1 | - Class: meta 2 | Course: Programando en R 3 | Lesson: Mirando en los Datos 4 | Author: Nick Carchedi 5 | Type: Standard 6 | Organization: JHU Biostat 7 | Version: 2.2.11 8 | 9 | - Class: text 10 | Output: Cada vez que usted está trabajando con un nuevo conjunto de datos, lo primero que debe hacer es mirarlo! ¿Cuál es el formato de los datos? ¿Cuáles son las dimensiones? ¿Cuáles son los nombres de las variables? ¿Cómo se almacenan las variables? ¿Existen datos que faltan? ¿Hay errores en los datos? 11 | 12 | - Class: text 13 | Output: Esta lección le enseñará cómo responder a estas preguntas y más sobre uso funciones incorporadas de R. Vamos a estar usando un conjunto de datos construido a partir de la base de datos del Departamento de Plantas Agrícolas de los Estados Unidos (http://plants.usda.gov/adv_search.html). 14 | 15 | - Class: cmd_question 16 | Output: He almacenado los datos para usted en una variable llamada plants. Escriba ls() para listar las variables en el espacio de trabajo, entre los cuales debe aparecer plants. 17 | CorrectAnswer: ls() 18 | AnswerTests: omnitest(correctExpr='ls()') 19 | Hint: Utilice el comando ls() para desplegar las variables creadas en el espacio de trabajo. 20 | 21 | - Class: cmd_question 22 | Output: Empecemos por por verificar la clase de la variable plants con class(plants). Esto nos dará una idea de la estructura general de los datos. 23 | CorrectAnswer: class(plants) 24 | AnswerTests: omnitest(correctExpr='class(plants)') 25 | Hint: Utilice la class(plants) para comprobar la clase de la variable plants. 26 | 27 | - Class: text 28 | Output: Es muy común que los datos se almacenen en una trama de datos (data.frame). Esta es la clase predeterminada para los datos leídos en R utilizando funciones como read.csv() y read.table(), sobre las cuales aprenderemos en otra lección. 29 | 30 | - Class: cmd_question 31 | Output: Dado que el conjunto de datos se almacena en una trama de datos, sabemos que debe ser es rectangular. En otras palabras, tiene dos dimensiones (filas y columnas) y encaja perfectamente en una tabla u hoja de cálculo. Utilice dim(plants) para ver exactamente con cuántas filas y columnas estamos tratando. 32 | CorrectAnswer: dim(plants) 33 | AnswerTests: omnitest(correctExpr='dim(plants)') 34 | Hint: Utilice dim(plants) para ver las dimensiones exactas del conjunto de datos de las plants. 35 | 36 | - Class: text 37 | Output: El primer número que se ve (5166) es el número de filas (observaciones) y el segundo número (10) es el número de columnas (variables). 38 | 39 | - Class: cmd_question 40 | Output: También puede utilizar nrow(plants) para ver sólo el número de filas. Inténtalo. 41 | CorrectAnswer: nrow(plants) 42 | AnswerTests: omnitest(correctExpr='nrow(plants)') 43 | Hint: Utilice nrow(plants) para ver sólo el número de filas. 44 | 45 | - Class: cmd_question 46 | Output: ... Y ncol(plants) para ver sólo el número de columnas. 47 | CorrectAnswer: ncol(plants) 48 | AnswerTests: omnitest(correctExpr='ncol(plants)') 49 | Hint: Utilice ncol(plants) para ver sólo el número de columnas. 50 | 51 | - Class: cmd_question 52 | Output: Si usted es curioso en cuanto a la cantidad de espacio del conjunto de datos está ocupando en la memoria, puede utilizar object.size(plants). 53 | AnswerTests: omnitest(correctExpr='object.size(plants)') 54 | Hint: object.size(plants) le dirá la cantidad de memoria ocupada por la trama de datos plants. 55 | 56 | - Class: cmd_question 57 | Output: Ahora que sabemos forma y tamaño del conjunto de datos, vamos a tener una idea de lo que hay dentro. names(plants) devolverá un vector de caracteres con los nombres de las columnas (es decir, variables). Intentalo. 58 | CorrectAnswer: names(plants) 59 | AnswerTests: omnitest(correctExpr='names(plants)') 60 | Hint: names(plants) volverán un vector carácter de nombres de columna (es decir, variables). 61 | 62 | - Class: text 63 | Output: Hemos aplicado unos nombres de variables bastante descriptivos para este conjunto de datos, pero no siempre será así. Un siguiente paso lógico es dar un vistazo a los datos reales. Sin embargo, nuestra base de datos contiene más de 5.000 observaciones (filas), así que es poco práctico ver toda la tabla a la vez. 64 | 65 | - Class: cmd_question 66 | Output: La función head() le permite hacer una vista previa de la parte superior del conjunto de datos. Dese la oportunidad con un solo argumento. 67 | CorrectAnswer: head(plants) 68 | AnswerTests: omnitest(correctExpr='head(plants)') 69 | Hint: head(plants) le mostrará la parte superior del conjunto de datos. 70 | 71 | - Class: text 72 | Output: Tome un minuto para mirar el resultado y entender la salida anterior. Cada fila se etiqueta con el número de observación y cada columna con el nombre de la variable. Es probable que su pantalla no sea lo suficientemente amplia como para ver las 10 columnas de lado a lado, en cuyo caso R muestra tantas columnas como pueda en cada línea antes de continuar al siguiente. 73 | 74 | - Class: cmd_question 75 | Output: Por defecto, la función head() muestra las primeras seis filas de los datos. Puede modificar este comportamiento al pasar como segundo argumento el número de filas que desea ver. Use la head() para obtener una vista previa de las primeras 10 filas de plantas. 76 | CorrectAnswer: head(plants, 10) 77 | AnswerTests: omnitest(correctExpr='head(plants, 10)') 78 | Hint: head(plants, 10) le mostrará las primeras 10 filas del conjunto de datos. 79 | 80 | - Class: cmd_question 81 | Output: Lo mismo se aplica en el uso de la función tail() para obtener una vista previa del final del conjunto de datos. Utilice tail() para ver las últimas 15 filas. 82 | CorrectAnswer: tail(plants, 15) 83 | AnswerTests: omnitest(correctExpr='tail(plants, 15)') 84 | Hint: tail(plants, 15) le mostrará las últimoas 15 filas del conjunto de datos. 85 | 86 | - Class: cmd_question 87 | Output: Después de la vista previa de la parte superior e inferior de los datos, usted probablemente ha notado un montón de NAs, que son los marcadores de posición de R para los valores perdidos. Use summary(plants) para obtener una mejor idea de cómo se distribuye cada variable y que tanto de la base de datos no se encuentra. 88 | CorrectAnswer: summary(plants) 89 | AnswerTests: omnitest(correctExpr='summary(plants)') 90 | Hint: Pruebe summary(plants) para ver cómo se distribuye cada variable y cuantos valores perdidos tiene nuestra base de datos. 91 | 92 | - Class: text 93 | Output: summary() proporciona una salida diferente para cada variable, dependiendo de su clase. Para los datos numéricos como Precip_Min, summary() muestra el mínimo, primer cuartil, la mediana, la media, el tercer cuartil, y el máximo. Estos valores nos ayudan a entender cómo se distribuyen los datos. 94 | 95 | - Class: text 96 | Output: Para las variables categóricas (llamadas variables "factor" en R), summary() muestra el número de veces que cada valor (o "nivel") se produce en los datos. Por ejemplo, cada valor de Scientific_Name sólo aparece una vez, ya que es única para una planta específica. Por el contrario, el resumen de Duration (también una variable de factor) nos dice que nuestro conjunto de datos contiene 3031 plantas perennes, 682 plantas anuales, etc. 97 | 98 | - Class: cmd_question 99 | Output: Se puede ver que R trunca el resumen para Active_Growth_Period incluyendo una nueva categoría denominada "Other". Dado que es una variable categórica / Factor, podemos ver cuántas veces cada valor realmente ocurre en los datos con table(plants$Active_Growth_Period). 100 | CorrectAnswer: table(plants$Active_Growth_Period) 101 | AnswerTests: omnitest(correctExpr='table(plants$Active_Growth_Period)') 102 | Hint: table(plants$Active_Growth_Period) mostrará los recuentos para cada nivel de la variable de factor. 103 | 104 | - Class: text 105 | Output: Cada una de las funciones que hemos introducido hasta el momento tiene su utilidad para ayudar a entender mejor la estructura de los datos. Sin embargo, hemos dejado lo mejor para lo último ... 106 | 107 | - Class: cmd_question 108 | Output: Quizás la función más útil y concisa para la comprensión de la estructura de sus datos es str (E*str*uctura). Dese una oportunidad ahora. 109 | CorrectAnswer: str(plants) 110 | AnswerTests: omnitest(correctExpr='str(plants)') 111 | Hint: Utilice str(plants) para observar la estructura de sus datos. 112 | 113 | - Class: text 114 | Output: La belleza de str() es que combina muchas de las características de las otras funciones que ya has visto, todo ello en un formato conciso y fácil de leer. En la parte superior, se nos dice que la clase de las plantas es 'data.frame' y que cuenta con 5166 observaciones y 10 variables. A continuación, nos da el nombre y la categoría de cada variable, así como una vista previa de su contenido. 115 | 116 | - Class: text 117 | Output: str() es en realidad una función muy general que se puede utilizar en la mayoría de los objetos en R. Cada vez que usted quiere entender la estructura de algo (un conjunto de datos, función, etc.), str() es un buen modo para comenzar. 118 | 119 | - Class: text 120 | Output: En esta lección, ha aprendido a tener una idea de la estructura y contenido de un nuevo conjunto de datos utilizando una colección de funciones simples y útiles. Tomarse el tiempo para hacer esto por adelantado puede ahorrarle tiempo y frustración más tarde durante su análisis. 121 | 122 | 123 | -------------------------------------------------------------------------------- /MANIFEST: -------------------------------------------------------------------------------- 1 | Basic_Building_Blocks 2 | Workspace_and_Files 3 | Sequences_of_Numbers 4 | Vectors 5 | Missing_Values 6 | Subsetting_Vectors 7 | Matrices_and_Data_Frames 8 | Logic 9 | Functions 10 | lapply_and_sapply 11 | vapply_and_tapply 12 | Looking_at_Data 13 | Simulation 14 | Dates_and_Times 15 | Base_Graphics 16 | -------------------------------------------------------------------------------- /Matrices_and_Data_Frames/customTests.R: -------------------------------------------------------------------------------- 1 | notify <- function() { 2 | e <- get("e", parent.frame()) 3 | if(e$val == "No") return(TRUE) 4 | 5 | good <- FALSE 6 | while(!good) { 7 | # Get info 8 | name <- readline_clean("What is your full name? ") 9 | address <- readline_clean("What is the email address of the person you'd like to notify? ") 10 | 11 | # Repeat back to them 12 | message("\nDoes everything look good?\n") 13 | message("Your name: ", name, "\n", "Send to: ", address) 14 | 15 | yn <- select.list(c("Yes", "No"), graphics = FALSE) 16 | if(yn == "Yes") good <- TRUE 17 | } 18 | 19 | # Get course and lesson names 20 | course_name <- attr(e$les, "course_name") 21 | lesson_name <- attr(e$les, "lesson_name") 22 | 23 | subject <- paste(name, "just completed", course_name, "-", lesson_name) 24 | body = "" 25 | 26 | # Send email 27 | swirl:::email(address, subject, body) 28 | 29 | hrule() 30 | message("I just tried to create a new email with the following info:\n") 31 | message("To: ", address) 32 | message("Subject: ", subject) 33 | message("Body: ") 34 | 35 | message("\nIf it didn't work, you can send the same email manually.") 36 | hrule() 37 | 38 | # Return TRUE to satisfy swirl and return to course menu 39 | TRUE 40 | } 41 | 42 | readline_clean <- function(prompt = "") { 43 | wrapped <- strwrap(prompt, width = getOption("width") - 2) 44 | mes <- stringr::str_c("| ", wrapped, collapse = "\n") 45 | message(mes) 46 | readline() 47 | } 48 | 49 | hrule <- function() { 50 | message("\n", paste0(rep("#", getOption("width") - 2), collapse = ""), "\n") 51 | } 52 | -------------------------------------------------------------------------------- /Matrices_and_Data_Frames/initLesson.R: -------------------------------------------------------------------------------- 1 | # Put initialization code in this file. The variables you create 2 | # here will show up in the user's workspace when he or she begins 3 | # the lesson. 4 | -------------------------------------------------------------------------------- /Matrices_and_Data_Frames/lesson.yaml: -------------------------------------------------------------------------------- 1 | - Class: meta 2 | Course: Programando en R 3 | Lesson: Matrices y tablas de datos 4 | Author: Nick Carchedi 5 | Type: Standard 6 | Organization: JHU Biostat 7 | Version: 2.2.0 8 | 9 | - Class: text 10 | Output: En esta lección, vamos a cubrir las matrices y tablas tramas de datos. Ambos representan los tipos de datos "rectangulares", lo que significa que se utilizan para almacenar datos tabulares, con filas y columnas. 11 | 12 | - Class: text 13 | Output: La principal diferencia, como se verá, es que las matrices sólo pueden contener una sola clase de datos, mientras que las tramas de datos o data frames pueden consistir en muchas clases diferentes de datos. 14 | 15 | - Class: cmd_question 16 | Output: Vamos a crear un vector que contiene los números del 1 al 20 con el operador `:`. Almacene el resultado en una variable llamada my_vector. 17 | CorrectAnswer: my_vector <- 1:20 18 | AnswerTests: omnitest(correctExpr='my_vector <- 1:20') 19 | Hint: Usted aprendió acerca de la operador `:` en la lección sobre secuencias. Si desea crear un vector que contiene los números 1, 2 y 3 (en ese orden), se puede utilizar tanto c(1, 2, 3) como 1:3. En este caso, queremos que los números del 1 al 20, almacenados en una variable llamada my_vector. Además, recuerde que usted no necesita la función c() cuando utilice `:`. 20 | 21 | - Class: cmd_question 22 | Output: Vea el contenido del vector que acaba de crear. 23 | CorrectAnswer: my_vector 24 | AnswerTests: omnitest(correctExpr='my_vector') 25 | Hint: Simplemente escriba my_vector para ver su contenido. 26 | 27 | - Class: cmd_question 28 | Output: La función dim() nos dice las "dimensiones" de un objeto. ¿Qué sucede si usamos dim(my_vector)? Dese una oportunidad. 29 | CorrectAnswer: dim(my_vector) 30 | AnswerTests: omnitest(correctExpr='dim(my_vector)') 31 | Hint: Sólo tienes que escribir dim(my_vector) para ver qué pasa. 32 | 33 | - Class: cmd_question 34 | Output: Claramente, eso no es muy útil! Dado que my_vector es un vector, no tiene un atributo `dim` (por lo que es sólo NULL), pero podemos obtener su longitud usando la función length(). Trate de eso ahora. 35 | CorrectAnswer: length(my_vector) 36 | AnswerTests: omnitest(correctExpr='length(my_vector)') 37 | Hint: Escriba length(my_vector) para ver la longitud del vector que acaba de crear. 38 | 39 | - Class: cmd_question 40 | Output: Ah! Eso es lo que queríamos. Pero, ¿qué pasa si le damos a my_vector un atributo `dim`? Hagamos un intento. Escriba dim(my_vector) <- c(4, 5). 41 | CorrectAnswer: dim(my_vector) <- c(4, 5) 42 | AnswerTests: omnitest(correctExpr='dim(my_vector) <- c(4, 5)') 43 | Hint: Escriba dim(my_vector) <- c(4, 5) para dar a my_vector un atributo `dim`. 44 | 45 | - Class: text 46 | Output: Está bien si ese último comando le pareció un poco extraño. ¡Debería! La función dim() le permite obtener o establecer el atributo `dim` para un objeto en R. En este caso, asignamos el valor c(4, 5) para el atributo `dim` de my_vector. 47 | 48 | - Class: cmd_question 49 | Output: Utilice dim(my_vector) para confirmar que hemos establecido correctamente el atributo `dim`. 50 | CorrectAnswer: dim(my_vector) 51 | AnswerTests: omnitest(correctExpr='dim(my_vector)') 52 | Hint: Sólo tienes que escribir dim(my_vector) para asegurarse de que el atributo `dim` se ha establecido. 53 | 54 | - Class: cmd_question 55 | Output: Otra forma de ver esto es llamando a función attributes() sobre my_vector. Inténtalo ahora. 56 | CorrectAnswer: attributes(my_vector) 57 | AnswerTests: omnitest(correctExpr='attributes(my_vector)') 58 | Hint: El comando attributes(my_vector) te mostrará todos los atributos para el objeto my_vector. 59 | 60 | - Class: text 61 | Output: Al igual que en la clase de matemáticas, cuando se trata de un objeto de 2 dimensiones (piense en una mesa rectangular), el primer número es el número de filas y el segundo es el número de columnas. Por lo tanto, asignamos a my_vector 4 filas y 5 columnas. 62 | 63 | - Class: cmd_question 64 | Output: Pero, espera! Eso no suena como que siga siendo un vector. Bueno, no lo es. Ahora es una matriz. Ver el contenido de my_vector ahora para ver lo que parece. 65 | CorrectAnswer: my_vector 66 | AnswerTests: omnitest(correctExpr='my_vector') 67 | Hint: Escriba my_vector para ver su contenido. 68 | 69 | - Class: cmd_question 70 | Output: Ahora, vamos a confirmar que en realidad es una matriz mediante el uso de la función class(). Escriba class(my_vector) para ver lo que quiero decir. 71 | CorrectAnswer: class(my_vector) 72 | AnswerTests: omnitest(correctExpr='class(my_vector)') 73 | Hint: Escriba class(my_vector) para ver la clase de my_vector. 74 | 75 | - Class: cmd_question 76 | Output: Efectivamente, my_vector es ahora una matriz. Deberíamos almacenarlo en una nueva variable que nos ayude a recordar lo que es. Almacene el valor de my_vector en una nueva variable llamada my_matrix. 77 | CorrectAnswer: my_matrix <- my_vector 78 | AnswerTests: omnitest(correctExpr='my_matrix <- my_vector') 79 | Hint: Puesto que no podemos simplemente cambiar el nombre de nuestra variable my_vector, le asignaremos su valor a una nueva variable con my_matrix <- my_vector. 80 | 81 | - Class: text 82 | Output: El ejemplo que hemos utilizado hasta ahora estaba destinado a ilustrar el punto de que una matriz es simplemente un vector atómico con un atributo de dimensión. Un método más directo de la creación de la misma matriz utiliza la función de matrix(). 83 | 84 | - Class: cmd_question 85 | Output: Abra el archivo de ayuda para la función de matrix() ahora usando la función `?`. 86 | CorrectAnswer: ?matrix 87 | AnswerTests: omnitest(correctExpr='?matrix') 88 | Hint: El comando ?matrix hará el truco. 89 | 90 | - Class: cmd_question 91 | Output: Ahora, mira la documentación para la función matrix y vea si puede encontrar la manera de crear una matriz que contenga los mismos números (1-20) y dimensiones (4 filas, 5 columnas) llamando a la función de matrix(). Almacene el resultado en una variable llamada my_matrix2. 92 | CorrectAnswer: my_matrix2 <- matrix(1:20, nrow=4, ncol=5) 93 | AnswerTests: calculates_same_value('matrix(1:20, nrow=4, ncol=5)'); expr_creates_var('my_matrix2') 94 | Hint: Llame a la función de matrix() con tres argumentos -- 1:20, el número de filas y el número de columnas. Asegúrese de especificar los argumentos por su nombre y guardar el resultado en my_matrix2 (no en my_matrix). 95 | 96 | - Class: cmd_question 97 | Output: Por último, vamos a confirmar que my_matrix y my_matrix2 son en realidad idénticos. La función identical() nos dirá si sus dos primeros argumentos son los mismos. Inténtalo. 98 | CorrectAnswer: identical(my_matrix, my_matrix2) 99 | AnswerTests: any_of_exprs('identical(my_matrix, my_matrix2)', 'identical(my_matrix2, my_matrix)') 100 | Hint: Si no está seguro acerca de esto, entonces la revice de la documentación de identical() utilizando la función `?`. 101 | 102 | - Class: text 103 | Output: Ahora, imagine que los números en la tabla representan algunas medidas de un experimento clínico, donde cada fila representa un paciente y cada columna representa una variable para la que se tomaron mediciones. 104 | 105 | - Class: text 106 | Output: Podemos querer etiquetar las filas, para que sepamos qué números pertenecen a cada paciente en el experimento. Una forma de hacer esto es agregar una columna a la matriz, que contiene los nombres de las cuatro personas. 107 | 108 | - Class: cmd_question 109 | Output: Vamos a empezar por la creación de un vector de caracteres que contenga los nombres de nuestros pacientes - Bill, Gina, Kelly, y Sean. Recuerde que las comillas dobles dicen a R que algo es una cadena de caracteres. Almacene el resultado en la variable llamada patients. 110 | CorrectAnswer: patients <- c("Bill", "Gina", "Kelly", "Sean") 111 | AnswerTests: omnitest(correctExpr='patients <- c("Bill", "Gina", "Kelly", "Sean")') 112 | Hint: Asegúrese de capitalizar la primera letra de cada nombre y guarde el resultado en la variable llamada patients. Además, no altere el orden de los pacientes! Eso sería un desastre! 113 | 114 | - Class: cmd_question 115 | Output: Ahora vamos a utilizar la función cbind() para 'combinar columnas'. No te preocupes por guardar el resultado en una nueva variable. Sólo tiene que llamar cbind() con dos argumentos - el vector patients y my_matrix. 116 | CorrectAnswer: cbind(patients, my_matrix) 117 | AnswerTests: omnitest(correctExpr='cbind(patients, my_matrix)') 118 | Hint: Escriba cbind(patients, my_matrix) para añadir los nombres de nuestros pacientes a la matriz de números. 119 | 120 | - Class: text 121 | Output: Algo no huele bien sobre nuestro resultado! Parece que la combinación del vector de caracteres con nuestra matriz de números causó que todo quedara entre comillas dobles. Esto significa que nos quedamos con una matriz de cadenas de caracteres, lo que no es bueno. 122 | 123 | - Class: text 124 | Output: Si usted recuerda, al principio de esta lección, te dije que las matrices sólo pueden contener una clase de datos. Por lo tanto, cuando tratamos de combinar un vector de caracteres con una matriz numérica, R se vio obligado a 'coaccionar' los números a caracteres, de ahí las comillas dobles. 125 | 126 | - Class: text 127 | Output: Esto se llama "la coerción implícita ', porque no lo pedimos. Esto simplemente sucedió. Pero ¿por qué R no convirtió los nombres de nuestros pacientes a números? Voy a dejar que usted que reflexione sobre este asunto por su cuenta. 128 | 129 | - Class: cmd_question 130 | Output: Por lo tanto, estamos todavía en la cuestión de cómo incluir los nombres de nuestros pacientes en la tabla, sin destruir la integridad de nuestros datos numéricos. Pruebe lo siguiente -- my_data <- data.frame(patients, my_matrix) 131 | CorrectAnswer: my_data <- data.frame(patients, my_matrix) 132 | AnswerTests: omnitest(correctExpr='my_data <- data.frame(patients, my_matrix)') 133 | Hint: Escriba my_data <- data.frame(patients, my_matrix), para lo que podamos explorar lo que sucede. 134 | 135 | - Class: cmd_question 136 | Output: Ahora vea el contenido de my_data para ver a lo que hemos llegado. 137 | CorrectAnswer: my_data 138 | AnswerTests: omnitest(correctExpr='my_data') 139 | Hint: Escriba my_data para ver su contenido. 140 | 141 | - Class: text 142 | Output: Parece que la función data.frame() nos permitió guardar nuestro vector de caracteres de los nombres justo al lado de nuestra matriz de números. Eso es exactamente lo que esperábamos! 143 | 144 | - Class: text 145 | Output: Detrás de las escenas, la función data.frame() toma cualquier número de argumentos y devuelve un único objeto de la clase `data.frame` que se compone de los objetos originales. 146 | 147 | - Class: cmd_question 148 | Output: Vamos a confirmar esto llamando a la función de class() en nuestro recien creado data frame. 149 | CorrectAnswer: class(my_data) 150 | AnswerTests: omnitest(correctExpr='class(my_data)') 151 | Hint: La función class() toma un argumento - el objeto del cual se desea determinar su clase. 152 | 153 | - Class: text 154 | Output: También es posible asignar nombres a las filas individuales y columnas de una trama de datos (data frame), que presenta otra posible forma de determinar qué fila de valores en nuestra tabla pertenece a cada paciente. 155 | 156 | - Class: text 157 | Output: Sin embargo, puesto que ya hemos resuelto ese problema, vamos a resolver un problema diferente, que es asignar nombres a las columnas de nuestra tabla de datos para que sepamos qué tipo de medición representa cada columna. 158 | 159 | - Class: cmd_question 160 | Output: Dado que tenemos seis columnas (incluyendo nombres de los pacientes), tendremos que crear primero un vector que contenga un elemento para cada columna. Crearemos un vector de caracteres llamado cnames que contenga los valores siguientes (en orden) -- "patient", "age", "weight", "bp", "rating", "test". 161 | CorrectAnswer: cnames <- c("patient", "age", "weight", "bp", "rating", "test") 162 | AnswerTests: omnitest(correctExpr='cnames <- c("patient", "age", "weight", "bp", "rating", "test")') 163 | Hint: Asegúrese de que todos los nombres están en minúsculas, encerrados por comillas dobles y separados por comas. No te olvides de usar la función c(). 164 | 165 | - Class: cmd_question 166 | Output: Ahora, utilice la funcion colnames() para establecer el atributo `colnames` para nuestra tabla de datos o data frame. Esto es similar a la forma en que usamos la función dim() anteriormente en esta lección. 167 | CorrectAnswer: colnames(my_data) <- cnames 168 | AnswerTests: omnitest(correctExpr='colnames(my_data) <- cnames') 169 | Hint: Pruebe colnames(my_data) <- cnames. 170 | 171 | - Class: cmd_question 172 | Output: Veamos si el trabajo esta hecho. Imprima el contenido de my_data. 173 | CorrectAnswer: my_data 174 | AnswerTests: omnitest(correctExpr='my_data') 175 | Hint: Imprime el contenido de my_data en la consola. 176 | 177 | - Class: text 178 | Output: En esta lección, usted aprendió lo básico de trabajar con dos estructuras de datos muy importantes y comunes en R -- matrices y tablas de datos. Hay mucho más que aprender y vamos a estar cubriendo temas más avanzados, particularmente con respecto a las tablas de datos, en las lecciones futuras. 179 | 180 | 181 | -------------------------------------------------------------------------------- /Missing_Values/customTests.R: -------------------------------------------------------------------------------- 1 | # So swirl does not repeat execution of commands 2 | # AUTO_DETECT_NEWVAR <- FALSE 3 | 4 | expr_creates_var <- function(correctName=NULL){ 5 | e <- get("e", parent.frame()) 6 | # TODO: Eventually make auto-detection of new variables an option. 7 | # Currently it can be set in customTests.R 8 | delta <- if(!customTests$AUTO_DETECT_NEWVAR){ 9 | safeEval(e$expr, e) 10 | } else { 11 | e$delta 12 | } 13 | if(is.null(correctName)){ 14 | results <- expectThat(length(delta) >= 1, 15 | testthat::is_true(), 16 | label=paste(deparse(e$expr), 17 | "does not create a variable.")) 18 | } else { 19 | results <- expectThat(correctName %in% names(delta), 20 | testthat::is_true(), 21 | label=paste(deparse(e$expr), 22 | "does not create a variable named", 23 | correctName)) 24 | } 25 | if(results$passed){ 26 | e$newVar <- e$val 27 | e$newVarName <- names(delta)[1] 28 | e$delta <- mergeLists(delta, e$delta) 29 | } else { 30 | e$delta <- list() 31 | } 32 | return(results$passed) 33 | } 34 | 35 | # Returns TRUE if the user has calculated a value equal to that calculated by the given expression. 36 | calculates_same_value <- function(expr){ 37 | e <- get("e", parent.frame()) 38 | # Calculate what the user should have done. 39 | eSnap <- cleanEnv(e$snapshot) 40 | val <- eval(parse(text=expr), eSnap) 41 | passed <- isTRUE(all.equal(val, e$val)) 42 | if(!passed)e$delta <- list() 43 | return(passed) 44 | } 45 | 46 | omnitest <- function(correctExpr=NULL, correctVal=NULL, strict=FALSE){ 47 | e <- get("e", parent.frame()) 48 | # Trivial case 49 | if(is.null(correctExpr) && is.null(correctVal))return(TRUE) 50 | # Testing for correct expression only 51 | if(!is.null(correctExpr) && is.null(correctVal)){ 52 | passed <- expr_identical_to(correctExpr) 53 | if(!passed)e$delta <- list() 54 | return(passed) 55 | } 56 | # Testing for both correct expression and correct value 57 | # Value must be character or single number 58 | valGood <- NULL 59 | if(!is.null(correctVal)){ 60 | if(is.character(e$val)){ 61 | valResults <- expectThat(e$val, 62 | is_equivalent_to(correctVal, label=correctVal), 63 | label=(e$val)) 64 | if(is(e, "dev") && !valResults$passed)swirl_out(valResults$message) 65 | valGood <- valResults$passed 66 | # valGood <- val_matches(correctVal) 67 | } else if(!is.na(e$val) && is.numeric(e$val) && length(e$val) == 1){ 68 | cval <- try(as.numeric(correctVal), silent=TRUE) 69 | valResults <- expectThat(e$val, 70 | equals(cval, label=correctVal), 71 | label=toString(e$val)) 72 | if(is(e, "dev") && !valResults$passed)swirl_out(valResults$message) 73 | valGood <- valResults$passed 74 | } 75 | } 76 | exprGood <- ifelse(is.null(correctExpr), TRUE, expr_identical_to(correctExpr)) 77 | if(valGood && exprGood){ 78 | return(TRUE) 79 | } else if (valGood && !exprGood && !strict){ 80 | swirl_out("That's not the expression I expected but it works.") 81 | swirl_out("I've executed the correct expression in case the result is needed in an upcoming question.") 82 | eval(parse(text=correctExpr),globalenv()) 83 | return(TRUE) 84 | } else { 85 | e$delta <- list() 86 | return(FALSE) 87 | } 88 | } 89 | 90 | match_call <- function(correct_call = NULL) { 91 | e <- get("e", parent.frame()) 92 | # Trivial case 93 | if(is.null(correct_call)) return(TRUE) 94 | # Get full correct call 95 | full_correct_call <- expand_call(correct_call) 96 | # Expand user's expression 97 | expr <- deparse(e$expr) 98 | full_user_expr <- expand_call(expr) 99 | # Compare function calls with full arg names 100 | identical(full_correct_call, full_user_expr) 101 | } 102 | 103 | # Utility function for match_call answer test 104 | # Fills out a function call with full argument names 105 | expand_call <- function(call_string) { 106 | # Quote expression 107 | qcall <- parse(text=call_string)[[1]] 108 | # If expression is not greater than length 1... 109 | if(length(qcall) <= 1) return(qcall) 110 | # See if it's an assignment 111 | is_assign <- is(qcall, "<-") 112 | # If assignment, process righthandside 113 | if(is_assign) { 114 | # Get righthand side 115 | rhs <- qcall[[3]] 116 | # If righthand side is not a call, can't use match.fun() 117 | if(!is.call(rhs)) return(qcall) 118 | # Get function from function name 119 | fun <- match.fun(rhs[[1]]) 120 | # match.call() does not support primitive functions 121 | if(is.primitive(fun)) return(qcall) 122 | # Get expanded call 123 | full_rhs <- match.call(fun, rhs) 124 | # Full call 125 | qcall[[3]] <- full_rhs 126 | } else { # If not assignment, process whole thing 127 | # Get function from function name 128 | fun <- match.fun(qcall[[1]]) 129 | # match.call() does not support primitive functions 130 | if(is.primitive(fun)) return(qcall) 131 | # Full call 132 | qcall <- match.call(fun, qcall) 133 | } 134 | # Return expanded function call 135 | qcall 136 | } 137 | 138 | # Returns TRUE if e$expr matches any of the expressions given 139 | # (as characters) in the argument. 140 | ANY_of_exprs <- function(...){ 141 | e <- get("e", parent.frame()) 142 | any(sapply(c(...), function(expr)omnitest(expr))) 143 | } 144 | 145 | 146 | 147 | notify <- function() { 148 | e <- get("e", parent.frame()) 149 | if(e$val == "No") return(TRUE) 150 | 151 | good <- FALSE 152 | while(!good) { 153 | # Get info 154 | name <- readline_clean("What is your full name? ") 155 | address <- readline_clean("What is the email address of the person you'd like to notify? ") 156 | 157 | # Repeat back to them 158 | message("\nDoes everything look good?\n") 159 | message("Your name: ", name, "\n", "Send to: ", address) 160 | 161 | yn <- select.list(c("Yes", "No"), graphics = FALSE) 162 | if(yn == "Yes") good <- TRUE 163 | } 164 | 165 | # Get course and lesson names 166 | course_name <- attr(e$les, "course_name") 167 | lesson_name <- attr(e$les, "lesson_name") 168 | 169 | subject <- paste(name, "just completed", course_name, "-", lesson_name) 170 | body = "" 171 | 172 | # Send email 173 | swirl:::email(address, subject, body) 174 | 175 | hrule() 176 | message("I just tried to create a new email with the following info:\n") 177 | message("To: ", address) 178 | message("Subject: ", subject) 179 | message("Body: ") 180 | 181 | message("\nIf it didn't work, you can send the same email manually.") 182 | hrule() 183 | 184 | # Return TRUE to satisfy swirl and return to course menu 185 | TRUE 186 | } 187 | 188 | readline_clean <- function(prompt = "") { 189 | wrapped <- strwrap(prompt, width = getOption("width") - 2) 190 | mes <- stringr::str_c("| ", wrapped, collapse = "\n") 191 | message(mes) 192 | readline() 193 | } 194 | 195 | hrule <- function() { 196 | message("\n", paste0(rep("#", getOption("width") - 2), collapse = ""), "\n") 197 | } 198 | -------------------------------------------------------------------------------- /Missing_Values/initLesson.R: -------------------------------------------------------------------------------- 1 | # Put initialization code in this file. The variables you create 2 | # here will show up in the user's workspace when he or she begins 3 | # the lesson. 4 | -------------------------------------------------------------------------------- /Missing_Values/lesson.yaml: -------------------------------------------------------------------------------- 1 | - Class: meta 2 | Course: Programando en R 3 | Lesson: Missing Values 4 | Author: Nick Carchedi 5 | Type: Standard 6 | Organization: JHU Biostat 7 | Version: 2.2.0 8 | 9 | - Class: text 10 | Output: Los valores faltantes juegan un papel importante en las estadísticas y análisis de datos. A menudo, los valores perdidos no deben ser ignoradas, sino que deben ser estudiados cuidadosamente para ver si hay un patrón subyacente o causa para su falta. 11 | 12 | - Class: text 13 | Output: En R, NA se utiliza para representar cualquier valor que es "no disponible" o "perdido" (en el sentido estadístico). En esta lección, vamos a explorar los valores que faltan más. 14 | 15 | - Class: cmd_question 16 | Output: Cualquier operación que implique algún NA generalmente produce como resultado NA. Para ilustrar esto, vamos a crear un vector c(44, NA, 5, NA) y asignarlo a una variable x. 17 | CorrectAnswer: x <- c(44, NA, 5, NA) 18 | AnswerTests: omnitest(correctExpr='x <- c(44, NA, 5, NA)') 19 | Hint: Asigne el vector c(44, NA, 5, NA) a una variable x. La NA debe estar en mayúsculas. 20 | 21 | - Class: cmd_question 22 | Output: Ahora, vamos a multiplicar x por 3. 23 | CorrectAnswer: x * 3 24 | AnswerTests: ANY_of_exprs('x * 3', '3 * x') 25 | Hint: Pruebe x * 3. 26 | 27 | - Class: text 28 | Output: Observe que los elementos del vector resultante que se corresponden con los valores de NA en x son también NA. 29 | 30 | - Class: cmd_question 31 | Output: Para hacer las cosas un poco más interesante, vamos a crear un vector que contiene 1000 sorteos de una distribución normal estándar (media en 0 y desviación estándar en 1) con y <- rnorm(1000). 32 | CorrectAnswer: y <- rnorm(1000) 33 | AnswerTests: omnitest(correctExpr='y <- rnorm(1000)') 34 | Hint: La función rnorm() genera números aleatorios de una distribución normal. Escriba y <- rnorm(1000). 35 | 36 | - Class: cmd_question 37 | Output: A continuación, vamos a crear un vector que contiene 1000 NAs con z <- rep(NA, 1000). 38 | CorrectAnswer: z <- rep(NA, 1000) 39 | AnswerTests: omnitest(correctExpr='z <- rep(NA, 1000)') 40 | Hint: Escriba z <- rep(NA, 1000) para generar un vector de 1000 NAs. 41 | 42 | - Class: cmd_question 43 | Output: Por último, vamos a seleccionar 100 elementos al azar de estos 2000 valores (combinando y, z) de modo que no sabemos con cuántos NA vamos a terminar o qué posiciones van a ocupar en nuestro vector final -- my_data <- sample(c(y, z), 100). 44 | CorrectAnswer: my_data <- sample(c(y, z), 100) 45 | AnswerTests: omnitest(correctExpr='my_data <- sample(c(y, z), 100)') 46 | Hint: La función de sample() genera una muestra aleatoria de los datos facilitados como primer argumento (en este caso c (y, z)) del tamaño especificado por el segundo argumento (100). El comando my_data <- sample(c(y, z), 100) nos dará lo que queremos. 47 | 48 | - Class: cmd_question 49 | Output: Primero vamos a hacer la pregunta de dónde se encuentran los NA en nuestros datos. La función is.na() nos dice si cada elemento de un vector es NA. Llame a is.na() en my_data y asigne el resultado a my_na. 50 | CorrectAnswer: my_na <- is.na(my_data) 51 | AnswerTests: omnitest(correctExpr='my_na <- is.na(my_data)') 52 | Hint: Asigne el resultado de is.na(my_data) a la variable my_na. 53 | 54 | - Class: cmd_question 55 | Output: Ahora, imprima my_na para ver lo que le ocurrió. 56 | CorrectAnswer: my_na 57 | AnswerTests: omnitest(correctExpr='my_na') 58 | Hint: Escriba my_na para ver su contenido. 59 | 60 | - Class: text 61 | Output: En todas partes donde se ve un TRUE, se sabes el elemento correspondiente de my_data es NA. Del mismo modo, en todas partes se ve un FALSE, ya sabes el elemento correspondiente de my_data es uno de nuestros sorteos al azar de la distribución normal estándar. 62 | 63 | - Class: cmd_question 64 | Output: En nuestra discusión previa de los operadores lógicos, introdujimos el operador `==` como un método de prueba para la igualdad entre dos objetos. Así, se podría pensar que la expresión my_data == NA produce los mismos resultados que is.na(). Dese una oportunidad. 65 | CorrectAnswer: my_data == NA 66 | AnswerTests: omnitest(correctExpr='my_data == NA') 67 | Hint: Pruebe my_data == NA para ver qué pasa. 68 | 69 | - Class: text 70 | Output: La razón por la que recibió un vector de todos sus valores en NAs es que NA no es realmente un valor, es sólo un marcador de posición para una cantidad que no está disponible. Por lo tanto la expresión lógica esta incompleta y R no tiene más remedio que volver un vector de la misma longitud que my_data que contiene solo NAs. 71 | 72 | - Class: text 73 | Output: No se preocupe si eso es un poco confuso. La conclusión clave es ser cauteloso al usar expresiones lógicas, en cualquier momento un NA podría colarse, recuerde que un solo valor NA puede descarrilar toda la operación. 74 | 75 | - Class: text 76 | Output: Así que, volviendo a la tarea en cuestión. Ahora que tenemos un vector my_na, que tiene una verdad para cada NA y FALSE para cada valor numérico, podemos calcular el número total de NAs en nuestros datos. 77 | 78 | - Class: text 79 | Output: El truco es reconocer que debajo de la superficie, R representa TRUE como el número 1 y FALSE como el número 0. Por lo tanto, si tomamos la suma de un montón de TRUEs y FALSEs, obtenemos el número total de TRUEs. 80 | 81 | - Class: cmd_question 82 | Output: Vamos a hacer una prueba aquí. Llame a la función sum() en my_na para contar el número total de TRUEs en my_na, y por lo tanto el número total de NAs en my_data. No asigne el resultado de una nueva variable. 83 | CorrectAnswer: sum(my_na) 84 | AnswerTests: omnitest(correctExpr='sum(my_na)') 85 | Hint: Utilice sum(my_na) para contar el número de NAs en los datos. 86 | 87 | - Class: cmd_question 88 | Output: Bastante bien, ¿eh? Por último, vamos a echar un vistazo a los datos para convencernos de que todo 'suma'. Imprimir my_data en la consola. 89 | CorrectAnswer: my_data 90 | AnswerTests: omnitest(correctExpr='my_data') 91 | Hint: Imprimir my_data a la consola. 92 | 93 | - Class: cmd_question 94 | Output: Ahora que tenemos los NA al dedillo, echemos un vistazo a un segundo tipo de valor faltante, el NaN, que significa 'no es un número ". Para generar NaN, intente dividir (utilizando una barra inclinada) 0 entre 0 ahora. 95 | CorrectAnswer: 0/0 96 | AnswerTests: omnitest(correctExpr='0/0') 97 | Hint: Intente 0/0. 98 | 99 | - Class: cmd_question 100 | Output: Vamos a hacer una más, sólo por diversión. En R, Inf significa infinito. ¿Qué sucede si se resta de Inf de Inf? 101 | CorrectAnswer: Inf - Inf 102 | AnswerTests: omnitest(correctExpr='Inf - Inf') 103 | Hint: Escriba Inf - Inf. ¿Puedes adivinar el resultado? 104 | 105 | 106 | 107 | -------------------------------------------------------------------------------- /Programando_en_R.Rproj: -------------------------------------------------------------------------------- 1 | Version: 1.0 2 | 3 | RestoreWorkspace: Default 4 | SaveWorkspace: Default 5 | AlwaysSaveHistory: Default 6 | 7 | EnableCodeIndexing: Yes 8 | UseSpacesForTab: Yes 9 | NumSpacesForTab: 2 10 | Encoding: UTF-8 11 | 12 | RnwWeave: Sweave 13 | LaTeX: pdfLaTeX 14 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Programando en R 2 | 3 | Traducción al español del curso [R_Programming_Alt](https://github.com/swirldev/swirl_courses/tree/master/R_Programming_Alt) de [swirl](http://swirlstats.com/) sobre fundamentos de la programación en R. 4 | 5 | **Descripción** 6 | 7 | El paquete de R [swirl](http://swirlstats.com/)("Learn R, in R") permite crear cursos interactivos que se ejecutan desde la propia consola de R, por lo cual el estudiante puede ejecutar la instrucciiones directamente en R en la medida que avanza su curso. Existen varios cursor en el [repositorio de swirl](https://github.com/swirldev/swirl_courses), pero todos están en ingles. 8 | 9 | **Objetivo** 10 | 11 | El objetivo de este proyecto es disponer un curso interactivo sobre los fundamentos de la programación en R, en el idioma español para aquellos hispanohablantes interesados en aprender este lenguaje de programación. Para esto se traducirá el curso [R_Programming_Alt](https://github.com/swirldev/swirl_courses/tree/master/R_Programming_Alt). 12 | 13 | **Prerrequisitos** 14 | 15 | Para acceder a este curso debes tener instalado el [R](https://cran.rstudio.com/), y preferiblemente [Rstudio](https://www.rstudio.com/products/rstudio/download/), así como el paquete [swirl](http://swirlstats.com/). Puedes instalarlo desde la consola de R así: 16 | 17 | ```{r} 18 | install.packages('swirl') 19 | ``` 20 | 21 | **¿Como ejecutar el curso?** 22 | 23 | Para realizar este curso debemos primero instalarlo desde su repositorio en github en la consola de R, así: 24 | 25 | ```{r} 26 | library(swirl) 27 | install_course_github('josersosa','Programando_en_R') 28 | ``` 29 | 30 | He preparado un script ([instalar_curso.R](https://raw.githubusercontent.com/josersosa/Programando_en_R/master/instalar_curso.R)) para instalar este paquete junto con sus dependencias, en el caso de que no estén ya instaladas. También instala el curso y configura el idioma al español. 31 | 32 | Luego lo iniciamos con: 33 | 34 | ```{r} 35 | swirl() 36 | ``` 37 | 38 | Al comienzo nos solicita un nombre para identificarnos y almacenar los avances que hagamos en el caso que deseemos pausar el curso. Las primeras informaciones estan en ingles porque provienen del paquete swirl. Luego seleccionamos el curso _Programando en R_ y a partir de ahí todo lo esencial estará traducido. Las últimas versiones de swirl incluyen una función para seleccionar el idioma, que pdemos utilizar para que los mensajes del sistema estén en español: 39 | 40 | ```{r} 41 | select_language(language = "spanish") 42 | ``` 43 | 44 | Por último, cuando hayamos terminado, podemos desinstalar el curso con: 45 | 46 | ```{r} 47 | uninstall_course("Programando_en_R") 48 | ``` 49 | 50 | 51 | **Avance del proyecto** 52 | 53 | Hasta ahora, este proyecto tiene una avance del **100%** en la traducción. Están traducidas todas las lecciones de un total de las 12 del curso original [R_Programming_Alt](https://github.com/swirldev/swirl_courses/tree/master/R_Programming_Alt). 54 | Ya se han incluido la lecciones extraspara hacer nuestro curso en español un poco más completo: 55 | - Workspace_and_Files. 56 | - Functions. 57 | - Base_Graphics. Se incluyó la función barplot y algunos comentarios 58 | 59 | **TODOs** 60 | 61 | Reconfigurar los directoris con los títulos en español. 62 | 63 | Incluir las lecciones del curso [R Programming](https://github.com/swirldev/swirl_courses/tree/master/R_Programming) de swirl para hacer nuestro curso en español un poco más completo: 64 | - Workspace_and_Files. 65 | - Functions. 66 | - Base_Graphics. 67 | 68 | Por otra parte, intentaré incluir al final de cada lección, aparte del envío del correo, la opción de calificar mediante una conección a alguna aula virtual basada en moodle. 69 | 70 | -------------------------------------------------------------------------------- /Sequences_of_Numbers/customTests.R: -------------------------------------------------------------------------------- 1 | # So swirl does not repeat execution of commands 2 | # AUTO_DETECT_NEWVAR <- FALSE 3 | 4 | expr_creates_var <- function(correctName=NULL){ 5 | e <- get("e", parent.frame()) 6 | # TODO: Eventually make auto-detection of new variables an option. 7 | # Currently it can be set in customTests.R 8 | delta <- if(!customTests$AUTO_DETECT_NEWVAR){ 9 | safeEval(e$expr, e) 10 | } else { 11 | e$delta 12 | } 13 | if(is.null(correctName)){ 14 | results <- expectThat(length(delta) >= 1, 15 | testthat::is_true(), 16 | label=paste(deparse(e$expr), 17 | "does not create a variable.")) 18 | } else { 19 | results <- expectThat(correctName %in% names(delta), 20 | testthat::is_true(), 21 | label=paste(deparse(e$expr), 22 | "does not create a variable named", 23 | correctName)) 24 | } 25 | if(results$passed){ 26 | e$newVar <- e$val 27 | e$newVarName <- names(delta)[1] 28 | e$delta <- mergeLists(delta, e$delta) 29 | } else { 30 | e$delta <- list() 31 | } 32 | return(results$passed) 33 | } 34 | 35 | # Returns TRUE if the user has calculated a value equal to that calculated by the given expression. 36 | calculates_same_value <- function(expr){ 37 | e <- get("e", parent.frame()) 38 | # Calculate what the user should have done. 39 | eSnap <- cleanEnv(e$snapshot) 40 | val <- eval(parse(text=expr), eSnap) 41 | passed <- isTRUE(all.equal(val, e$val)) 42 | if(!passed)e$delta <- list() 43 | return(passed) 44 | } 45 | 46 | omnitest <- function(correctExpr=NULL, correctVal=NULL, strict=FALSE){ 47 | e <- get("e", parent.frame()) 48 | # Trivial case 49 | if(is.null(correctExpr) && is.null(correctVal))return(TRUE) 50 | # Testing for correct expression only 51 | if(!is.null(correctExpr) && is.null(correctVal)){ 52 | passed <- expr_identical_to(correctExpr) 53 | if(!passed)e$delta <- list() 54 | return(passed) 55 | } 56 | # Testing for both correct expression and correct value 57 | # Value must be character or single number 58 | valGood <- NULL 59 | if(!is.null(correctVal)){ 60 | if(is.character(e$val)){ 61 | valResults <- expectThat(e$val, 62 | is_equivalent_to(correctVal, label=correctVal), 63 | label=(e$val)) 64 | if(is(e, "dev") && !valResults$passed)swirl_out(valResults$message) 65 | valGood <- valResults$passed 66 | # valGood <- val_matches(correctVal) 67 | } else if(!is.na(e$val) && is.numeric(e$val) && length(e$val) == 1){ 68 | cval <- try(as.numeric(correctVal), silent=TRUE) 69 | valResults <- expectThat(e$val, 70 | equals(cval, label=correctVal), 71 | label=toString(e$val)) 72 | if(is(e, "dev") && !valResults$passed)swirl_out(valResults$message) 73 | valGood <- valResults$passed 74 | } 75 | } 76 | exprGood <- ifelse(is.null(correctExpr), TRUE, expr_identical_to(correctExpr)) 77 | if(valGood && exprGood){ 78 | return(TRUE) 79 | } else if (valGood && !exprGood && !strict){ 80 | swirl_out("That's not the expression I expected but it works.") 81 | swirl_out("I've executed the correct expression in case the result is needed in an upcoming question.") 82 | eval(parse(text=correctExpr),globalenv()) 83 | return(TRUE) 84 | } else { 85 | e$delta <- list() 86 | return(FALSE) 87 | } 88 | } 89 | 90 | match_call <- function(correct_call = NULL) { 91 | e <- get("e", parent.frame()) 92 | # Trivial case 93 | if(is.null(correct_call)) return(TRUE) 94 | # Get full correct call 95 | full_correct_call <- expand_call(correct_call) 96 | # Expand user's expression 97 | expr <- deparse(e$expr) 98 | full_user_expr <- expand_call(expr) 99 | # Compare function calls with full arg names 100 | identical(full_correct_call, full_user_expr) 101 | } 102 | 103 | # Utility function for match_call answer test 104 | # Fills out a function call with full argument names 105 | expand_call <- function(call_string) { 106 | # Quote expression 107 | qcall <- parse(text=call_string)[[1]] 108 | # If expression is not greater than length 1... 109 | if(length(qcall) <= 1) return(qcall) 110 | # See if it's an assignment 111 | is_assign <- is(qcall, "<-") 112 | # If assignment, process righthandside 113 | if(is_assign) { 114 | # Get righthand side 115 | rhs <- qcall[[3]] 116 | # If righthand side is not a call, can't use match.fun() 117 | if(!is.call(rhs)) return(qcall) 118 | # Get function from function name 119 | fun <- match.fun(rhs[[1]]) 120 | # match.call() does not support primitive functions 121 | if(is.primitive(fun)) return(qcall) 122 | # Get expanded call 123 | full_rhs <- match.call(fun, rhs) 124 | # Full call 125 | qcall[[3]] <- full_rhs 126 | } else { # If not assignment, process whole thing 127 | # Get function from function name 128 | fun <- match.fun(qcall[[1]]) 129 | # match.call() does not support primitive functions 130 | if(is.primitive(fun)) return(qcall) 131 | # Full call 132 | qcall <- match.call(fun, qcall) 133 | } 134 | # Return expanded function call 135 | qcall 136 | } 137 | 138 | # Returns TRUE if e$expr matches any of the expressions given 139 | # (as characters) in the argument. 140 | ANY_of_exprs <- function(...){ 141 | e <- get("e", parent.frame()) 142 | any(sapply(c(...), function(expr)omnitest(expr))) 143 | } 144 | 145 | 146 | 147 | notify <- function() { 148 | e <- get("e", parent.frame()) 149 | if(e$val == "No") return(TRUE) 150 | 151 | good <- FALSE 152 | while(!good) { 153 | # Get info 154 | name <- readline_clean("What is your full name? ") 155 | address <- readline_clean("What is the email address of the person you'd like to notify? ") 156 | 157 | # Repeat back to them 158 | message("\nDoes everything look good?\n") 159 | message("Your name: ", name, "\n", "Send to: ", address) 160 | 161 | yn <- select.list(c("Yes", "No"), graphics = FALSE) 162 | if(yn == "Yes") good <- TRUE 163 | } 164 | 165 | # Get course and lesson names 166 | course_name <- attr(e$les, "course_name") 167 | lesson_name <- attr(e$les, "lesson_name") 168 | 169 | subject <- paste(name, "just completed", course_name, "-", lesson_name) 170 | body = "" 171 | 172 | # Send email 173 | swirl:::email(address, subject, body) 174 | 175 | hrule() 176 | message("I just tried to create a new email with the following info:\n") 177 | message("To: ", address) 178 | message("Subject: ", subject) 179 | message("Body: ") 180 | 181 | message("\nIf it didn't work, you can send the same email manually.") 182 | hrule() 183 | 184 | # Return TRUE to satisfy swirl and return to course menu 185 | TRUE 186 | } 187 | 188 | readline_clean <- function(prompt = "") { 189 | wrapped <- strwrap(prompt, width = getOption("width") - 2) 190 | mes <- stringr::str_c("| ", wrapped, collapse = "\n") 191 | message(mes) 192 | readline() 193 | } 194 | 195 | hrule <- function() { 196 | message("\n", paste0(rep("#", getOption("width") - 2), collapse = ""), "\n") 197 | } 198 | -------------------------------------------------------------------------------- /Sequences_of_Numbers/lesson.yaml: -------------------------------------------------------------------------------- 1 | - Class: meta 2 | Course: Programando en R 3 | Lesson: Secuencias de Números 4 | Author: Nick Carchedi 5 | Type: Standard 6 | Organization: JHU Biostat 7 | Version: 2.2.0 8 | 9 | - Class: text 10 | Output: En esta lección, usted aprenderá cómo crear secuencias de números en R. 11 | 12 | - Class: cmd_question 13 | Output: La forma más sencilla de crear una secuencia de números en el que R es mediante el uso del operador `:`. Escriba 1:20 para ver cómo funciona. 14 | CorrectAnswer: '1:20' 15 | AnswerTests: omnitest(correctExpr='1:20') 16 | Hint: Escriba 1:20 sin espacios. Asegúrese de utilizar dos puntos regulares y no un punto y coma. 17 | 18 | - Class: cmd_question 19 | Output: Eso nos dio todo entero entre 1 y 20 ambos inclusive. También podríamos utilizarlo para crear una secuencia de números reales. Por ejemplo, trate con pi:10. 20 | CorrectAnswer: pi:10 21 | AnswerTests: omnitest(correctExpr='pi:10') 22 | Hint: Enter Introduzca pi:10 y ver qué pasa. pi es una constante predefinida en R que toma en el valor 3.1415.... 23 | 24 | - Class: text 25 | Output: El resultado es un vector de números reales que empiezan por pi (3.1415...) y el aumento va en incrementos de 1. Nunca se alcanza el límite superior de 10, ya que el siguiente número en nuestra secuencia sería mayor que 10. 26 | 27 | - Class: cmd_question 28 | Output: "¿Qué pasa si hacemos 15:1? Dese la oportunidad de averiguarlo." 29 | CorrectAnswer: '15:1' 30 | AnswerTests: omnitest(correctExpr='15:1') 31 | Hint: Escriba 15:1 y pulse Intro. 32 | 33 | - Class: text 34 | Output: Ha contado hacia atrás en incrementos de 1! Es poco probable que busquemos este comportamiento, pero sin embargo es bueno saber cómo podría suceder. 35 | 36 | - Class: text 37 | Output: "Recuerde que si usted tiene preguntas acerca de una función de R en particular, puede acceder a su documentación con un signo de interrogación seguido del nombre de la función: ?Function_name_here. Sin embargo, en el caso de buscar la ayuda sobre un operador como el colon usado anteriormente, debe incluir el símbolo de acentos abiertos como éste: ?`:`. (NOTA: El acento grave (`) generalmente se encuentra en la esquina superior izquierda de un teclado, por encima de la lengüeta llave. Si usted no tiene una tecla de acento grave, puede utilizar comillas regulares.)" 38 | 39 | - Class: cmd_question 40 | Output: Abra la documentación de `:` ahora. 41 | CorrectAnswer: ?`:` 42 | AnswerTests: ANY_of_exprs('?`:`', "?':'", '?":"') 43 | Hint: "Con el fin de ver la documentación de un símbolo como el operador de colon, usted tiene que utilizar acentos abiertos (o cotizaciones). Con esto, R sabe que no está intentando utilizar el símbolo en el comando. Así es como debe verse: ?`:`. No te olvides del simbolo de interrogación en el frente." 44 | 45 | - Class: text 46 | Output: A menudo, vamos a desear más control sobre una secuencia que estamos creando de lo que el operador `:` nos da. La función seq() sirve para este propósito. 47 | 48 | - Class: cmd_question 49 | Output: El uso más básico de seq() hace exactamente lo mismo que el operador `:`. Trate seq(1, 20) para ver esto. 50 | CorrectAnswer: seq(1, 20) 51 | AnswerTests: omnitest(correctExpr='seq(1, 20)') 52 | Hint: Escriba seq(1, 20) y pulse Enter. No se requiere el espacio después de la coma, pero se recomienda ya que tiende a hacer que el código parece más despejado. 53 | 54 | - Class: cmd_question 55 | Output: Esto nos da el mismo resultado que 1:20. Sin embargo, vamos a decir que en lugar de eso quieren un vector de números que van de 0 a 10, incrementado en 0,5. seq(0, 10, by = 0.5) hace precisamente eso. Intentalo. 56 | CorrectAnswer: seq(0, 10, by=0.5) 57 | AnswerTests: omnitest(correctExpr='seq(0, 10, by=0.5)') 58 | Hint: Usted todavía está utilizando la función seq() aquí, pero esta vez con un argumento extra que le dice a R que desea incrementar cada paso de la secuencia en 0,5. Pruebe seq(0, 10, by = 0.5). 59 | 60 | - Class: cmd_question 61 | Output: O tal vez no nos importa el incremento y sólo queremos una secuencia de 30 números entre 5 y 10. seq(5, 10, length=30) produce este efecto. Hazlo ahora y almacena el resultado en una nueva variable llamada my_seq. 62 | CorrectAnswer: my_seq <- seq(5, 10, length=30) 63 | AnswerTests: omnitest(correctExpr='my_seq <- seq(5, 10, length=30)') 64 | Hint: 'Estas usando la misma función aquí, pero cambiando sus argumentos para diferentes resultados. Asegúrese de guardar el resultado en una nueva variable llamada my_seq, así: my_seq <- seq(5, 10, length=30).' 65 | 66 | - Class: cmd_question 67 | Output: Para confirmar que my_seq tiene longitud 30, podemos utilizar la función length(). Inténtalo ahora. 68 | CorrectAnswer: length(my_seq) 69 | AnswerTests: omnitest(correctExpr='length(my_seq)') 70 | Hint: Utilice length(my_seq) para ver la longitud de la variable my_seq. 71 | 72 | - Class: text 73 | Output: Vamos a suponer que no sabemos la longitud de my_seq, pero queremos generar una secuencia de números enteros de 1 a N, donde N representa la longitud de la my_seq vector. En otras palabras, queremos un nuevo vector (1, 2, 3, ...) que es de la misma longitud de my_seq. 74 | 75 | - Class: cmd_question 76 | Output: 'Hay varias maneras que podríamos hacer esto. Una posibilidad es combinar el operador `:` y la función de la length() así: 1:length(my_seq). Dese un intento. ' 77 | CorrectAnswer: 1:length(my_seq) 78 | AnswerTests: omnitest(correctExpr='1:length(my_seq)') 79 | Hint: Trate con 1:length(my_seq), sin asignar el resultado a una nueva variable. 80 | 81 | - Class: cmd_question 82 | Output: Otra opción es utilizar seq(along.with = my_seq). Haga un intento. 83 | CorrectAnswer: seq(along.with = my_seq) 84 | AnswerTests: omnitest(correctExpr='seq(along.with = my_seq)') 85 | Hint: Escriba seq(along.with = my_seq). Nótese que estamos usando la misma función seq(), pero con un argumento diferente llamado `along.with`. Esto le dice a R que desea una secuencia 'a lo largo de' la secuencia my_seq. Recuerde que usted puede escribir ?seq si tiene preguntas acerca de la función seq(). 86 | 87 | - Class: cmd_question 88 | Output: Sin embargo, como es el caso con muchas tareas comunes, R tiene una función incorporada especial para este propósito llamado seq_along(). Escriba seq_along(my_seq) para verlo en accion. 89 | CorrectAnswer: seq_along(my_seq) 90 | AnswerTests: omnitest(correctExpr='seq_along(my_seq)') 91 | Hint: La función seq_along() es una variación de la función seq(). Trate seq_along(my_seq) para obtener el mismo resultado de otra manera. 92 | 93 | - Class: text 94 | Output: A menudo hay varios enfoques para resolver el mismo problema, en particular en R. enfoques simples que involucran menos escritura son generalmente mejores. Es también importante que su código sea legible, para que usted y otros puedan entender lo que está pasando sin demasiados problemas. 95 | 96 | 97 | - Class: text 98 | Output: Si R tiene una función incorporada para una tarea en particular, es probable que la función esté altamente optimizada para ese propósito y es su mejor opción. A medida que usted se convierta en un programador R avanzado, usted diseñará sus propias funciones para realizar tareas cuando no hay mejores opciones. Exploraremos escribir sus propias funciones en lecciones futuras. 99 | 100 | - Class: text 101 | Output: Otra función relacionada con la creación de secuencias de números es rep(), que es sinónimo de 'réplica'. Echemos un vistazo a algunos usos de esta función. 102 | 103 | - Class: cmd_question 104 | Output: Si estamos interesados ​​en la creación de un vector que contiene 40 ceros, podemos utilizar rep(0, times=40). Intentalo. 105 | CorrectAnswer: rep(0, times = 40) 106 | AnswerTests: omnitest(correctExpr='rep(0, times = 40)') 107 | Hint: Escribe rep(0, times = 40) para hacer un vector que contiene 40 ceros. 108 | 109 | - Class: cmd_question 110 | Output: Si en cambio queremos que nuestro vector contenga 10 repeticiones del vector (0, 1, 2), podemos hacer rep(c(0, 1, 2), times = 10). Adelante. 111 | CorrectAnswer: rep(c(0, 1, 2), times = 10) 112 | AnswerTests: omnitest(correctExpr='rep(c(0, 1, 2), times = 10)') 113 | Hint: Pruebe rep(c (0, 1, 2), times = 10) para diferentes variaciones sobre el mismo tema. Asegúrese de utilizar la función c() para decirle R que los números 0, 1 y 2 constituyen un vector. 114 | 115 | - Class: cmd_question 116 | Output: Por último, vamos a decir que en lugar de repetir el vector (0, 1, 2) una y otra vez, queremos que nuestro vector contenga 10 ceros, luego 10 unos, y luego 10 dos. Podemos hacer esto con el argumento `each`. Trate de rep(c (0, 1, 2), each = 10). 117 | CorrectAnswer: rep(c(0, 1, 2), each = 10) 118 | AnswerTests: omnitest(correctExpr='rep(c(0, 1, 2), each = 10)') 119 | Hint: Escriba rep(c (0, 1, 2), each = 10) para ver cómo el argumento `each` de la función rep() altera su comportamiento ligeramente. 120 | 121 | 122 | -------------------------------------------------------------------------------- /Simulation/customTests.R: -------------------------------------------------------------------------------- 1 | # So swirl does not repeat execution of commands 2 | # AUTO_DETECT_NEWVAR <- FALSE 3 | 4 | expr_creates_var <- function(correctName=NULL){ 5 | e <- get("e", parent.frame()) 6 | # TODO: Eventually make auto-detection of new variables an option. 7 | # Currently it can be set in customTests.R 8 | delta <- if(!customTests$AUTO_DETECT_NEWVAR){ 9 | safeEval(e$expr, e) 10 | } else { 11 | e$delta 12 | } 13 | if(is.null(correctName)){ 14 | results <- expectThat(length(delta) >= 1, 15 | testthat::is_true(), 16 | label=paste(deparse(e$expr), 17 | "does not create a variable.")) 18 | } else { 19 | results <- expectThat(correctName %in% names(delta), 20 | testthat::is_true(), 21 | label=paste(deparse(e$expr), 22 | "does not create a variable named", 23 | correctName)) 24 | } 25 | if(results$passed){ 26 | e$newVar <- e$val 27 | e$newVarName <- names(delta)[1] 28 | e$delta <- mergeLists(delta, e$delta) 29 | } else { 30 | e$delta <- list() 31 | } 32 | return(results$passed) 33 | } 34 | 35 | # Returns TRUE if the user has calculated a value equal to that calculated by the given expression. 36 | calculates_same_value <- function(expr){ 37 | e <- get("e", parent.frame()) 38 | # Calculate what the user should have done. 39 | eSnap <- cleanEnv(e$snapshot) 40 | val <- eval(parse(text=expr), eSnap) 41 | passed <- isTRUE(all.equal(val, e$val)) 42 | if(!passed)e$delta <- list() 43 | return(passed) 44 | } 45 | 46 | omnitest <- function(correctExpr=NULL, correctVal=NULL, strict=FALSE){ 47 | e <- get("e", parent.frame()) 48 | # Trivial case 49 | if(is.null(correctExpr) && is.null(correctVal))return(TRUE) 50 | # Testing for correct expression only 51 | if(!is.null(correctExpr) && is.null(correctVal)){ 52 | passed <- expr_identical_to(correctExpr) 53 | if(!passed)e$delta <- list() 54 | return(passed) 55 | } 56 | # Testing for both correct expression and correct value 57 | # Value must be character or single number 58 | valGood <- NULL 59 | if(!is.null(correctVal)){ 60 | if(is.character(e$val)){ 61 | valResults <- expectThat(e$val, 62 | is_equivalent_to(correctVal, label=correctVal), 63 | label=(e$val)) 64 | if(is(e, "dev") && !valResults$passed)swirl_out(valResults$message) 65 | valGood <- valResults$passed 66 | # valGood <- val_matches(correctVal) 67 | } else if(!is.na(e$val) && is.numeric(e$val) && length(e$val) == 1){ 68 | cval <- try(as.numeric(correctVal), silent=TRUE) 69 | valResults <- expectThat(e$val, 70 | equals(cval, label=correctVal), 71 | label=toString(e$val)) 72 | if(is(e, "dev") && !valResults$passed)swirl_out(valResults$message) 73 | valGood <- valResults$passed 74 | } 75 | } 76 | exprGood <- ifelse(is.null(correctExpr), TRUE, expr_identical_to(correctExpr)) 77 | if(valGood && exprGood){ 78 | return(TRUE) 79 | } else if (valGood && !exprGood && !strict){ 80 | swirl_out("That's not the expression I expected but it works.") 81 | swirl_out("I've executed the correct expression in case the result is needed in an upcoming question.") 82 | eval(parse(text=correctExpr),globalenv()) 83 | return(TRUE) 84 | } else { 85 | e$delta <- list() 86 | return(FALSE) 87 | } 88 | } 89 | 90 | match_call <- function(correct_call = NULL) { 91 | e <- get("e", parent.frame()) 92 | # Trivial case 93 | if(is.null(correct_call)) return(TRUE) 94 | # Get full correct call 95 | full_correct_call <- expand_call(correct_call) 96 | # Expand user's expression 97 | expr <- deparse(e$expr) 98 | full_user_expr <- expand_call(expr) 99 | # Compare function calls with full arg names 100 | identical(full_correct_call, full_user_expr) 101 | } 102 | 103 | # Utility function for match_call answer test 104 | # Fills out a function call with full argument names 105 | expand_call <- function(call_string) { 106 | # Quote expression 107 | qcall <- parse(text=call_string)[[1]] 108 | # If expression is not greater than length 1... 109 | if(length(qcall) <= 1) return(qcall) 110 | # See if it's an assignment 111 | is_assign <- is(qcall, "<-") 112 | # If assignment, process righthandside 113 | if(is_assign) { 114 | # Get righthand side 115 | rhs <- qcall[[3]] 116 | # If righthand side is not a call, can't use match.fun() 117 | if(!is.call(rhs)) return(qcall) 118 | # Get function from function name 119 | fun <- match.fun(rhs[[1]]) 120 | # match.call() does not support primitive functions 121 | if(is.primitive(fun)) return(qcall) 122 | # Get expanded call 123 | full_rhs <- match.call(fun, rhs) 124 | # Full call 125 | qcall[[3]] <- full_rhs 126 | } else { # If not assignment, process whole thing 127 | # Get function from function name 128 | fun <- match.fun(qcall[[1]]) 129 | # match.call() does not support primitive functions 130 | if(is.primitive(fun)) return(qcall) 131 | # Full call 132 | qcall <- match.call(fun, qcall) 133 | } 134 | # Return expanded function call 135 | qcall 136 | } 137 | 138 | # Returns TRUE if e$expr matches any of the expressions given 139 | # (as characters) in the argument. 140 | ANY_of_exprs <- function(...){ 141 | e <- get("e", parent.frame()) 142 | any(sapply(c(...), function(expr)omnitest(expr))) 143 | } 144 | 145 | 146 | 147 | notify <- function() { 148 | e <- get("e", parent.frame()) 149 | if(e$val == "No") return(TRUE) 150 | 151 | good <- FALSE 152 | while(!good) { 153 | # Get info 154 | name <- readline_clean("What is your full name? ") 155 | address <- readline_clean("What is the email address of the person you'd like to notify? ") 156 | 157 | # Repeat back to them 158 | message("\nDoes everything look good?\n") 159 | message("Your name: ", name, "\n", "Send to: ", address) 160 | 161 | yn <- select.list(c("Yes", "No"), graphics = FALSE) 162 | if(yn == "Yes") good <- TRUE 163 | } 164 | 165 | # Get course and lesson names 166 | course_name <- attr(e$les, "course_name") 167 | lesson_name <- attr(e$les, "lesson_name") 168 | 169 | subject <- paste(name, "just completed", course_name, "-", lesson_name) 170 | body = "" 171 | 172 | # Send email 173 | swirl:::email(address, subject, body) 174 | 175 | hrule() 176 | message("I just tried to create a new email with the following info:\n") 177 | message("To: ", address) 178 | message("Subject: ", subject) 179 | message("Body: ") 180 | 181 | message("\nIf it didn't work, you can send the same email manually.") 182 | hrule() 183 | 184 | # Return TRUE to satisfy swirl and return to course menu 185 | TRUE 186 | } 187 | 188 | readline_clean <- function(prompt = "") { 189 | wrapped <- strwrap(prompt, width = getOption("width") - 2) 190 | mes <- stringr::str_c("| ", wrapped, collapse = "\n") 191 | message(mes) 192 | readline() 193 | } 194 | 195 | hrule <- function() { 196 | message("\n", paste0(rep("#", getOption("width") - 2), collapse = ""), "\n") 197 | } 198 | -------------------------------------------------------------------------------- /Simulation/initLesson.R: -------------------------------------------------------------------------------- 1 | # Put initialization code in this file. 2 | -------------------------------------------------------------------------------- /Simulation/lesson.yaml: -------------------------------------------------------------------------------- 1 | - Class: meta 2 | Course: Programando en R 3 | Lesson: Simulación 4 | Author: Nick Carchedi 5 | Type: Standard 6 | Organization: JHU Biostat 7 | Version: 2.2.11 8 | 9 | - Class: text 10 | Output: Una de las grandes ventajas de utilizar un lenguaje de programación estadística como R es su vasta colección de herramientas para la simulación de números aleatorios. 11 | 12 | - Class: text 13 | Output: Esta lección asume la familiaridad con algunas distribuciones de probabilidad comunes, aunque en este tópico solo se discutirá sobre la generación de números aleatorios. Incluso si usted no tiene experiencia previa con estos conceptos, podrá ser capaz de completar la lección y entender las ideas principales. 14 | 15 | - Class: cmd_question 16 | Output: La primera función que usaremos para generar números aleatorios es sample(). Use ?sample para levantar la documentación. 17 | CorrectAnswer: ?sample 18 | AnswerTests: omnitest(correctExpr='?sample') 19 | Hint: Utilice '?sample' para ver la documentación de la función sample(). 20 | 21 | - Class: cmd_question 22 | Output: "Vamos a simular el lanzamiento de cuatro dados de seis caras: sample(1:6, 4, replace = TRUE)." 23 | CorrectAnswer: sample(1:6, 4, replace = TRUE) 24 | AnswerTests: match_call('sample(1:6, 4, replace = TRUE)') 25 | Hint: Type sample(1:6, 4, replace = TRUE) to simulate rolling four six-sided dice. 26 | 27 | - Class: cmd_question 28 | Output: Ahora repita el comando para ver cómo su resultado difiere. (La probabilidad de obtener el mismo resultado exacto es (1/6) ^ 4 = 0,00077, que es bastante pequeña!) 29 | CorrectAnswer: sample(1:6, 4, replace = TRUE) 30 | AnswerTests: match_call('sample(1:6, 4, replace = TRUE)') 31 | Hint: Escriba sample(1:6, 4, replace = TRUE) para simular el lanzamiento de cuatro dados de seis caras de nuevo. 32 | 33 | - Class: text 34 | Output: sample(1:6, 4, replace = TRUE) da instrucciones a R para seleccionar al azar a cuatro números entre 1 y 6, con reemplazo. El muestreo con reemplazo simplemente significa que cada número es "devuelto" después de que se ha seleccionado, por lo que el mismo número puede aparecer más de una vez. Esto es lo que queremos aquí, ya que lo que sacas en un dado no debe afectar lo que sacas en cualquiera de los otros. 35 | 36 | - Class: cmd_question 37 | Output: Ahora genera una muestra de 10 números entre 1 y 20, sin reemplazo. Para muestras sin reemplazo, sólo tiene que dejar fuera el argumento 'replace'. 38 | CorrectAnswer: sample(1:20, 10) 39 | AnswerTests: match_call('sample(1:20, 10)') 40 | Hint: Escriba sample(1:20, 10) para generar una muestra aleatoria de 10 números entre 1 y 20, sin reemplazo. 41 | 42 | - Class: text 43 | Output: Dado el último comando muestrea sin reemplazo, ningún número puede aparecer más de una vez en la salida. 44 | 45 | - Class: cmd_question 46 | Output: LETTERS es una variable predefinida en R que contiene un vector de las 26 letras del alfabeto Inglés. Tome una mirada en ella ahora. 47 | CorrectAnswer: LETTERS 48 | AnswerTests: omnitest(correctExpr='LETTERS') 49 | Hint: Escriba LETTERS para imprimir su contenido en la consola. 50 | 51 | - Class: cmd_question 52 | Output: La función sample() también se puede utilizar para permutar, o reorganizar, los elementos de un vector. Por ejemplo, intente sample(LETTERS) para permutar las 26 letras del alfabeto Inglés. 53 | CorrectAnswer: sample(LETTERS) 54 | AnswerTests: omnitest(correctExpr='sample(LETTERS)') 55 | Hint: Utilice sample(LETTERS) para permutar las 26 letras del alfabeto Inglés. 56 | 57 | - Class: text 58 | Output: Esto es idéntico a tomar una muestra de tamaño 26 a partir de LETTERS, sin reemplazo. Cuando no se especifica el argumento 'size' dentro de sample(), R toma una muestra del mismo tamaño que el vector desde el que se está muestreando. 59 | 60 | - Class: text 61 | Output: Ahora, supongamos que queremos simular 100 lanzamientos de una moneda de dos caras desbalanceada. Esta moneda particular tiene un 0.3 de probabilidad de salir "cruz" y un 0.7 de probabilidad de salir "cara". 62 | 63 | - Class: cmd_question 64 | Output: Digamos que el valor 0 representa "cruz" y el valor 1 representan "cara". Utilice sample() para extraer una muestra de tamaño 100 a partir del vector c(0,1), con reemplazo. Como la moneda es injusta o desbalanceada, debemos atribuir probabilidades específicas a los valores 0 (cruz) y 1 (cara) con un cuarto argumento, prob = c(0.3, 0.7). Asigne el resultado de una nueva variable llamada flips. 65 | CorrectAnswer: flips <- sample(c(0,1), 100, replace = TRUE, prob = c(0.3, 0.7)) 66 | AnswerTests: match_call('flips <- sample(c(0,1), 100, replace = TRUE, prob = c(0.3, 0.7))') 67 | Hint: 'El siguiente comando producirá 100 lanzamientos de una moneda injusta y asignará el resultado: flips <- sample(c(0,1), 100, replace = TRUE, prob = c(0.3, 0.7))' 68 | 69 | - Class: cmd_question 70 | Output: Vea el contenido de la variable de flips. 71 | CorrectAnswer: flips 72 | AnswerTests: omnitest(correctExpr='flips') 73 | Hint: Simplemente escriba flips para ver su contenido. 74 | 75 | - Class: cmd_question 76 | Output: Dado que la probabilidad de obtener cara en un lanzamiento en 0.7, es de esperar que aproximadamente el 70% de nuestra muestra tendrá el valor 1. Cuente el número real de 1s contenidas en flips utilizando la función sum(). 77 | CorrectAnswer: sum(flips) 78 | AnswerTests: omnitest(correctExpr='sum(flips)') 79 | Hint: sum(flips) suma todos los 1s y 0s, lo que da como resultado el número total de 1s en flips. 80 | 81 | - Class: cmd_question 82 | Output: Un lanzamiento de cara o cruz da un resultado binario (0 ó 1) y estamos llevando a cabo 100 ensayos independientes (flips), por lo que el número total de 1s se puede modelar como una variable aleatoria Binomial. Podemos utilizar la función rbinom() para simular una Binomial. Abra la documentación de rbinom() usando ?rbinom. 83 | CorrectAnswer: ?rbinom 84 | AnswerTests: omnitest(correctExpr='?rbinom') 85 | Hint: Escriba ?rbinom para abrir el archivo de ayuda de rbinom(). 86 | 87 | - Class: text 88 | Output: Cada distribución de probabilidad en R tiene una función r*** (por "random" o azar), una función d*** (por "density"), una función p*** (por "probabilidad" acumulada), y una q*** ( por "cuantil"). Para esta lección estamos interesados ​​en las funciones r***, pero le invitamos a explorar las demás por su cuenta. 89 | 90 | - Class: cmd_question 91 | Output: Una variable aleatoria binomial representa el número total de "éxitos" (caras) en un número determinado de "ensayos" independientes (lanzamientos de monedas). Por lo tanto, podemos generar una sola variable aleatoria que represente el número de "caras" en 100 lanzamientos de nuestra moneda injusta usando rbinom(1, size = 100, prob = 0.7). Tenga en cuenta que sólo se especifica la probabilidad de "éxito" (caras) y no la probabilidad de "fracaso" (cruz). Inténtalo ahora. 92 | CorrectAnswer: rbinom(1, size = 100, prob = 0.7) 93 | AnswerTests: match_call('rbinom(1, size = 100, prob = 0.7)') 94 | Hint: Llame rbinom() con n = 1, size = 100, y prob = 0.7. 95 | 96 | - Class: cmd_question 97 | Output: De forma equivalente, si queremos ver todos los 0s y 1s, podemos solicitar 100 observaciones, cada una de tamaño 1, con probabilidad de éxito de 0,7. Dese una oportunidad, asignando el resultado a una nueva variable llamada flips2. 98 | CorrectAnswer: flips2 <- rbinom(100, size = 1, prob = 0.7) 99 | AnswerTests: match_call('flips2 <- rbinom(100, size = 1, prob = 0.7)') 100 | Hint: Llame rbinom() con n = 100, size = 1, y prob = 0.7 y asigne el resultado a flips2. 101 | 102 | - Class: cmd_question 103 | Output: Vea el contenido de flips2. 104 | CorrectAnswer: flips2 105 | AnswerTests: omnitest('flips2') 106 | Hint: Escriba flips2 para ver su contenido. 107 | 108 | - Class: cmd_question 109 | Output: Ahora use sum() para contar el número de 1s (caras) en flips2. Debe estar cerca de 70! 110 | CorrectAnswer: sum(flips2) 111 | AnswerTests: omnitest('sum(flips2)') 112 | Hint: Utilice sum(flips2) para contar el número de 1s. 113 | 114 | - Class: cmd_question 115 | Output: Similar a rbinom(), podemos utilizar R para simular números aleatorios de muchas otras distribuciones de probabilidad. Abra la documentación para rnorm() ahora. 116 | CorrectAnswer: ?rnorm 117 | AnswerTests: omnitest('?rnorm') 118 | Hint: Escriba ?rnorm para ver el archivo de ayuda. 119 | 120 | - Class: cmd_question 121 | Output: La distribución normal estándar tiene media 0 y desviación estándar 1. Como se puede ver en la sección "Usage" en la documentación, los valores por defecto de los argumentos de la 'media' y 'sd' a rnorm() son 0 y 1, respectivamente. Por lo tanto, rnorm(10) va a generar 10 números aleatorios de una distribución normal estándar. Dese una oportunidad. 122 | CorrectAnswer: rnorm(10) 123 | AnswerTests: omnitest('rnorm(10)') 124 | Hint: Utilice rnorm(10) para generar 10 números aleatorios de una distribución normal estándar. 125 | 126 | - Class: cmd_question 127 | Output: Ahora haga lo mismo, excepto con una media de 100 y una desviación estándar de 25. 128 | CorrectAnswer: rnorm(10, 100, 25) 129 | AnswerTests: match_call('rnorm(10, 100, 25)') 130 | Hint: Utilice RNorm (10, media = 100, SD = 25) para generar 10 números aleatorios de una distribución normal con media 100 y desviación estándar 25. 131 | 132 | - Class: text 133 | Output: Por último, ¿qué pasa si queremos simular 100 *grupos* de números al azar, cada uno con 5 valores generados a partir de una distribución de Poisson con media 10? Vamos a empezar con un grupo de 5 números, entonces te voy a mostrar cómo repetir la operación de 100 veces de una manera conveniente y compacta. 134 | 135 | - Class: cmd_question 136 | Output: Genere 5 valores aleatorios de una distribución de Poisson con media 10 (lambda). Eche un vistazo a la documentación de rpois() si necesita ayuda. 137 | CorrectAnswer: rpois(5, 10) 138 | AnswerTests: match_call('rpois(5, 10)') 139 | Hint: Utilice rpois(5, 10) para generar 5 números aleatorios de una distribución de Poisson con media 10. 140 | 141 | - Class: cmd_question 142 | Output: Ahora usa replicate(100, rpois(5, 10)) para realizar esta operación 100 veces. Almacene el resultado en una nueva variable llamada my_pois. 143 | CorrectAnswer: my_pois <- replicate(100, rpois(5, 10)) 144 | AnswerTests: match_call('my_pois <- replicate(100, rpois(5, 10))') 145 | Hint: my_pois <- replicate(100, rpois(5, 10)) se repetirá la operación 100 veces y almacenará el resultado. 146 | 147 | - Class: cmd_question 148 | Output: Echa un vistazo a los contenidos de my_pois. 149 | CorrectAnswer: my_pois 150 | AnswerTests: omnitest('my_pois') 151 | Hint: Imprime el contenido de my_pois a la consola. 152 | 153 | - Class: cmd_question 154 | Output: replicate() crea una matriz, cada columna contiene 5 números aleatorios generados a partir de una distribución de Poisson con media 10. Ahora podemos encontrar la media de cada columna en my_pois utilizando la función colMeans(). Almacene el resultado en una variable llamada cm. 155 | CorrectAnswer: cm <- colMeans(my_pois) 156 | AnswerTests: omnitest('cm <- colMeans(my_pois)') 157 | Hint: Utilice cm <- colMeans(my_pois) para crear un vector con las medias de las columnas de my_pois, almacenando el resultado en cm. 158 | 159 | - Class: cmd_question 160 | Output: Vamos a echar un vistazo a la distribución de nuestra muestra de medias de columna graficando un histograma con hist(cm). 161 | CorrectAnswer: hist(cm) 162 | AnswerTests: omnitest('hist(cm)') 163 | Hint: hist(cm) le dará un histograma de las medias de columna. 164 | 165 | - Class: text 166 | Output: Parece que nuestras medias de columna se distribuyen casi normalmente, ¿verdad? Ese es el teorema central del límite trabajando, pero eso es una lección para otro día! 167 | 168 | - Class: text 169 | Output: Todas las distribuciones de probabilidad estándar están construidas en R, incluyendo la Exponencial (rexp()), la Chi-cuadrado (rchisq()), la Gamma (rgamma()), .... Bueno, ya verás el patrón. 170 | 171 | - Class: text 172 | Output: La simulación es prácticamente un campo en si mismo y sólo hemos rozado la superficie de lo que se puede hacer. Le animo a explorar estas y otras funciones más por su cuenta. 173 | 174 | 175 | -------------------------------------------------------------------------------- /Subsetting_Vectors/customTests.R: -------------------------------------------------------------------------------- 1 | notify <- function() { 2 | e <- get("e", parent.frame()) 3 | if(e$val == "No") return(TRUE) 4 | 5 | good <- FALSE 6 | while(!good) { 7 | # Get info 8 | name <- readline_clean("What is your full name? ") 9 | address <- readline_clean("What is the email address of the person you'd like to notify? ") 10 | 11 | # Repeat back to them 12 | message("\nDoes everything look good?\n") 13 | message("Your name: ", name, "\n", "Send to: ", address) 14 | 15 | yn <- select.list(c("Yes", "No"), graphics = FALSE) 16 | if(yn == "Yes") good <- TRUE 17 | } 18 | 19 | # Get course and lesson names 20 | course_name <- attr(e$les, "course_name") 21 | lesson_name <- attr(e$les, "lesson_name") 22 | 23 | subject <- paste(name, "just completed", course_name, "-", lesson_name) 24 | body = "" 25 | 26 | # Send email 27 | swirl:::email(address, subject, body) 28 | 29 | hrule() 30 | message("I just tried to create a new email with the following info:\n") 31 | message("To: ", address) 32 | message("Subject: ", subject) 33 | message("Body: ") 34 | 35 | message("\nIf it didn't work, you can send the same email manually.") 36 | hrule() 37 | 38 | # Return TRUE to satisfy swirl and return to course menu 39 | TRUE 40 | } 41 | 42 | readline_clean <- function(prompt = "") { 43 | wrapped <- strwrap(prompt, width = getOption("width") - 2) 44 | mes <- stringr::str_c("| ", wrapped, collapse = "\n") 45 | message(mes) 46 | readline() 47 | } 48 | 49 | hrule <- function() { 50 | message("\n", paste0(rep("#", getOption("width") - 2), collapse = ""), "\n") 51 | } 52 | -------------------------------------------------------------------------------- /Subsetting_Vectors/initLesson.R: -------------------------------------------------------------------------------- 1 | # Put initialization code in this file. The variables you create 2 | # here will show up in the user's workspace when he or she begins 3 | # the lesson. 4 | 5 | x <- sample(c(rnorm(20), rep(NA, 20))) 6 | -------------------------------------------------------------------------------- /Subsetting_Vectors/lesson.yaml: -------------------------------------------------------------------------------- 1 | - Class: meta 2 | Course: Programando en R 3 | Lesson: Subcomjuntos de Vectores 4 | Author: Nick Carchedi 5 | Type: Standard 6 | Organization: JHU Biostat 7 | Version: 2.2.0 8 | 9 | - Class: text 10 | Output: En esta lección, vamos a ver cómo extraer elementos de un vector basado en algunas condiciones que especifiquemos. 11 | 12 | - Class: text 13 | Output: Por ejemplo, sólo puede estar interesado en los primeros 20 elementos de un vector, o sólo los elementos que no son NA, o sólo aquellos que son positivos o corresponden a una variable específica de interés. Al final de esta lección, usted sabrá cómo manejar cada uno de estos escenarios. 14 | 15 | - Class: cmd_question 16 | Output: He creado para ti un vector llamado x que contiene una ordenación aleatoria de 20 números (de una distribución normal estándar) y 20 NAs. Escriba x ahora para ver lo que contiene. 17 | CorrectAnswer: x 18 | AnswerTests: omnitest(correctExpr='x') 19 | Hint: Escriba x para ver su contenido. 20 | 21 | - Class: text 22 | Output: La forma en que dices a R que deseas seleccionar algunos elementos particulares (es decir, un "subconjunto") de un vector, es mediante la colocación de un "vector índice", entre corchetes, inmediatamente después del nombre del vector. 23 | 24 | - Class: cmd_question 25 | Output: Para un ejemplo sencillo, intente con x[1:10] para ver los primeros diez elementos de x. 26 | CorrectAnswer: x[1:10] 27 | AnswerTests: omnitest(correctExpr='x[1:10]') 28 | Hint: Vea los diez primeros elementos de x con x[1:10]. 29 | 30 | - Class: text 31 | Output: Los vectores índice vienen en cuatro sabores diferentes -- vectores lógicos, vectores de enteros positivos, vectores de enteros negativos y vectores de cadenas de caracteres -- cada uno de los cuales vamos a cubrir en esta lección. 32 | 33 | - Class: text 34 | Output: Empecemos por la indexación con vectores lógicos. Un escenario común cuando se trabaja con datos del mundo real es que queremos extraer todos los elementos de un vector que no son NA (es decir, los datos que faltan). Recordemos que is.na(x) obtiene un vector de valores lógicos de la misma longitud que x, con TRUEs correspondientes a los valores de NA en x y FALSEs correspondientes a valores no NA en x. 35 | 36 | - Class: mult_question 37 | Output: ¿Qué opinas sobre lo que x[is.na(x)] te dará? 38 | AnswerChoices: Un vector de todas las NAs; Un vector sin las NAs; Un vector de TRUEs y FALSEs; Un vector de longitud 0 39 | CorrectAnswer: Un vector de todas las NAs 40 | AnswerTests: omnitest(correctVal="Un vector de todas las NAs") 41 | Hint: Recuerde que is.na(x) nos dice donde las AN están en un vector. Así que si contruimos un subconjunto x basado en eso, ¿qué es lo que usted espera que suceda? 42 | 43 | - Class: cmd_question 44 | Output: Demuestrese a sí mismo escribiendo x[is.na(x)]. 45 | CorrectAnswer: x[is.na(x)] 46 | AnswerTests: omnitest(correctExpr='x[is.na(x)]') 47 | Hint: Escriba x[is.na(x)] para ver que usted obtendrá todos los NAs, lo que claramente, no es lo que queremos! 48 | 49 | - Class: cmd_question 50 | Output: Recordemos que `!` nos da la negación de una expresión lógica, por lo !is.na(x) se puede leer como "no es NA". Por lo tanto, si queremos crear un vector llamado y que contenga todos los valores no-NA de x, podemos utilizar y <- x[!is.na(x)]. Dese la oportunidad. 51 | CorrectAnswer: y <- x[!is.na(x)] 52 | AnswerTests: omnitest(correctExpr='y <- x[!is.na(x)]') 53 | Hint: Escriba y <- x[!is.na(x)] para capturar todos los valores no faltantes de x. 54 | 55 | - Class: cmd_question 56 | Output: Imprimir y en la consola. 57 | CorrectAnswer: 'y' 58 | AnswerTests: omnitest(correctExpr='y') 59 | Hint: Escriba y para ver su contenido. 60 | 61 | - Class: text 62 | Output: Ahora que hemos aislado los valores no perdidos de x y los pusimos en y, podemos crear los subconjuntos y como nos plazca. 63 | 64 | - Class: mult_question 65 | Output: Recordemos que la expresión y > 0 nos dará un vector de valores lógicos de la misma longitud de y, con TRUEs correspondientes a los valores de y que son mayores que cero y FALSEs correspondientes a valores de y que son menos que o igual a cero . ¿Qué piensa usted de lo que y[y > 0] le dará? 66 | AnswerChoices: Un vector de todos los elementos positivos de y; Un vector de todos los elementos negativos de y; Un vector de todas las NAs; Un vector de longitud 0; Un vector de TRUEs y FALSEs 67 | CorrectAnswer: Un vector de todos los elementos positivos de y 68 | AnswerTests: omnitest(correctVal="Un vector de todos los elementos positivos de y") 69 | Hint: La expresión lógica y > 0 nos dará TRUE para cada elemento de y que es positivo. En base a eso, ¿qué piensas que y[y > 0] devolverá? 70 | 71 | - Class: cmd_question 72 | Output: Escriba y[y > 0] para ver que tenemos todos los elementos positivos de y, que también son los elementos positivos de nuestro vector original x. 73 | CorrectAnswer: y[y > 0] 74 | AnswerTests: omnitest(correctExpr='y[y > 0]') 75 | Hint: Escriba y[y > 0] para ver sólo los elementos positivos de y. 76 | 77 | - Class: cmd_question 78 | Output: Usted podría preguntarse por qué no simplemente empezamos con x[x > 0] para aislar los elementos positivos de x. Trate de que ahora para ver por qué. 79 | CorrectAnswer: x[x > 0] 80 | AnswerTests: omnitest(correctExpr='x[x > 0]') 81 | Hint: Pruebe x[x > 0] para ver por qué no usamos este enfoque. 82 | 83 | - Class: text 84 | Output: Debido a que NA no es un valor, sino más bien un marcador de posición para una cantidad desconocida, la expresión NA > 0 se evalúa como NA. Por lo tanto tenemos un montón de NAs mezclados con nuestros números positivos cuando hacemos esto. 85 | 86 | - Class: cmd_question 87 | Output: Con la combinación de nuestro conocimiento de los operadores lógicos con nuestro nuevo conocimiento de subconjuntos, podríamos hacer esto - x[!is.na(x) & x > 0]. Pruébelo. 88 | CorrectAnswer: x[!is.na(x) & x > 0] 89 | AnswerTests: omnitest(correctExpr='x[!is.na(x) & x > 0]') 90 | Hint: Intente con x[!is.na(x) & x > 0] para ver lo que obtendrá. 91 | 92 | - Class: text 93 | Output: En este caso, pedimos sólo valores de x que son no-faltantes y mayores que cero. 94 | 95 | - Class: text 96 | Output: Ya le hemos mostrado cómo obtener el subconjunto de los diez primeros valores de x utilizando x[1:10]. En este caso, hemos proporcionando un vector de enteros positivos dentro de los corchetes, esto le pide a R que devuelva sólo los elementos de x numerados del 1 al 10. 97 | 98 | - Class: text 99 | Output: Muchos lenguajes de programación utilizan lo que se llama "la indexación de base cero", lo que significa que el primer elemento de un vector se considera elemento 0. R utiliza "la indexación de base 1", que (ya lo debe suponer!) Significa que el primer elemento de un vector se considera el elemento 1. 100 | 101 | - Class: cmd_question 102 | Output: ¿Puedes imaginar cómo se podria obtener el subconjunto de la tercera, quinta y séptima posición de los elementos de x? Sugerencia - Utilice la función c ) para especificar la posición de elementos como un vector numérico. 103 | CorrectAnswer: x[c(3, 5, 7)] 104 | AnswerTests: omnitest(correctExpr='x[c(3, 5, 7)]') 105 | Hint: Creé un vector de índices con c(3, 5, 7), a continuación, pongalo que en el interior de los corchetes del vector x. 106 | 107 | - Class: cmd_question 108 | Output: Es importante que usemos vectores de enteros para obtener subconjuntos de nuestro vector x, lo que tenemos es un conjunto de índices de x, por ejemplo {1, 2, ..., 40} de x, nos data 40 elementos. ¿Qué sucedería si pedimos el elemento cero de x (es decir, x[0])? Dese la oportunidad. 109 | CorrectAnswer: x[0] 110 | AnswerTests: omnitest(correctExpr='x[0]') 111 | Hint: Pruebe x[0] para ver lo que sucede cuando nos referimos al elemento cero de un vector, que no se define en R. 112 | 113 | - Class: cmd_question 114 | Output: Como era de esperar, no conseguimos nada útil. Desafortunadamente, R no nos impide hacer esto. ¿Y si le pedimos por el elemento 3000 de x? Pruebelo. 115 | CorrectAnswer: x[3000] 116 | AnswerTests: omnitest(correctExpr='x[3000]') 117 | Hint: Solicite el elemento 3000 de x (que no existe) con x[3000]. 118 | 119 | - Class: text 120 | Output: De nuevo, nada útil (NA), pero R no nos impide pedirlo. Esto debería ser una historia con moraleja. Usted siempre debe asegurarse de que lo que usted está pidiendo, está dentro de los límites del vector que está trabajando. 121 | 122 | - Class: text 123 | Output: ¿Qué pasa si estamos interesados ​​en todos los elementos de x, excepto el segundo y décimo? Sería bastante tedioso construir un vector que contiene todos los números del 1 al 40 excepto 2 y 10. 124 | 125 | - Class: cmd_question 126 | Output: Por suerte, R acepta índices enteros negativos. Mientras que x[c(2, 10)] nos da sólo la segundo y décimo elementos x, x[c(-2, -10)] nos da todos los elementos de x excepto el 2do y 10mo elementos. Trate x[c(-2, -10)] ahora para comprobarlo. 127 | CorrectAnswer: x[c(-2, -10)] 128 | AnswerTests: omnitest(correctExpr='x[c(-2, -10)]') 129 | Hint: Dele a x[c(-2, -10)] una oportunidad. 130 | 131 | - Class: cmd_question 132 | Output: Un atajo para especificar varios números negativos es poner el signo "menos" delante del vector de números positivos. Escriba x[-c(2, 10)] para obtener exactamente el mismo resultado 133 | CorrectAnswer: x[-c(2, 10)] 134 | AnswerTests: omnitest(correctExpr='x[-c(2, 10)]') 135 | Hint: Usar x[-c(2, 10)] simplifica las cosas un poco. Esto podría ser un ahorro de tiempo si debemos especificar muchos índices negativos. 136 | 137 | - Class: text 138 | Output: Hasta el momento, hemos cubierto tres tipos de vectores de índice - lógico, entero positivo y entero negativo. El único tipo que queda nos obliga a introducir el concepto de los elementos "nombrados". 139 | 140 | - Class: cmd_question 141 | Output: Creé un vector numérico con tres elementos nombrados usando vect <- c(foo = 11, bar = 2, norf = NA). 142 | CorrectAnswer: vect <- c(foo = 11, bar = 2, norf = NA) 143 | AnswerTests: omnitest(correctExpr='vect <- c(foo = 11, bar = 2, norf = NA)') 144 | Hint: Crear un vector nombrado con vect <- c(foo = 11, bar = 2, norf = NA). 145 | 146 | - Class: cmd_question 147 | Output: Cuando imprimimos vect en la consola, verás que cada elemento tiene un nombre. Pruebelo. 148 | CorrectAnswer: vect 149 | AnswerTests: omnitest(correctExpr='vect') 150 | Hint: Escriba vect para ver su contenido. 151 | 152 | - Class: cmd_question 153 | Output: También podemos obtener los nombres de vect pasando vect como argumento de la función names(). Dese que un intento. 154 | CorrectAnswer: names(vect) 155 | AnswerTests: omnitest(correctExpr='names(vect)') 156 | Hint: Echa un vistazo a los resultados de names(vect). 157 | 158 | - Class: cmd_question 159 | Output: También podemos crear un vect2 vector sin nombres con c(11, 2, NA). Hazlo ahora.. 160 | CorrectAnswer: vect2 <- c(11, 2, NA) 161 | AnswerTests: omnitest(correctExpr='vect2 <- c(11, 2, NA)') 162 | Hint: Crear un vector ordinario (sin nombres) llamado vect2 que contenga c(11, 2, NA). 163 | 164 | - Class: cmd_question 165 | Output: A continuación, podemos añadir los atributos `names` a vect2 después realizado, con names(vect2) <- c("foo", "bar", "norf"). Adelante. 166 | CorrectAnswer: names(vect2) <- c("foo", "bar", "norf") 167 | AnswerTests: omnitest(correctExpr='names(vect2) <- c("foo", "bar", "norf")') 168 | Hint: Añada nombres a vect2 con names(vect2) <- c("foo", "bar", "norf"). 169 | 170 | - Class: cmd_question 171 | Output: Ahora, vamos a ver que vect y vect2 son los mismos pasándolos como argumentos a la función identical(). 172 | CorrectAnswer: identical(vect, vect2) 173 | AnswerTests: any_of_exprs('identical(vect, vect2)', 'identical(vect2, vect)') 174 | Hint: La función identical() nos dice si sus dos primeros argumentos son idénticos. 175 | 176 | - Class: text 177 | Output: De hecho, vect y vect2 son vectores nombrados idénticos. 178 | 179 | - Class: mult_question 180 | Output: Ahora, de vuelta a la cuestión de subconjuntos de un vector de elementos con nombre. ¿Cuál de los siguientes comandos crees que dará el segundo elemento de vect? 181 | AnswerChoices: vect[bar]; vect["bar"]; vect["2"] 182 | CorrectAnswer: vect["bar"] 183 | AnswerTests: omnitest(correctVal='vect["bar"]') 184 | Hint: Si queremos que el elemento llamado "bar" (es decir, el segundo elemento del vect), que comando nos consegurá eso? 185 | 186 | - Class: cmd_question 187 | Output: Ahora, a probarlo. 188 | CorrectAnswer: vect["bar"] 189 | AnswerTests: omnitest(correctExpr='vect["bar"]') 190 | Hint: Pruebe vect["bar"]. 191 | 192 | - Class: cmd_question 193 | Output: De la misma manera, podemos especificar un vector de nombres con vect[c("foo", "bar")]. Pruebalo. 194 | CorrectAnswer: vect[c("foo", "bar")] 195 | AnswerTests: omnitest(correctExpr='vect[c("foo", "bar")]') 196 | Hint: Utilice vect[c("foo", "bar")] para obtener sólo los elementos de vect llamados "foo" y "bar". 197 | 198 | - Class: text 199 | Output: Ahora usted sabe los cuatro métodos de subconjuntos de datos de vectores. Diferentes enfoques son mejores en diferentes escenarios y en caso de duda, experiméntalo! 200 | 201 | 202 | -------------------------------------------------------------------------------- /Vectors/customTests.R: -------------------------------------------------------------------------------- 1 | notify <- function() { 2 | e <- get("e", parent.frame()) 3 | if(e$val == "No") return(TRUE) 4 | 5 | good <- FALSE 6 | while(!good) { 7 | # Get info 8 | name <- readline_clean("What is your full name? ") 9 | address <- readline_clean("What is the email address of the person you'd like to notify? ") 10 | 11 | # Repeat back to them 12 | message("\nDoes everything look good?\n") 13 | message("Your name: ", name, "\n", "Send to: ", address) 14 | 15 | yn <- select.list(c("Yes", "No"), graphics = FALSE) 16 | if(yn == "Yes") good <- TRUE 17 | } 18 | 19 | # Get course and lesson names 20 | course_name <- attr(e$les, "course_name") 21 | lesson_name <- attr(e$les, "lesson_name") 22 | 23 | subject <- paste(name, "just completed", course_name, "-", lesson_name) 24 | body = "" 25 | 26 | # Send email 27 | swirl:::email(address, subject, body) 28 | 29 | hrule() 30 | message("I just tried to create a new email with the following info:\n") 31 | message("To: ", address) 32 | message("Subject: ", subject) 33 | message("Body: ") 34 | 35 | message("\nIf it didn't work, you can send the same email manually.") 36 | hrule() 37 | 38 | # Return TRUE to satisfy swirl and return to course menu 39 | TRUE 40 | } 41 | 42 | readline_clean <- function(prompt = "") { 43 | wrapped <- strwrap(prompt, width = getOption("width") - 2) 44 | mes <- stringr::str_c("| ", wrapped, collapse = "\n") 45 | message(mes) 46 | readline() 47 | } 48 | 49 | hrule <- function() { 50 | message("\n", paste0(rep("#", getOption("width") - 2), collapse = ""), "\n") 51 | } 52 | -------------------------------------------------------------------------------- /Vectors/lesson.yaml: -------------------------------------------------------------------------------- 1 | - Class: meta 2 | Course: Programando en R 3 | Lesson: Vectores 4 | Author: Nick Carchedi 5 | Type: Standard 6 | Organization: JHU Biostat 7 | Version: 2.2.0 8 | 9 | - Class: text 10 | Output: La estructura de datos más común y simple en R es el vector. 11 | 12 | - Class: text 13 | Output: 'Los vectores vienen en dos sabores diferentes: vectores y listas atómicos. Un vector atómico contiene exactamente un tipo de datos, mientras que una lista puede contener tipos de datos múltiples. Vamos a explorar vectores atómicos antes de llegar a las listas.' 14 | 15 | - Class: text 16 | Output: En las lecciones anteriores, hemos tratado en su totalidad con vectores numéricos, que son uno tipo de vector atómico. Otros tipos de vectores atómicos incluyen lógicos, carácteres, números enteros, y complejos. En esta lección, vamos a echar un vistazo más de cerca tipo de datos lógico y vectores de caracteres. 17 | 18 | - Class: text 19 | Output: Los vectores lógicos pueden contener los valores TRUE, FALSE, y NA (para "no disponible"). Estos valores se generan como resultado de 'condiciones' lógicas. Vamos a experimentar con algunas condiciones simples. 20 | 21 | - Class: cmd_question 22 | Output: En primer lugar, crearemos un vector numérico num_vect que contiene los valores de 0.5, 55, -10, Y 6. 23 | CorrectAnswer: num_vect <- c(0.5, 55, -10, 6) 24 | AnswerTests: omnitest(correctExpr='num_vect <- c(0.5, 55, -10, 6)') 25 | Hint: Recuerde que la función c() se utiliza para la creación de un vector. Si olvida cómo usarlo, utilice ?c para acceder al archivo de ayuda. No te olvides de asignar el resultado a una nueva variable llamada num_vect. 26 | 27 | - Class: cmd_question 28 | Output: Ahora, cree una variable denominada tf que toma el resultado de num_vect < 1, que se lee como "donde num_vect es a menor que 1". 29 | CorrectAnswer: tf <- num_vect < 1 30 | AnswerTests: omnitest(correctExpr='tf <- num_vect < 1') 31 | Hint: Utilice tf <- num_vect < 1 para asignar el resultado de num_vect < 1 a una variable denominada tf. 32 | 33 | - Class: mult_question 34 | Output: ¿Qué opinas sobre a que se parece tf ? 35 | CorrectAnswer: un vector de 4 valores lógicos 36 | AnswerChoices: un vector de 4 valores lógicos; un único valor lógico 37 | AnswerTests: omnitest(correctVal='un vector de 4 valores lógicos') 38 | Hint: Recuerde nuestra lección sobre aritmética vectorial? El tema era que R realiza muchas operaciones sobre una base de elemento por elemento. Llamamos a estas operaciones 'vectorizadas'. 39 | 40 | - Class: cmd_question 41 | Output: Imprime el contenido de tf ahora. 42 | CorrectAnswer: tf 43 | AnswerTests: omnitest(correctExpr='tf') 44 | Hint: Sólo escribe tf y pulse Intro para ver el valor. 45 | 46 | - Class: text 47 | Output: La declaración num_vect < 1 es una condición y tf nos dice si cada uno de los correspondientes elementos numéricos del vector num_vect satisface esta condición. 48 | 49 | - Class: text 50 | Output: El primer elemento de num_vect es 0,5, que es inferior a 1 y por lo tanto la declaración 0.5 < 1 es TRUE. El segundo elemento de num_vect es 55, que es mayor que 1, por lo que la declaración 55 < 1 es FALSE. La misma lógica se aplica para los elementos tercero y cuarto. 51 | 52 | - Class: cmd_question 53 | Output: Vamos a intentar otra. Escriba num_vect >= 6 sin asignar el resultado a una nueva variable. 54 | CorrectAnswer: num_vect >= 6 55 | AnswerTests: omnitest(correctExpr='num_vect >= 6') 56 | Hint: No cree una nueva variable en este caso. Sólo queremos ver el resultado de num_vect >= 6. Asegúrese de que no hay espacio entre los `>` y `=` símbolos. Piense de ellos como un símbolo que representa 'mayor o igual que'. 57 | 58 | - Class: text 59 | Output: Esta vez, estamos preguntando si cada elemento individual de num_vect es mayor o igual a 6. Dado que sólo 55 y 6 son mayor o igual a 6, los segundo y cuarto elementos del resultado son TRUE y los primero y tercer elementos son FALSE. 60 | 61 | - Class: text 62 | Output: Los símbolos `<` y `>=` en estos ejemplos son llamados 'operadores lógicos'. Otros operadores lógicos incluyen `>`, `<=`, `==` para la igualdad exacta, y `!=` Para la desigualdad. 63 | 64 | - Class: text 65 | Output: Si tenemos dos expresiones lógicas, A y B, podemos preguntarnos si, al menos, uno es TRUE con A | B ('o' lógico alias 'unión') o si son ambos TRUE con A & B ('y' lógico alias 'intersección'). Por último, !A es la negación de A y es cierto cuando A es FALSO y viceversa. 66 | 67 | - Class: text 68 | Output: Es una buena idea pasar algún tiempo jugando con diversas combinaciones de estos operadores lógicos hasta que se sienta cómodo con su uso. Bien, seguimos con algunos ejemplos para empezar. 69 | 70 | - Class: text 71 | Output: Haga su mejor esfuerzo para predecir el resultado de cada una de las siguientes afirmaciones. Puede usar lápiz y papel para resolverlos si es útil. Si te quedas atascado, simplemente adivinar y usted tiene una probabilidad del 50% de obtener la respuesta correcta! 72 | 73 | - Class: mult_question 74 | Output: (3 > 5) & (4 == 4) 75 | CorrectAnswer: 'FALSE' 76 | AnswerChoices: TRUE; FALSE 77 | AnswerTests: omnitest(correctVal='FALSE') 78 | Hint: Para resolver este problema hay que romperlo en 2 piezas. El `&` como conector entre dos piezas que son TRUE. Su trabajo consiste en averiguar si esto es una declaración correcta. Si así, toda la condición es TRUE. Si no, es FALSE. 79 | 80 | - Class: mult_question 81 | Output: (TRUE == TRUE) | (TRUE == FALSE) 82 | CorrectAnswer: 'TRUE' 83 | AnswerChoices: TRUE; FALSE 84 | AnswerTests: omnitest(correctVal='TRUE') 85 | Hint: Rompamos este problema en 2 piezas. El `|` es en conector entre los estados intermedios en dosnde al menos una de las piezas es TRUE. Su trabajo consiste en averiguar si eso es una afirmación precisa. Si es así, toda la condición es TRUE. Si no, es FALSO. 86 | 87 | - Class: mult_question 88 | Output: ((111 >= 111) | !(TRUE)) & ((4 + 1) == 5) 89 | CorrectAnswer: 'TRUE' 90 | AnswerChoices: TRUE; FALSE 91 | AnswerTests: omnitest(correctVal='TRUE') 92 | Hint: This is a tricky one. Remember that the `!` symbol negates whatever comes 93 | after it. There's also an 'order of operations' going on here. Conditions that 94 | are enclosed within parentheses should be evaluated first. Then, work your way 95 | outwards. 96 | Este es un asunto difícil. Recuerde que el símbolo `!` niega lo que venga después. También ocurre aquí que hay un "orden de las operaciones". Condiciones que están encerrados entre paréntesis deben ser evaluadas primero. Entonces, la forma de evaluarlas es hacia el exterior. 97 | 98 | - Class: text 99 | Output: No se preocupe si usted encuentra esto complicado. Se supone que lo sea. El trabajo con las declaraciones lógicas en R requiere práctica, pero serán recompensados ​​sus esfuerzos en lecciones futuras (por ejemplo, subconjuntos y estructuras de control) 100 | 101 | - Class: text 102 | Output: Los vectores de caracteres también son muy comunes en R. Las comillas dobles se utilizan para distinguir objetos de tipo carácter, como en el siguiente ejemplo. 103 | 104 | - Class: cmd_question 105 | Output: 'Cree un vector de caracteres que contenga las siguientes palabras: "Mi", "nombre", "es". Recuerde que debe incluir cada palabra en su propio conjunto de comillas dobles, de forma que R sepa que son cadenas de caracteres. Guarde el vector en una variable llamada my_char.' 106 | CorrectAnswer: my_char <- c("Mi", "nombre", "es") 107 | AnswerTests: omnitest(correctExpr='my_char <- c("Mi", "nombre", "es")') 108 | Hint: Escriba my_char <- c("Mi", "nombre", "es") para crear una nueva variable llamada my_char que contiene un vector de caracteres de longitud 3. Asegúrese de que las comas de separación de las palabras están fuera de las comillas dobles, o sino R pensara que las comas son parte de las palabras. 109 | 110 | - Class: cmd_question 111 | Output: Imprime el contenido de my_char para ver como luce. 112 | CorrectAnswer: my_char 113 | AnswerTests: omnitest(correctExpr='my_char') 114 | Hint: Escriba my_char para ver su contenido. 115 | 116 | - Class: text 117 | Output: En este momento, my_char es un vector de caracteres de longitud 3. Digamos que queremos unir a los elementos de my_char juntos en una cadena de caracteres continua (Es decir, un vector de caracteres de longitud 1). Podemos hacer esto utilizando la función de paste(). 118 | 119 | - Class: cmd_question 120 | Output: Escriba de paste(my_char, collapse = " ") ahora. Asegúrese de que hay un espacio entre las dobles comillas en el argumento `collapse`. Usted verá por qué en un segundo. 121 | CorrectAnswer: paste(my_char, collapse = " ") 122 | AnswerTests: omnitest(correctExpr='paste(my_char, collapse = " ")') 123 | Hint: Utilice paste(my_char, collapse = " ") para colapsar las palabras en el vector de modo que así formen una frase. Debe haber un único espacio entre las doble comillas en el argumento `collapse` para que haya espacios individuales que separen las palabras. 124 | 125 | - Class: text 126 | Output: El argumento `collapse` de la función paste() le dice a R que cuando unamos los elementos del vector de caracteres my_char, nos gustaría separarlos con espacios individuales. 127 | 128 | - Class: text 129 | Output: Parece que nos falta algo .... ¡Ah, sí! ¡Su nombre! 130 | 131 | - Class: cmd_question 132 | Output: 'Para añadir (o ''concatenar'') su nombre al final de my_char, utilice la función c() como esta: c(my_char, "your_name_here"). Coloque su nombre entre comillas dobles en "Your_Name_Here". Pruébalo ahora, almacenando el resultado en una nueva variable llamada my_name.' 133 | CorrectAnswer: my_name <- c(my_char, "Swirl") 134 | AnswerTests: var_is_a("character", "my_name"); expr_uses_func("c"); expr_creates_var("my_name"); val_has_length(4) 135 | Hint: Añada su nombre en al final del vector my_char utilizando la función c(). Asegúrese de asignar el resultado a una nueva variable llamada my_name. Por ejemplo sí su nombre fuera "Remolino", debería escribir my_name <- c(my_char, "Remolino"). 136 | 137 | - Class: cmd_question 138 | Output: Echa un vistazo a los contenidos de my_name. 139 | CorrectAnswer: my_name 140 | AnswerTests: omnitest(correctExpr='my_name') 141 | Hint: Escriba my_name y pulse Intro para ver su contenido. 142 | 143 | - Class: cmd_question 144 | Output: Ahora, utilice la función paste() una vez más para unir las palabras en my_name juntas en una sola cadena de caracteres. No olvides decir collapse = " "! 145 | CorrectAnswer: paste(my_name, collapse = " ") 146 | AnswerTests: omnitest(correctExpr='paste(my_name, collapse = " ")') 147 | Hint: Use paste(my_name, collapse = " ") para unir las cuatro palabras juntas, separadas por espacios. 148 | 149 | - Class: text 150 | Output: En este ejemplo, hemos utilizado la función paste() para colapsar los elementos de un vector de caracteres único . paste() también se puede utilizar para unir a los elementos de múltiples vectores de caracteres. 151 | 152 | - Class: cmd_question 153 | Output: En el caso más sencillo, podemos unir dos vectores de caracteres que son cada uno de longitud 1 (es decir, se unen dos palabras). Trate de paste("Hola", "mundo!", sep = " "), donde el argumento `sep` dice R que queremos separar los elementos unidos con un espacio sencillo. 154 | CorrectAnswer: paste("Hola", "mundo!", sep = " ") 155 | AnswerTests: omnitest(correctExpr='paste("Hola", "mundo!", sep = " ")') 156 | Hint: Introduzca paste("Hola", "mundo!", sep = " ") para unir las dos palabras "Hola" y "mundo", separados por un solo espacio. Debe haber un único espacio entre el comillas dobles en el argumento `sep` a la función paste(). 157 | 158 | - Class: cmd_question 159 | Output: Para un ejemplo un poco más complicado, podemos unir dos vectores, cada uno de longitud 3. Utilice paste() para unir el vector entero 1:3 con el vector de caracteres c("X", "Y", "Z"). Esta vez, utilice sep = "" Para no dejar espacio entre los elementos unidos. 160 | CorrectAnswer: paste(1:3, c("X", "Y", "Z"), sep = "") 161 | AnswerTests: any_of_exprs('paste(1:3, c("X", "Y", "Z"), sep = "")', 'paste(c(1:3), c("X", "Y", "Z"), sep = "")') 162 | Hint: Use paste(1:3, c("X", "Y", "Z"), sep = "") para ver lo que sucede cuando unimos dos vectores de igual longitud utilizando paste(). 163 | 164 | - Class: text 165 | Output: '¿Qué crees que sucederá si nuestros vectores son de diferente longitud? (Sugerencia: hemos hablado de esto en una lección anterior.)' 166 | 167 | - Class: cmd_question 168 | Output: Reciclaje del vector! Intente paste(LETTERS, 1:4, sep = "-"), donde LETTERS es una variable predefinida en R que contiene un vector de caracteres de las 26 letras con el Alfabeto inglés. 169 | CorrectAnswer: paste(LETTERS, 1:4, sep = "-") 170 | AnswerTests: omnitest(correctExpr='paste(LETTERS, 1:4, sep = "-")') 171 | Hint: Escriba paste(LETTERS, 1:4, sep = "-") para ver cómo R recicla el vector 1:4 para que coincida la longitud de las letras. Nótese que estamos usando `-` como nuestro separador esta vez en lugar de un solo espacio. 172 | 173 | - Class: text 174 | Output: Dado que el vector de caracteres LETTERS es más largo que el vector numérico 1:4, R simplemente recicla, o repite, 1:4 hasta que coincida con la longitud de LETTERS. 175 | 176 | 177 | - Class: text 178 | Output: También digno de mención es que el vector numérico 1:4 se a 'coercionado' en un vector de caracteres por la función de paste(). 179 | 180 | - Class: text 181 | Output: Vamos a discutir la coerción en otra lección, pero todo lo que realmente significa es que los números 1, 2, 3 y 4 en la salida anterior ya no son numeros para R, sino más bien los characteres "1", "2", "3" y "4". 182 | 183 | 184 | -------------------------------------------------------------------------------- /instalar_curso.R: -------------------------------------------------------------------------------- 1 | if (!require("devtools")) install.packages("devtools") 2 | if (!require("bitops")) install.packages("bitops") 3 | if (!require("RCurl")) install.packages("RCurl") 4 | if (!require("stringi")) install.packages("stringi") 5 | if (!require("httr")) install.packages("httr") 6 | if (!require("swirl")) install.packages("swirl") 7 | #install.packages("devtools", "bitops", "RCurl", "stringi", "httr", "swirl") 8 | library(devtools) 9 | library(bitops) 10 | library(RCurl) 11 | library(httr) 12 | library(swirl) 13 | set_config( config( ssl_verifypeer = 0L ) ) 14 | if (file.exists("/opt/R/home/library/swirl/Courses/Programando_en_R")) { 15 | uninstall_course("Programando_en_R") 16 | } 17 | install_course_github('josersosa','Programando_en_R') 18 | select_language(language = "spanish") 19 | 20 | -------------------------------------------------------------------------------- /lapply_and_sapply/customTests.R: -------------------------------------------------------------------------------- 1 | # So swirl does not repeat execution of commands 2 | # AUTO_DETECT_NEWVAR <- FALSE 3 | 4 | expr_creates_var <- function(correctName=NULL){ 5 | e <- get("e", parent.frame()) 6 | # TODO: Eventually make auto-detection of new variables an option. 7 | # Currently it can be set in customTests.R 8 | delta <- if(!customTests$AUTO_DETECT_NEWVAR){ 9 | safeEval(e$expr, e) 10 | } else { 11 | e$delta 12 | } 13 | if(is.null(correctName)){ 14 | results <- expectThat(length(delta) >= 1, 15 | testthat::is_true(), 16 | label=paste(deparse(e$expr), 17 | "does not create a variable.")) 18 | } else { 19 | results <- expectThat(correctName %in% names(delta), 20 | testthat::is_true(), 21 | label=paste(deparse(e$expr), 22 | "does not create a variable named", 23 | correctName)) 24 | } 25 | if(results$passed){ 26 | e$newVar <- e$val 27 | e$newVarName <- names(delta)[1] 28 | e$delta <- mergeLists(delta, e$delta) 29 | } else { 30 | e$delta <- list() 31 | } 32 | return(results$passed) 33 | } 34 | 35 | # Returns TRUE if the user has calculated a value equal to that calculated by the given expression. 36 | calculates_same_value <- function(expr){ 37 | e <- get("e", parent.frame()) 38 | # Calculate what the user should have done. 39 | eSnap <- cleanEnv(e$snapshot) 40 | val <- eval(parse(text=expr), eSnap) 41 | passed <- isTRUE(all.equal(val, e$val)) 42 | if(!passed)e$delta <- list() 43 | return(passed) 44 | } 45 | 46 | omnitest <- function(correctExpr=NULL, correctVal=NULL, strict=FALSE){ 47 | e <- get("e", parent.frame()) 48 | # Trivial case 49 | if(is.null(correctExpr) && is.null(correctVal))return(TRUE) 50 | # Testing for correct expression only 51 | if(!is.null(correctExpr) && is.null(correctVal)){ 52 | passed <- expr_identical_to(correctExpr) 53 | if(!passed)e$delta <- list() 54 | return(passed) 55 | } 56 | # Testing for both correct expression and correct value 57 | # Value must be character or single number 58 | valGood <- NULL 59 | if(!is.null(correctVal)){ 60 | if(is.character(e$val)){ 61 | valResults <- expectThat(e$val, 62 | is_equivalent_to(correctVal, label=correctVal), 63 | label=(e$val)) 64 | if(is(e, "dev") && !valResults$passed)swirl_out(valResults$message) 65 | valGood <- valResults$passed 66 | # valGood <- val_matches(correctVal) 67 | } else if(!is.na(e$val) && is.numeric(e$val) && length(e$val) == 1){ 68 | cval <- try(as.numeric(correctVal), silent=TRUE) 69 | valResults <- expectThat(e$val, 70 | equals(cval, label=correctVal), 71 | label=toString(e$val)) 72 | if(is(e, "dev") && !valResults$passed)swirl_out(valResults$message) 73 | valGood <- valResults$passed 74 | } 75 | } 76 | exprGood <- ifelse(is.null(correctExpr), TRUE, expr_identical_to(correctExpr)) 77 | if(valGood && exprGood){ 78 | return(TRUE) 79 | } else if (valGood && !exprGood && !strict){ 80 | swirl_out("That's not the expression I expected but it works.") 81 | swirl_out("I've executed the correct expression in case the result is needed in an upcoming question.") 82 | eval(parse(text=correctExpr),globalenv()) 83 | return(TRUE) 84 | } else { 85 | e$delta <- list() 86 | return(FALSE) 87 | } 88 | } 89 | 90 | match_call <- function(correct_call = NULL) { 91 | e <- get("e", parent.frame()) 92 | # Trivial case 93 | if(is.null(correct_call)) return(TRUE) 94 | # Get full correct call 95 | full_correct_call <- expand_call(correct_call) 96 | # Expand user's expression 97 | expr <- deparse(e$expr) 98 | full_user_expr <- expand_call(expr) 99 | # Compare function calls with full arg names 100 | identical(full_correct_call, full_user_expr) 101 | } 102 | 103 | # Utility function for match_call answer test 104 | # Fills out a function call with full argument names 105 | expand_call <- function(call_string) { 106 | # Quote expression 107 | qcall <- parse(text=call_string)[[1]] 108 | # If expression is not greater than length 1... 109 | if(length(qcall) <= 1) return(qcall) 110 | # See if it's an assignment 111 | is_assign <- is(qcall, "<-") 112 | # If assignment, process righthandside 113 | if(is_assign) { 114 | # Get righthand side 115 | rhs <- qcall[[3]] 116 | # If righthand side is not a call, can't use match.fun() 117 | if(!is.call(rhs)) return(qcall) 118 | # Get function from function name 119 | fun <- match.fun(rhs[[1]]) 120 | # match.call() does not support primitive functions 121 | if(is.primitive(fun)) return(qcall) 122 | # Get expanded call 123 | full_rhs <- match.call(fun, rhs) 124 | # Full call 125 | qcall[[3]] <- full_rhs 126 | } else { # If not assignment, process whole thing 127 | # Get function from function name 128 | fun <- match.fun(qcall[[1]]) 129 | # match.call() does not support primitive functions 130 | if(is.primitive(fun)) return(qcall) 131 | # Full call 132 | qcall <- match.call(fun, qcall) 133 | } 134 | # Return expanded function call 135 | qcall 136 | } 137 | 138 | # Returns TRUE if e$expr matches any of the expressions given 139 | # (as characters) in the argument. 140 | ANY_of_exprs <- function(...){ 141 | e <- get("e", parent.frame()) 142 | any(sapply(c(...), function(expr)omnitest(expr))) 143 | } 144 | 145 | 146 | 147 | notify <- function() { 148 | e <- get("e", parent.frame()) 149 | if(e$val == "No") return(TRUE) 150 | 151 | good <- FALSE 152 | while(!good) { 153 | # Get info 154 | name <- readline_clean("What is your full name? ") 155 | address <- readline_clean("What is the email address of the person you'd like to notify? ") 156 | 157 | # Repeat back to them 158 | message("\nDoes everything look good?\n") 159 | message("Your name: ", name, "\n", "Send to: ", address) 160 | 161 | yn <- select.list(c("Yes", "No"), graphics = FALSE) 162 | if(yn == "Yes") good <- TRUE 163 | } 164 | 165 | # Get course and lesson names 166 | course_name <- attr(e$les, "course_name") 167 | lesson_name <- attr(e$les, "lesson_name") 168 | 169 | subject <- paste(name, "just completed", course_name, "-", lesson_name) 170 | body = "" 171 | 172 | # Send email 173 | swirl:::email(address, subject, body) 174 | 175 | hrule() 176 | message("I just tried to create a new email with the following info:\n") 177 | message("To: ", address) 178 | message("Subject: ", subject) 179 | message("Body: ") 180 | 181 | message("\nIf it didn't work, you can send the same email manually.") 182 | hrule() 183 | 184 | # Return TRUE to satisfy swirl and return to course menu 185 | TRUE 186 | } 187 | 188 | readline_clean <- function(prompt = "") { 189 | wrapped <- strwrap(prompt, width = getOption("width") - 2) 190 | mes <- stringr::str_c("| ", wrapped, collapse = "\n") 191 | message(mes) 192 | readline() 193 | } 194 | 195 | hrule <- function() { 196 | message("\n", paste0(rep("#", getOption("width") - 2), collapse = ""), "\n") 197 | } 198 | -------------------------------------------------------------------------------- /lapply_and_sapply/flag.names.txt: -------------------------------------------------------------------------------- 1 | 1. Title: Flag database 2 | 3 | 2. Source Information 4 | -- Creators: Collected primarily from the "Collins Gem Guide to Flags": 5 | Collins Publishers (1986). 6 | -- Donor: Richard S. Forsyth 7 | 8 Grosvenor Avenue 8 | Mapperley Park 9 | Nottingham NG3 5DX 10 | 0602-621676 11 | -- Date: 5/15/1990 12 | 13 | 3. Past Usage: 14 | -- None known other than what is shown in Forsyth's PC/BEAGLE User's Guide. 15 | 16 | 4. Relevant Information: 17 | -- This data file contains details of various nations and their flags. 18 | In this file the fields are separated by spaces (not commas). With 19 | this data you can try things like predicting the religion of a country 20 | from its size and the colours in its flag. 21 | -- 10 attributes are numeric-valued. The remainder are either Boolean- 22 | or nominal-valued. 23 | 24 | 5. Number of Instances: 194 25 | 26 | 6. Number of attributes: 30 (overall) 27 | 28 | 7. Attribute Information: 29 | 1. name Name of the country concerned 30 | 2. landmass 1=N.America, 2=S.America, 3=Europe, 4=Africa, 4=Asia, 6=Oceania 31 | 3. zone Geographic quadrant, based on Greenwich and the Equator 32 | 1=NE, 2=SE, 3=SW, 4=NW 33 | 4. area in thousands of square km 34 | 5. population in round millions 35 | 6. language 1=English, 2=Spanish, 3=French, 4=German, 5=Slavic, 6=Other 36 | Indo-European, 7=Chinese, 8=Arabic, 37 | 9=Japanese/Turkish/Finnish/Magyar, 10=Others 38 | 7. religion 0=Catholic, 1=Other Christian, 2=Muslim, 3=Buddhist, 4=Hindu, 39 | 5=Ethnic, 6=Marxist, 7=Others 40 | 8. bars Number of vertical bars in the flag 41 | 9. stripes Number of horizontal stripes in the flag 42 | 10. colours Number of different colours in the flag 43 | 11. red 0 if red absent, 1 if red present in the flag 44 | 12. green same for green 45 | 13. blue same for blue 46 | 14. gold same for gold (also yellow) 47 | 15. white same for white 48 | 16. black same for black 49 | 17. orange same for orange (also brown) 50 | 18. mainhue predominant colour in the flag (tie-breaks decided by taking 51 | the topmost hue, if that fails then the most central hue, 52 | and if that fails the leftmost hue) 53 | 19. circles Number of circles in the flag 54 | 20. crosses Number of (upright) crosses 55 | 21. saltires Number of diagonal crosses 56 | 22. quarters Number of quartered sections 57 | 23. sunstars Number of sun or star symbols 58 | 24. crescent 1 if a crescent moon symbol present, else 0 59 | 25. triangle 1 if any triangles present, 0 otherwise 60 | 26. icon 1 if an inanimate image present (e.g., a boat), otherwise 0 61 | 27. animate 1 if an animate image (e.g., an eagle, a tree, a human hand) 62 | present, 0 otherwise 63 | 28. text 1 if any letters or writing on the flag (e.g., a motto or 64 | slogan), 0 otherwise 65 | 29. topleft colour in the top-left corner (moving right to decide 66 | tie-breaks) 67 | 30. botright Colour in the bottom-left corner (moving left to decide 68 | tie-breaks) 69 | 70 | 8. Missing values: None -------------------------------------------------------------------------------- /lapply_and_sapply/initLesson.R: -------------------------------------------------------------------------------- 1 | # Path to installed lesson 2 | .lessonpath <- file.path(path.package("swirl"), "Courses", 3 | "Programando_en_R", "lapply_and_sapply") 4 | # Path to dataset 5 | .datapath <- file.path(.lessonpath, "flag.data.txt") 6 | # Load dataset 7 | flags <- read.csv(.datapath, header=FALSE) 8 | # Set column names 9 | colnames(flags) <- c("name", "landmass", "zone", "area", "population", 10 | "language", "religion", "bars", "stripes", "colours", 11 | "red", "green", "blue", "gold", "white", "black", 12 | "orange", "mainhue", "circles", "crosses", "saltires", 13 | "quarters", "sunstars", "crescent", "triangle", 14 | "icon", "animate", "text", "topleft", "botright") 15 | # Path to dataset info 16 | .infopath <- file.path(.lessonpath, "flag.names.txt") 17 | # Function for user to open info 18 | viewinfo <- function() { 19 | file.edit(.infopath) 20 | return(.infopath) 21 | } -------------------------------------------------------------------------------- /vapply_and_tapply/customTests.R: -------------------------------------------------------------------------------- 1 | # So swirl does not repeat execution of commands 2 | # AUTO_DETECT_NEWVAR <- FALSE 3 | 4 | expr_creates_var <- function(correctName=NULL){ 5 | e <- get("e", parent.frame()) 6 | # TODO: Eventually make auto-detection of new variables an option. 7 | # Currently it can be set in customTests.R 8 | delta <- if(!customTests$AUTO_DETECT_NEWVAR){ 9 | safeEval(e$expr, e) 10 | } else { 11 | e$delta 12 | } 13 | if(is.null(correctName)){ 14 | results <- expectThat(length(delta) >= 1, 15 | testthat::is_true(), 16 | label=paste(deparse(e$expr), 17 | "does not create a variable.")) 18 | } else { 19 | results <- expectThat(correctName %in% names(delta), 20 | testthat::is_true(), 21 | label=paste(deparse(e$expr), 22 | "does not create a variable named", 23 | correctName)) 24 | } 25 | if(results$passed){ 26 | e$newVar <- e$val 27 | e$newVarName <- names(delta)[1] 28 | e$delta <- mergeLists(delta, e$delta) 29 | } else { 30 | e$delta <- list() 31 | } 32 | return(results$passed) 33 | } 34 | 35 | # Returns TRUE if the user has calculated a value equal to that calculated by the given expression. 36 | calculates_same_value <- function(expr){ 37 | e <- get("e", parent.frame()) 38 | # Calculate what the user should have done. 39 | eSnap <- cleanEnv(e$snapshot) 40 | val <- eval(parse(text=expr), eSnap) 41 | passed <- isTRUE(all.equal(val, e$val)) 42 | if(!passed)e$delta <- list() 43 | return(passed) 44 | } 45 | 46 | omnitest <- function(correctExpr=NULL, correctVal=NULL, strict=FALSE){ 47 | e <- get("e", parent.frame()) 48 | # Trivial case 49 | if(is.null(correctExpr) && is.null(correctVal))return(TRUE) 50 | # Testing for correct expression only 51 | if(!is.null(correctExpr) && is.null(correctVal)){ 52 | passed <- expr_identical_to(correctExpr) 53 | if(!passed)e$delta <- list() 54 | return(passed) 55 | } 56 | # Testing for both correct expression and correct value 57 | # Value must be character or single number 58 | valGood <- NULL 59 | if(!is.null(correctVal)){ 60 | if(is.character(e$val)){ 61 | valResults <- expectThat(e$val, 62 | is_equivalent_to(correctVal, label=correctVal), 63 | label=(e$val)) 64 | if(is(e, "dev") && !valResults$passed)swirl_out(valResults$message) 65 | valGood <- valResults$passed 66 | # valGood <- val_matches(correctVal) 67 | } else if(!is.na(e$val) && is.numeric(e$val) && length(e$val) == 1){ 68 | cval <- try(as.numeric(correctVal), silent=TRUE) 69 | valResults <- expectThat(e$val, 70 | equals(cval, label=correctVal), 71 | label=toString(e$val)) 72 | if(is(e, "dev") && !valResults$passed)swirl_out(valResults$message) 73 | valGood <- valResults$passed 74 | } 75 | } 76 | exprGood <- ifelse(is.null(correctExpr), TRUE, expr_identical_to(correctExpr)) 77 | if(valGood && exprGood){ 78 | return(TRUE) 79 | } else if (valGood && !exprGood && !strict){ 80 | swirl_out("That's not the expression I expected but it works.") 81 | swirl_out("I've executed the correct expression in case the result is needed in an upcoming question.") 82 | eval(parse(text=correctExpr),globalenv()) 83 | return(TRUE) 84 | } else { 85 | e$delta <- list() 86 | return(FALSE) 87 | } 88 | } 89 | 90 | match_call <- function(correct_call = NULL) { 91 | e <- get("e", parent.frame()) 92 | # Trivial case 93 | if(is.null(correct_call)) return(TRUE) 94 | # Get full correct call 95 | full_correct_call <- expand_call(correct_call) 96 | # Expand user's expression 97 | expr <- deparse(e$expr) 98 | full_user_expr <- expand_call(expr) 99 | # Compare function calls with full arg names 100 | identical(full_correct_call, full_user_expr) 101 | } 102 | 103 | # Utility function for match_call answer test 104 | # Fills out a function call with full argument names 105 | expand_call <- function(call_string) { 106 | # Quote expression 107 | qcall <- parse(text=call_string)[[1]] 108 | # If expression is not greater than length 1... 109 | if(length(qcall) <= 1) return(qcall) 110 | # See if it's an assignment 111 | is_assign <- is(qcall, "<-") 112 | # If assignment, process righthandside 113 | if(is_assign) { 114 | # Get righthand side 115 | rhs <- qcall[[3]] 116 | # If righthand side is not a call, can't use match.fun() 117 | if(!is.call(rhs)) return(qcall) 118 | # Get function from function name 119 | fun <- match.fun(rhs[[1]]) 120 | # match.call() does not support primitive functions 121 | if(is.primitive(fun)) return(qcall) 122 | # Get expanded call 123 | full_rhs <- match.call(fun, rhs) 124 | # Full call 125 | qcall[[3]] <- full_rhs 126 | } else { # If not assignment, process whole thing 127 | # Get function from function name 128 | fun <- match.fun(qcall[[1]]) 129 | # match.call() does not support primitive functions 130 | if(is.primitive(fun)) return(qcall) 131 | # Full call 132 | qcall <- match.call(fun, qcall) 133 | } 134 | # Return expanded function call 135 | qcall 136 | } 137 | 138 | # Returns TRUE if e$expr matches any of the expressions given 139 | # (as characters) in the argument. 140 | ANY_of_exprs <- function(...){ 141 | e <- get("e", parent.frame()) 142 | any(sapply(c(...), function(expr)omnitest(expr))) 143 | } 144 | 145 | 146 | 147 | notify <- function() { 148 | e <- get("e", parent.frame()) 149 | if(e$val == "No") return(TRUE) 150 | 151 | good <- FALSE 152 | while(!good) { 153 | # Get info 154 | name <- readline_clean("What is your full name? ") 155 | address <- readline_clean("What is the email address of the person you'd like to notify? ") 156 | 157 | # Repeat back to them 158 | message("\nDoes everything look good?\n") 159 | message("Your name: ", name, "\n", "Send to: ", address) 160 | 161 | yn <- select.list(c("Yes", "No"), graphics = FALSE) 162 | if(yn == "Yes") good <- TRUE 163 | } 164 | 165 | # Get course and lesson names 166 | course_name <- attr(e$les, "course_name") 167 | lesson_name <- attr(e$les, "lesson_name") 168 | 169 | subject <- paste(name, "just completed", course_name, "-", lesson_name) 170 | body = "" 171 | 172 | # Send email 173 | swirl:::email(address, subject, body) 174 | 175 | hrule() 176 | message("I just tried to create a new email with the following info:\n") 177 | message("To: ", address) 178 | message("Subject: ", subject) 179 | message("Body: ") 180 | 181 | message("\nIf it didn't work, you can send the same email manually.") 182 | hrule() 183 | 184 | # Return TRUE to satisfy swirl and return to course menu 185 | TRUE 186 | } 187 | 188 | readline_clean <- function(prompt = "") { 189 | wrapped <- strwrap(prompt, width = getOption("width") - 2) 190 | mes <- stringr::str_c("| ", wrapped, collapse = "\n") 191 | message(mes) 192 | readline() 193 | } 194 | 195 | hrule <- function() { 196 | message("\n", paste0(rep("#", getOption("width") - 2), collapse = ""), "\n") 197 | } 198 | -------------------------------------------------------------------------------- /vapply_and_tapply/initLesson.R: -------------------------------------------------------------------------------- 1 | # Path to installed lesson 2 | .lessonpath <- file.path(path.package("swirl"), "Courses", 3 | "Programando_en_R", "lapply_and_sapply") 4 | # Path to dataset 5 | .datapath <- file.path(.lessonpath, "flag.data.txt") 6 | # Load dataset 7 | flags <- read.csv(.datapath, header=FALSE) 8 | # Set column names 9 | colnames(flags) <- c("name", "landmass", "zone", "area", "population", 10 | "language", "religion", "bars", "stripes", "colours", 11 | "red", "green", "blue", "gold", "white", "black", 12 | "orange", "mainhue", "circles", "crosses", "saltires", 13 | "quarters", "sunstars", "crescent", "triangle", 14 | "icon", "animate", "text", "topleft", "botright") 15 | # Path to dataset info 16 | .infopath <- file.path(.lessonpath, "flag.names.txt") 17 | # Function for user to open info 18 | viewinfo <- function() { 19 | file.edit(.infopath) 20 | return(.infopath) 21 | } 22 | 23 | # Dummy function to advance user past question for which 24 | # correct answer yields an error 25 | ok <- function() { 26 | invisible() 27 | } -------------------------------------------------------------------------------- /vapply_and_tapply/lesson.yaml: -------------------------------------------------------------------------------- 1 | - Class: meta 2 | Course: Programando en R 3 | Lesson: vapply y tapply 4 | Author: Nick Carchedi 5 | Type: Standard 6 | Organization: JHU Biostat 7 | Version: 2.2.11 8 | 9 | - Class: text 10 | Output: "En la última lección, usted aprendió sobre dos de los miembros más importantes de la familia de funciones *apply de R: lapply() y sapply(). Ambos toman una lista como entrada, aplican una función a cada elemento de la lista y entonces combinan y devuelven el resultado. lapply() siempre devuelve una lista, mientras que sapply() intenta simplificar el resultado como un vector." 11 | 12 | - Class: text 13 | Output: En esta lección, aprenderá cómo utilizar vapply() y tapply(), cada uno de los cuales sirve a un propósito muy específico dentro de la metodología Dividir-Aplicar-Combinar. Por coherencia, vamos a utilizar el mismo conjunto de datos que utilizamos en la lección "lapply y sapply". 14 | 15 | - Class: text 16 | Output: "El conjunto de datos flags del aprendizaje del repositorio UCI Machine contiene detalles de diversas naciones y sus banderas. Más información se puede encontrar aquí: Http://archive.ics.uci.edu/ml/datasets/Flags" 17 | 18 | - Class: text 19 | Output: He almacenado los datos en una variable llamada flags. Si ha pasado un tiempo desde que completó la lección "lapply y sapply", es posible que desee reencontrarse con los datos mediante el uso de funciones como dim(), head(), str() y summary() cuando regrese a la símbolo (>). También puede escribir viewinfo() en el indicador para que aparezca algún tipo de documentación para el conjunto de datos. ¡Empecemos! 20 | 21 | - Class: cmd_question 22 | Output: Como vimos en la lección anterior, la función unique() devuelve un vector de los valores únicos contenidos en el objeto que se le pasa. Por lo tanto, sapply(flags, unique) devuelve una lista que contiene un vector de valores únicos para cada columna del conjunto de datos flags. Inténtalo de nuevo ahora. 23 | CorrectAnswer: sapply(flags, unique) 24 | AnswerTests: omnitest(correctExpr='sapply(flags, unique)') 25 | Hint: Utilice sapply(flags, unique) para devolver una lista que contenga un vector de valores únicos para cada columna del conjunto de datos flags. 26 | 27 | - Class: text 28 | Output: ¿Si hubiera olvidado como funciona unique() y equivocadamente pensara que devuelve el *número* de los valores únicos contenidos en el objeto que se le pasa? Entonces podría haber esperado incorrectamente que sapply(flags, unique) devolvería un vector numérico, ya que cada elemento de la lista devuelta contendría un solo número y que sapply() entonces podría simplificar el resultado en un vector. 29 | 30 | - Class: text 31 | Output: Cuando se trabaja de forma interactiva (en el indicador >), esto no es un gran problema, ya que se ve el resultado de inmediato y puede reconocer rápidamente su error. Sin embargo, cuando se trabaja de forma no interactiva (por ejemplo, al escribir sus propias funciones), un malentendido puede pasar desapercibido y causar resultados incorrectos en el más adelante. Por lo tanto, es posible que desee tener más cuidado y ahí es donde vapply() es útil. 32 | 33 | - Class: text 34 | Output: Mientras que sapply() intenta "adivinar" el formato correcto del resultado, vapply() le permite especificarlo explícitamente. Si el resultado no coincide con el formato que especifique, vapply() lanzará un error que hirá que la operación se detenga. Esto puede evitar problemas significativos en su código, que podrían ser causados ​​por conseguir valores de retorno inesperado de sapply(). 35 | 36 | - Class: cmd_question 37 | Output: Intente con vapply(flags, unique, numeric(1)), donde se indica que usted espera que cada elemento del resultado sea un vector numérico de longitud 1. Dado que este NO es realmente el caso, obtendrá un error. Una vez que obtenga el error, escriba ok() para continuar con la siguiente pregunta. 38 | CorrectAnswer: ok() 39 | AnswerTests: omnitest(correctExpr="ok()") 40 | Hint: Escriba vapply(flags, unique, numeric(1)), a continuación, escriba ok() para continuar con la siguiente pregunta. 41 | 42 | - Class: cmd_question 43 | Output: Recuerde de la lección anterior que sapply(flags, class) devolverá un vector de caracteres que contiene la clase de cada columna en el conjunto de datos. Intente de nuevo ahora para ver el resultado. 44 | CorrectAnswer: sapply(flags, class) 45 | AnswerTests: omnitest(correctExpr="sapply(flags, class)") 46 | Hint: Escriba sapply(flags, class) para obtener un vector carácter con la clase de cada columna. 47 | 48 | - Class: cmd_question 49 | Output: Si queremos ser explícitos sobre el formato del resultado que esperamos, podemos utilizar vapply(flags, class, character(1)). El argumento 'character(1)' dice a R que esperamos que la función class devolverá un vector de caracteres de longitud 1 cuando se aplique a cada columna del conjunto de datos flags. Inténtalo ahora. 50 | CorrectAnswer: vapply(flags, class, character(1)) 51 | AnswerTests: omnitest(correctExpr="vapply(flags, class, character(1))") 52 | Hint: UUtilice vapply(flags, class, character(1)) para devolver un vector carácter de clases de columna. 53 | 54 | - Class: text 55 | Output: Tenga en cuenta que dado que nuestra expectativa era correcta (es decir que el formato de salida de class es character(1)), el resultado de vapply() es idéntico al de sapply() - un vector carácter de clases de columna. 56 | 57 | - Class: text 58 | Output: Usted puede pensar en vapply() como "más segura" que sapply(), ya que se requiere que se especifique el formato de la salida con antelación, en lugar de permitir que R 'adivine' lo que querías. Además, vapply() tiene mejor rendimiento que sapply() para grandes conjuntos de datos. Sin embargo, cuando se hace el análisis de datos de forma interactiva (en el indicador >), sapply(), nos ahorra un poco de escritura y suele ser lo suficientemente bueno. 59 | 60 | - Class: text 61 | Output: Como analista de datos, a menudo deseará dividir sus datos en grupos, en función del valor de una variable y luego aplicar una función a cada grupo. La siguiente función que veremos, tapply(), hace exactamente eso. 62 | 63 | - Class: cmd_question 64 | Output: Utilice ?tapply para desplegar la documentación de esta función. 65 | CorrectAnswer: ?tapply 66 | AnswerTests: any_of_exprs('?tapply', 'help(tapply)') 67 | Hint: Levante el archivo de ayuda con ?tapply 68 | 69 | - Class: cmd_question 70 | Output: La variable 'landmass' en nuestro conjunto de datos toma valores enteros entre 1 y 6, cada uno de los cuales representa una parte diferente del mundo (masas de tierra o masas continentales). Utilice la table(flags$landmass) para ver cuántas banderas/países se clasifican en cada grupo. 71 | CorrectAnswer: table(flags$landmass) 72 | AnswerTests: omnitest(correctExpr="table(flags$landmass)") 73 | Hint: Utilice table(flags$landmass) para ver cuántas banderas/países se clasifican en cada grupo. 74 | 75 | - Class: cmd_question 76 | Output: La variable 'animate' en nuestro conjunto de datos toma el valor 1 si la bandera de un país contiene una imagen animada (por ejemplo, un águila, un árbol, una mano humana) y 0 en caso contrario. Utilice table(flags$animate) para ver cuántas banderas contiene una imagen animada. 77 | CorrectAnswer: table(flags$animate) 78 | AnswerTests: omnitest(correctExpr="table(flags$animate)") 79 | Hint: Utilice table(flags$animate) para ver cuántas banderas contiene una imagen animada. 80 | 81 | - Class: text 82 | Output: Esto nos dice que 39 banderas contienen un objeto animado (animar = 1) y 155 no (animar = 0). 83 | 84 | - Class: cmd_question 85 | Output: Si se toma la media aritmética de un montón de 0s y 1s, se obtiene la proporción de 1s. Utilice tapply(flags$animate, flags$landmass, mean) para aplicar la función mean a la variable 'animate' por separado para cada uno de los seis grupos por masa continental, lo que nos da la proporción de banderas que contienen una imagen animada dentro de cada grupo de masa continental. 86 | CorrectAnswer: tapply(flags$animate, flags$landmass, mean) 87 | AnswerTests: omnitest(correctExpr="tapply(flags$animate, flags$landmass, mean)") 88 | Hint: tapply(flags$animate, flags$landmass, mean) nos indicará la proporción de banderas que contienen una imagen animada dentro de cada grupo de masa de tierra continental. 89 | 90 | - Class: text 91 | Output: El primer grupo de masa de tierra (landmass = 1) corresponde a América del Norte y contiene la mayor proporción de las banderas con una imagen animada con 0.4194 (41.9%). 92 | 93 | - Class: cmd_question 94 | Output: Del mismo modo, podemos ver un resumen de los valores de la población (redondeados en millones) para los países con y sin el color rojo de su bandera con tapply(flags$population, flags$red, summary). 95 | CorrectAnswer: tapply(flags$population, flags$red, summary) 96 | AnswerTests: omnitest(correctExpr="tapply(flags$population, flags$red, summary)") 97 | Hint: Puede ver un resumen de las poblaciones de los países con y sin el color rojo de su bandera con tapply(flags$population, flags$red, summary). 98 | 99 | - Class: mult_question 100 | Output: ¿Cuál es la mediana de la población (en millones) para los países *sin* el color rojo de su bandera? 101 | AnswerChoices: 9.0; 4.0; 27.6; 3.0; 22.1; 0.0 102 | CorrectAnswer: 3.0 103 | AnswerTests: omnitest(correctVal= '3.0') 104 | Hint: Utilice el resultado de la última pregunta. Recordemos que el red = 0 significa que el color rojo no está presente en la bandera del país. 105 | 106 | - Class: cmd_question 107 | Output: Por último, utilizar el mismo enfoque para ver un resumen de los valores de población para cada una de las seis masas continentales. 108 | CorrectAnswer: tapply(flags$population, flags$landmass, summary) 109 | AnswerTests: omnitest(correctExpr="tapply(flags$population, flags$landmass, summary)") 110 | Hint: "Se puede ver un resumen de las poblaciones de cada una de las seis masas llamando a tapply() con tres argumentos: flags$population, flags$landmass, and summary." 111 | 112 | - Class: mult_question 113 | Output: ¿Cuál es el máximo de población (en millones) para el cuarto grupo de masa (África)? 114 | AnswerChoices: 56.00; 1010.0; 119.0; 5.00; 157.00 115 | CorrectAnswer: 56.00 116 | AnswerTests: omnitest(correctVal= '56.00') 117 | Hint: Utilice el resultado de la última pregunta. 118 | 119 | - Class: text 120 | Output: En esta lección, ha aprendido a utilizar vapply() como una alternativa más segura a sapply(), que es más útil al escribir sus propias funciones. También ha aprendido a utilizar tapply() para dividir los datos en grupos basados ​​en el valor de una variable, luego aplicar una función a cada grupo. Estas funciones serán útiles en su búsqueda para convertirse en un mejor analista de datos. 121 | 122 | 123 | --------------------------------------------------------------------------------