Mostrando entradas con la etiqueta ifelse. Mostrar todas las entradas
Mostrando entradas con la etiqueta ifelse. Mostrar todas las entradas

2019-12-31

Calculate the difference between alternate rows in R

Problem

We want to calculate the difference between alternate rows in R

df <- 
structure(list(MemId = c(1, 2, 3, 4, 5,6), ET = structure(c(1506829256,
 1506829319, 1506843096,1506843226, 1506850144, 1506853708), class = 
c("POSIXct", "POSIXt"))), .Names = c("MemId", "ET"), row.names = c("1",
 "2", "14", "15", "37", "38"), class = "data.frame")
  MemId                  ET
1      1 2017-10-01 05:40:56
2      2 2017-10-01 05:41:59
14     3 2017-10-01 09:31:36
15     4 2017-10-01 09:33:46
37     5 2017-10-01 11:29:04
38     6 2017-10-01 12:28:28

Solution

First, we create a dummy column with 0 and 1. Then when id == 1 we calculate with difftime the difference between the value of the vector ET and the "previous" value lag(ET).

library(dplyr)
df %>%
  mutate(id = rep_len(0:1, nrow(df))) %>%
  mutate(dif = ifelse(id == 1, difftime(ET, lag(ET), units = "secs"), NA))
  MemId                  ET id  dif
1     1 2017-10-01 05:40:56  0   NA
2     2 2017-10-01 05:41:59  1   63
3     3 2017-10-01 09:31:36  0   NA
4     4 2017-10-01 09:33:46  1  130
5     5 2017-10-01 11:29:04  0   NA
6     6 2017-10-01 12:28:28  1 3564

2019-12-28

How to convert a continuous variable to discrete in R?

Problem

We want to convert continuous variable to discrete in R:

'Create a new qualitative variable, called Elite, by binning the Top10perc variable. We are going to divide universities into two groups based on whether or not the proportion of students coming from the top 10% of their high school classes exceeds 50%'.

library(ISLR)
library(tidyverse)
glimpse(College)
Observations: 777
Variables: 18
$ Private      Yes, Yes, Yes, Yes, Yes, Yes, Yes, Yes, Yes, Yes, Yes, Ye...
$ Apps         1660, 2186, 1428, 417, 193, 587, 353, 1899, 1038, 582, 17...
$ Accept       1232, 1924, 1097, 349, 146, 479, 340, 1720, 839, 498, 142...
$ Enroll       721, 512, 336, 137, 55, 158, 103, 489, 227, 172, 472, 484...
$ Top10perc    23, 16, 22, 60, 16, 38, 17, 37, 30, 21, 37, 44, 38, 44, 2...
$ Top25perc    52, 29, 50, 89, 44, 62, 45, 68, 63, 44, 75, 77, 64, 73, 4...
$ F.Undergrad  2885, 2683, 1036, 510, 249, 678, 416, 1594, 973, 799, 183...
$ P.Undergrad  537, 1227, 99, 63, 869, 41, 230, 32, 306, 78, 110, 44, 63...
$ Outstate     7440, 12280, 11250, 12960, 7560, 13500, 13290, 13868, 155...
$ Room.Board   3300, 6450, 3750, 5450, 4120, 3335, 5720, 4826, 4400, 338...
$ Books        450, 750, 400, 450, 800, 500, 500, 450, 300, 660, 500, 40...
$ Personal     2200, 1500, 1165, 875, 1500, 675, 1500, 850, 500, 1800, 6...
$ PhD          70, 29, 53, 92, 76, 67, 90, 89, 79, 40, 82, 73, 60, 79, 3...
$ Terminal     78, 30, 66, 97, 72, 73, 93, 100, 84, 41, 88, 91, 84, 87, ...
$ S.F.Ratio    18.1, 12.2, 12.9, 7.7, 11.9, 9.4, 11.5, 13.7, 11.3, 11.5,...
$ perc.alumni  12, 16, 30, 37, 2, 11, 26, 37, 23, 15, 31, 41, 21, 32, 26...
$ Expend       7041, 10527, 8735, 19016, 10922, 9727, 8861, 11487, 11644...
$ Grad.Rate    60, 56, 54, 59, 15, 55, 63, 73, 80, 52, 73, 76, 74, 68, 5...

Solution

  1. Option 1: form ISLR's book.
  2. Elite = rep("No", nrow(College))
    Elite[College$Top10perc > 50] = "Yes"
    Elite <- as.factor(Elite)
    college <- data.frame(College,  Elite)
    summary(college[, c("Top10perc", "Elite")])
    
    There are 78 elite universities.

      Top10perc     Elite    
     Min.   : 1.00   No :699  
     1st Qu.:15.00   Yes: 78  
     Median :23.00            
     Mean   :27.56            
     3rd Qu.:35.00            
     Max.   :96.00    
    
  3. Option 2: ifelse from base package and dplyr
  4. # base 
    College$Elite <- factor(ifelse(College$Top10perc > 50, "Yes", "No"))
    # dplyr
    library(dplyr)
    College <-
      college %>%
      mutate(Elite = factor(ifelse(College$Top10perc > 50, "Yes", "No")))
    
  5. Option 3: creating a logical vector.
  6. There are multiple options. I show two examples.

    college$Elite <- transform(College, Elite = Top10perc > 50)
    College$Elite <- College$Top10perc > 50
    

References

From 'An Introduction to Statistical Learning' (ISLR), page 54.

Related posts

2018-12-08

Discretización de variables en R

Problema

Deseamos discretizar una variable, es decir, convertir una variable continua en discreta. Utilizamos el conjunto de datos College del paquete ISLR. Crearemos una nueva variable cualitativa llamada Elite, discretizando la variable Top10perc. Vamos a dividir las universidades en dos grupos basados en si la proporción de nuevos estudiantes provienen de entre el 10% de los mejores alumnos de sus institutos excede o no el 50%.

library(ISLR)
library(tidyverse)
glimpse(College)
Observations: 777
Variables: 18
$ Private      Yes, Yes, Yes, Yes, Yes, Yes, Yes, Yes, Yes, Yes, Yes, Ye...
$ Apps         1660, 2186, 1428, 417, 193, 587, 353, 1899, 1038, 582, 17...
$ Accept       1232, 1924, 1097, 349, 146, 479, 340, 1720, 839, 498, 142...
$ Enroll       721, 512, 336, 137, 55, 158, 103, 489, 227, 172, 472, 484...
$ Top10perc    23, 16, 22, 60, 16, 38, 17, 37, 30, 21, 37, 44, 38, 44, 2...
$ Top25perc    52, 29, 50, 89, 44, 62, 45, 68, 63, 44, 75, 77, 64, 73, 4...
$ F.Undergrad  2885, 2683, 1036, 510, 249, 678, 416, 1594, 973, 799, 183...
$ P.Undergrad  537, 1227, 99, 63, 869, 41, 230, 32, 306, 78, 110, 44, 63...
$ Outstate     7440, 12280, 11250, 12960, 7560, 13500, 13290, 13868, 155...
$ Room.Board   3300, 6450, 3750, 5450, 4120, 3335, 5720, 4826, 4400, 338...
$ Books        450, 750, 400, 450, 800, 500, 500, 450, 300, 660, 500, 40...
$ Personal     2200, 1500, 1165, 875, 1500, 675, 1500, 850, 500, 1800, 6...
$ PhD          70, 29, 53, 92, 76, 67, 90, 89, 79, 40, 82, 73, 60, 79, 3...
$ Terminal     78, 30, 66, 97, 72, 73, 93, 100, 84, 41, 88, 91, 84, 87, ...
$ S.F.Ratio    18.1, 12.2, 12.9, 7.7, 11.9, 9.4, 11.5, 13.7, 11.3, 11.5,...
$ perc.alumni  12, 16, 30, 37, 2, 11, 26, 37, 23, 15, 31, 41, 21, 32, 26...
$ Expend       7041, 10527, 8735, 19016, 10922, 9727, 8861, 11487, 11644...
$ Grad.Rate    60, 56, 54, 59, 15, 55, 63, 73, 80, 52, 73, 76, 74, 68, 5...

Solución

  1. Opción 1:Propuesta en el libro ISLR.
  2. Elite = rep("No", nrow(College))
    Elite[College$Top10perc > 50] = "Yes"
    Elite <- as.factor(Elite)
    college <- data.frame(College,  Elite)
    summary(college[, c("Top10perc", "Elite")])
    
    Podemos observar como 78 universidades contienen alumnos pertenecientes a la élite.

      Top10perc     Elite    
     Min.   : 1.00   No :699  
     1st Qu.:15.00   Yes: 78  
     Median :23.00            
     Mean   :27.56            
     3rd Qu.:35.00            
     Max.   :96.00    
    
  3. Opción 2: ifelse con paquete base y dplyr
  4. # base 
    College$Elite <- factor(ifelse(College$Top10perc > 50, "Yes", "No"))
    # dplyr
    library(dplyr)
    College <-
      college %>%
      mutate(Elite = factor(ifelse(College$Top10perc > 50, "Yes", "No")))
    
  5. Opción 3: vector lógico.
  6. Hay múltiples opciones. Presento dos ejemplos.

    college$Elite <- transform(College, Elite = Top10perc > 50)
    College$Elite <- College$Top10perc > 50
    

Entradas relacionadas

2018-04-25

Calcular la diferencia entre filas alternas en R

Problema

Queremos calcular la diferencia entre filas alternas en R.

df <- 
structure(list(MemId = c(1, 2, 3, 4, 5,6), ET = structure(c(1506829256,
 1506829319, 1506843096,1506843226, 1506850144, 1506853708), class = 
c("POSIXct", "POSIXt"))), .Names = c("MemId", "ET"), row.names = c("1",
 "2", "14", "15", "37", "38"), class = "data.frame")
  MemId                  ET
1      1 2017-10-01 05:40:56
2      2 2017-10-01 05:41:59
14     3 2017-10-01 09:31:36
15     4 2017-10-01 09:33:46
37     5 2017-10-01 11:29:04
38     6 2017-10-01 12:28:28

Solución

Creamos una columna auxiliar con ceros y unos. Y con la función difftime, calculamos para los unos la diferencia entre un momento en el tiempo (ET) y el anterior (lag(ET)).

library(dplyr)
df %>%
  mutate(id = rep_len(0:1, nrow(df))) %>%
  mutate(dif = ifelse(id == 1, difftime(ET, lag(ET), units = "secs"), NA))
  MemId                  ET id  dif
1     1 2017-10-01 05:40:56  0   NA
2     2 2017-10-01 05:41:59  1   63
3     3 2017-10-01 09:31:36  0   NA
4     4 2017-10-01 09:33:46  1  130
5     5 2017-10-01 11:29:04  0   NA
6     6 2017-10-01 12:28:28  1 3564

Entradas relacionadas

Referencias

2015-10-26

Una manera más eficiente de comparar números que con ifelse en R

Title

Problema

Tenemos el siguiente data frame.

       x  y
[1,]  -1 99
[2,]   5  4
[3,]  10 -2
[4,] 600  0
[5,] -16  1
[6,]   0 55

Y deseamos obtener un vector fruto de la siguiente comparación de x e y:

1. El menor valor en y si tanto x e y son positivos.
2. Cualquier valor positivo de y si x es negativo.
3. O dejar el valor de x si no se cumplen las dos condiciones anteriores.

Datos

dat <- structure(list(x = c(-1L, 5L, 10L, 600L, -16L, 0L), y = c(99L, 
4L, -2L, 0L, 1L, 55L)), .Names = c("x", "y"), class = "data.frame", row.names = c("[1,]", 
"[2,]", "[3,]", "[4,]", "[5,]", "[6,]"))

Soluciones

 # Extraemos los vectores
x <- dat[, 1]
y <- dat[, 2]
  • ifelse
  • El problema de esta opción es que no es muy eficiente computacionalmente.

    ifelse(y >= 0, ifelse(x < 0, y, ifelse(x > y, y, x)), x)
    
     [1] 99  4 10  0  1  0

  • Indexando
  • Esta opción es entre 5 y 6 veces más rápida.

    xz[(x < y & x >= 0)| y < 0] <- x[(x < y & x >= 0)| y < 0];z
    
     [1] 99  4 10  0  1  0
  • Sin indexar
  • Aún más rápida que la anterior.

    x * ((x < y & x >= 0) | y < 0) + y * ((x > y & y >= 0) | x < 0) 
    
     [1] 99  4 10  0  1  0

    Comparativa

    Empleamos el paquete microbenchmark para comparar el tiempo de ejecución de las 3 opciones.

    microbenchmark(
      if_else = ifelse(y >= 0, ifelse(x < 0, y, ifelse(x > y, y, x)), x),
      indexar= z[(x < y & x >= 0)| y < 0] <- x[(x < y & x >= 0)| y < 0],  
      sinindexar = x *((x < y & x >= 0)| y < 0)+ y * ((x > y & y >= 0)| x < 0),
        )
    
    Unit: microseconds
           expr    min      lq     mean median     uq     max neval cld
        if_else 43.023 47.1785 53.29921 53.289 53.290 107.067   100  b
        indexar  8.800  9.2900 10.71218  9.778 10.267  53.290   100  a 
     sinindexar  7.333  7.8230  8.89833  8.311  8.800  52.800   100  a 
    
    La opción ifelse es la menos eficiente. La opción indexar mejora sustancialmente la velocidad de ejecución. Finalmente, la opción sinindexar es algo más rápida aún que indexar. Existen opciones más rápidas incluso, que puedes ver en el enlace del apartado referencias. Sin embargo, quizá la ganancia en velocidad de ejecución no compensa la pérdida de legibilidad.

    Entradas relacionadas

    Referencias

    2015-10-01

    Combinar columnas de factores o caracteres en una columna con R

    Title

    Problema

    Partimos del siguiente data frame y deseamos fusionar las dos columnas en una nueva, de manera que no hay ningún valor NA.

    Datos

       var1     var2
    1    red     <NA>
    2   <NA> lightred
    3   <NA>     blue
    4   <NA> lightred
    5    red     <NA>
    6 orange     <NA>
    
    help <- data.frame(var1 = c("red", NA, NA, NA, "red", "orange"),
                       var2 = c(NA, "lightred", "blue", "lightred", NA, NA))
    

    Soluciones

    • Función coalesce
    • Con el paquete sqldf tenemos acceso a la función coalesce de SQL. Coalesce devuelve la primera columna no nula en la lista. Si todas las columnas evaluadas son nulas devolverá el valor nulo.

      library(sqldf)
      # Nueva columna newvar
      help$newvar <- sqldf("select coalesce(var1, var2) newvar from help")
      # O todo el data frame
      help <- sqldf("select *, coalesce(var1, var2) newvar from help")
      
          var1     var2   newvar
      1    red     <NA>      red
      2   <NA> lightred lightred
      3   <NA>     blue     blue
      4   <NA> lightred lightred
      5    red     <NA>      red
      6 orange     <NA>   orange
      
    • Función ifelse
    • Como var1 y var 2 son factores necesitamos convertirlos en caracteres con as.character. El inconveniente de esta segunda opción es que si hubiera más de dos columnas necesitaríamos anidar más ifelse mientras que coalesce podríamos seguir añadiendo columnas como nuevos argumentos.

      within(help, newvar <- ifelse(is.na(var1), as.character(var2), as.character(var1)))
          var1     var2   newvar
      1    red     <NA>      red
      2   <NA> lightred lightred
      3   <NA>     blue     blue
      4   <NA> lightred lightred
      5    red     <NA>      red
      6 orange     <NA>   orange
      

    Entradas relacionadas

    Referencias

    2015-06-08

    Prueba de ingenio de la Oficina de la Casa Blanca para Políticas de Ciencia y Tecnología

    Title

    Problema

    El pasado 17 de mayo, Ed Felten planteó el siguiente problema en el blog de la Casa Blanca Office of Science & Tech Policy.

    Alice y Bob están jugando el siguiente juego. Son compañeros de equipo, por lo que van a ganar o perder juntos. Antes de comenzar el juego, pueden hablar entre sí y ponerse de acuerdo en una estrategia.

    Cuando el juego comienza, Alice y Bob van a habitaciones separadas e insonorizadas —no pueden comunicarse entre sí de ninguna manera. Cada uno de ellos lanza una moneda y anota si salió Cara o Cruz. (Las trampas no están permitidas —tienen que lanzar la moneda honestamente y decir la verdad sobre el resultado.) Ahora Alice escribe su predicción sobre el resultado de la moneda de Bob; y Bob lo mismo respecto a la moneda que lanzó Alice.

    Si una o ambas de las predicciones escritas resulta ser correcta, entonces Alice y Bob ganan como equipo. Pero si ambas predicciones están equivocadas, entonces ambos pierden.

    La pregunta es: ¿puedes pensar en una estrategia para Alice y Bob que garantice que ganen siempre?

    Solución

  • Planteamiento
  • Representamos todas las opciones.

    n <- 4
    l <- rep(list(c("Cara", "Cruz")), n)
    df <- expand.grid(l)
    colnames(df) <- c("A", "Ap", "B", "Bp")
    df$Rdo <- ifelse(df$B == df$Ap | df$A == df$Bp, "Gana", "Pierde")
    df
    
    A - Alice
    Ap - Predicción de Alice
    B - Bob
    Bp - Predicción de Bob
    Rdo - Resultado

          A   Ap    B   Bp    Rdo
    1  Cara Cara Cara Cara   Gana
    2  Cruz Cara Cara Cara   Gana
    3  Cara Cruz Cara Cara   Gana
    4  Cruz Cruz Cara Cara Pierde
    5  Cara Cara Cruz Cara   Gana
    6  Cruz Cara Cruz Cara Pierde
    7  Cara Cruz Cruz Cara   Gana
    8  Cruz Cruz Cruz Cara   Gana
    9  Cara Cara Cara Cruz   Gana
    10 Cruz Cara Cara Cruz   Gana
    11 Cara Cruz Cara Cruz Pierde
    12 Cruz Cruz Cara Cruz   Gana
    13 Cara Cara Cruz Cruz Pierde
    14 Cruz Cara Cruz Cruz   Gana
    15 Cara Cruz Cruz Cruz   Gana
    16 Cruz Cruz Cruz Cruz   Gana
    
    Sin ninguna estrategia ganan el 75% de las veces:

    nrow(df[df$Rdo == "Gana", ])/nrow(df)
    
    [1] 0.75
    
    Examinemos los casos en los que pierden.

    df[df$Rdo == "Pierde", ] 
    
          A   Ap    B   Bp    Rdo
    4  Cruz Cruz Cara Cara Pierde
    6  Cruz Cara Cruz Cara Pierde
    11 Cara Cruz Cara Cruz Pierde
    13 Cara Cara Cruz Cruz Pierde
    
    En el primer(4) y último(13) caso ambos predicen el mismo resultado que el de la moneda que lanzaron. En el segundo (6) y tercero (11) ambos predicen el opuesto del resultado de la moneda que lanzaron.

  • Solución
  • Probamos una estrategia en la que uno de ellos —Alice en nuestro caso— predice el caso opuesto al resultado del lanzamiento de su moneda y Bob predice el mismo resultado que el del lanzamiento de su moneda.

    df$Ap2 <- ifelse(df$A == "Cara", "Cruz", "Cara")
    df$Bp2 <- df$B
    df$Rdo2 <- ifelse(df$B == df$Ap2 | df$A == df$Bp2, "Gana", "Pierde")
    df 
    
    Ap2 - Predicción de Alice, opuesta al resultado de su moneda
    Bp2 - Predicción de Bob, igual al resultado de su moneda
    Rdo2 - Resultado final: siempre ganan

          A   Ap    B   Bp    Rdo  Ap2  Bp2 Rdo2
    1  Cara Cara Cara Cara   Gana Cruz Cara Gana
    2  Cruz Cara Cara Cara   Gana Cara Cara Gana
    3  Cara Cruz Cara Cara   Gana Cruz Cara Gana
    4  Cruz Cruz Cara Cara Pierde Cara Cara Gana
    5  Cara Cara Cruz Cara   Gana Cruz Cruz Gana
    6  Cruz Cara Cruz Cara Pierde Cara Cruz Gana
    7  Cara Cruz Cruz Cara   Gana Cruz Cruz Gana
    8  Cruz Cruz Cruz Cara   Gana Cara Cruz Gana
    9  Cara Cara Cara Cruz   Gana Cruz Cara Gana
    10 Cruz Cara Cara Cruz   Gana Cara Cara Gana
    11 Cara Cruz Cara Cruz Pierde Cruz Cara Gana
    12 Cruz Cruz Cara Cruz   Gana Cara Cara Gana
    13 Cara Cara Cruz Cruz Pierde Cruz Cruz Gana
    14 Cruz Cara Cruz Cruz   Gana Cara Cruz Gana
    15 Cara Cruz Cruz Cruz   Gana Cruz Cruz Gana
    16 Cruz Cruz Cruz Cruz   Gana Cara Cruz Gana
    

    Referencias

    Nube de datos