## ----setup, include = FALSE---------------------------------------------------
knitr::opts_chunk$set(
  collapse = TRUE,
  comment = "#>"
)

## ----eval=FALSE, echo=TRUE----------------------------------------------------
# library(libr)
# 
# # Add some columns to mtcars using data step logic
# df <- datastep(mtcars[1:10, 1:3], {
# 
#     if (mpg >= 20)
#       mpgcat <- "High"
#     else
#       mpgcat <- "Low"
# 
#     recdt <- as.Date("1974-06-10")
# 
#     if (cyl == 8)
#       is8cyl <- TRUE
# 
#   })
# 
# # View results
# df
# #     mpg cyl  disp mpgcat      recdt is8cyl
# # 1  21.0   6 160.0   High 1974-06-10     NA
# # 2  21.0   6 160.0   High 1974-06-10     NA
# # 3  22.8   4 108.0   High 1974-06-10     NA
# # 4  21.4   6 258.0   High 1974-06-10     NA
# # 5  18.7   8 360.0    Low 1974-06-10   TRUE
# # 6  18.1   6 225.0    Low 1974-06-10     NA
# # 7  14.3   8 360.0    Low 1974-06-10   TRUE
# # 8  24.4   4 146.7   High 1974-06-10     NA
# # 9  22.8   4 140.8   High 1974-06-10     NA
# # 10 19.2   6 167.6    Low 1974-06-10     NA
# 

## ----eval=FALSE, echo=TRUE----------------------------------------------------
# library(libr)
# 
# # Keep and order output columns
# df <- datastep(mtcars[1:10,],
#   keep = c("mpg", "cyl", "disp", "mpgcat", "recdt"), {
# 
#     if (mpg >= 20)
#       mpgcat <- "High"
#     else
#       mpgcat <- "Low"
# 
#     recdt <- as.Date("1974-06-10")
# 
#     if (cyl == 8)
#       is8cyl <- TRUE
# 
#   })
# 
# df
# #     mpg cyl  disp mpgcat      recdt
# # 1  21.0   6 160.0   High 1974-06-10
# # 2  21.0   6 160.0   High 1974-06-10
# # 3  22.8   4 108.0   High 1974-06-10
# # 4  21.4   6 258.0   High 1974-06-10
# # 5  18.7   8 360.0    Low 1974-06-10
# # 6  18.1   6 225.0    Low 1974-06-10
# # 7  14.3   8 360.0    Low 1974-06-10
# # 8  24.4   4 146.7   High 1974-06-10
# # 9  22.8   4 140.8   High 1974-06-10
# # 10 19.2   6 167.6    Low 1974-06-10
# 

## ----eval=FALSE, echo=TRUE----------------------------------------------------
# library(libr)
# 
# df <- datastep(mtcars[1:10, ],
#                drop = c("disp", "hp", "drat", "qsec",
#                         "vs", "am", "gear", "carb"),
#                retain = list(cumwt = 0 ),
#                rename = c(mpg = "MPG", cyl = "Cylinders", wt = "Wgt",
#                           cumwt = "Cumulative Wgt"), {
# 
#   cumwt <- cumwt + wt
# 
#  })
# 
# df
# #     MPG Cylinders   Wgt Cumulative Wgt
# # 1  21.0         6 2.620          2.620
# # 2  21.0         6 2.875          5.495
# # 3  22.8         4 2.320          7.815
# # 4  21.4         6 3.215         11.030
# # 5  18.7         8 3.440         14.470
# # 6  18.1         6 3.460         17.930
# # 7  14.3         8 3.570         21.500
# # 8  24.4         4 3.190         24.690
# # 9  22.8         4 3.150         27.840
# # 10 19.2         6 3.440         31.280
# 

## ----eval=FALSE, echo=TRUE----------------------------------------------------
# # Keep with wildcard
# df <- datastep(mtcars[1:10,],
#   keep = c("mpg", "cyl", "d*", "mpgcat"), {
# 
#     if (mpg >= 20)
#       mpgcat <- "High"
#     else
#       mpgcat <- "Low"
# 
#   })
# 
# df
# #     mpg cyl  disp drat mpgcat
# # 1  21.0   6 160.0 3.90   High
# # 2  21.0   6 160.0 3.90   High
# # 3  22.8   4 108.0 3.85   High
# # 4  21.4   6 258.0 3.08   High
# # 5  18.7   8 360.0 3.15    Low
# # 6  18.1   6 225.0 2.76    Low
# # 7  14.3   8 360.0 3.21    Low
# # 8  24.4   4 146.7 3.69   High
# # 9  22.8   4 140.8 3.92   High
# # 10 19.2   6 167.6 3.92    Low
# 

## ----eval=FALSE, echo=TRUE----------------------------------------------------
# library(libr)
# 
# # Identify start and end of by-groups
# df <- datastep(mtcars[1:10,],
#   keep = c("mpg", "cyl", "gear", "grp"),
#   by = c("gear"), sort_check = FALSE, {
# 
#     if (first. & last.)
#       grp <- "Start - End"
#     else if (first.)
#       grp <- "Start"
#     else if (last.)
#       grp <- "End"
#     else
#       grp <- "-"
# 
#   })
# 
# df
# #     mpg cyl gear   grp
# # 1  21.0   6    4 Start
# # 2  21.0   6    4     -
# # 3  22.8   4    4   End
# # 4  21.4   6    3 Start
# # 5  18.7   8    3     -
# # 6  18.1   6    3     -
# # 7  14.3   8    3   End
# # 8  24.4   4    4 Start
# # 9  22.8   4    4     -
# # 10 19.2   6    4   End
# 

## ----eval=FALSE, echo=TRUE----------------------------------------------------
# library(libr)
# 
# # Create sample data
# df <- data.frame(HairEyeColor)[seq(2, 32, 2), ]
# 
# # Sort by groups
# df <- sort(df, by = c("Sex", "Hair"))
# 
# # Identify start and end of by-groups
# df2 <- datastep(df,
#    drop = c("Eye", "Freq"),
#    by = c("Sex", "Hair"), {
# 
#     fSex <- first.Sex
#     lSex <- last.Sex
#     fHair <- first.Hair
#     lHair <- last.Hair
# 
#   })
# 
# df2
# #     Hair    Sex  fSex  lSex fHair lHair
# # 1  Brown   Male  TRUE FALSE  TRUE FALSE
# # 2  Brown   Male FALSE FALSE FALSE FALSE
# # 3  Brown   Male FALSE FALSE FALSE FALSE
# # 4  Brown   Male FALSE FALSE FALSE  TRUE
# # 5  Blond   Male FALSE FALSE  TRUE FALSE
# # 6  Blond   Male FALSE FALSE FALSE FALSE
# # 7  Blond   Male FALSE FALSE FALSE FALSE
# # 8  Blond   Male FALSE  TRUE FALSE  TRUE
# # 9  Brown Female  TRUE FALSE  TRUE FALSE
# # 10 Brown Female FALSE FALSE FALSE FALSE
# # 11 Brown Female FALSE FALSE FALSE FALSE
# # 12 Brown Female FALSE FALSE FALSE  TRUE
# # 13 Blond Female FALSE FALSE  TRUE FALSE
# # 14 Blond Female FALSE FALSE FALSE FALSE
# # 15 Blond Female FALSE FALSE FALSE FALSE
# # 16 Blond Female FALSE  TRUE FALSE  TRUE
# 

## ----eval=FALSE, echo=TRUE----------------------------------------------------
# library(libr)
# 
# # Categorize mpg as above or below the mean
# df <- datastep(mtcars,
#   keep = c("mpg", "cyl", "mean_mpg", "mpgcat"),
#   calculate = { mean_mpg = mean(mpg) },
#   {
# 
#     if (mpg >= mean_mpg)
#       mpgcat <- "High"
#     else
#       mpgcat <- "Low"
# 
#   })
# 
# df[1:10,]
# #     mpg cyl mean_mpg mpgcat
# # 1  21.0   6 20.09062   High
# # 2  21.0   6 20.09062   High
# # 3  22.8   4 20.09062   High
# # 4  21.4   6 20.09062   High
# # 5  18.7   8 20.09062    Low
# # 6  18.1   6 20.09062    Low
# # 7  14.3   8 20.09062    Low
# # 8  24.4   4 20.09062   High
# # 9  22.8   4 20.09062   High
# # 10 19.2   6 20.09062    Low
# 

## ----eval=FALSE, echo=TRUE----------------------------------------------------
# library(libr)
# library(dplyr)
# 
# # Add datastep to dplyr pipeline
# df <- mtcars |>
#   select(mpg, cyl, gear) |>
#   mutate(mean_mpg = mean(mpg)) |>
#   datastep({
# 
#     if (mpg >= mean_mpg)
#       mpgcat <- "High"
#     else
#       mpgcat <- "Low"
# 
#   }) |>
#   filter(row_number() <= 10)
# 
# df
# #     mpg cyl gear mean_mpg mpgcat
# # 1  21.0   6    4 20.09062   High
# # 2  21.0   6    4 20.09062   High
# # 3  22.8   4    4 20.09062   High
# # 4  21.4   6    3 20.09062   High
# # 5  18.7   8    3 20.09062    Low
# # 6  18.1   6    3 20.09062    Low
# # 7  14.3   8    3 20.09062    Low
# # 8  24.4   4    4 20.09062   High
# # 9  22.8   4    4 20.09062   High
# # 10 19.2   6    4 20.09062    Low
# 

## ----eval=FALSE, echo=TRUE----------------------------------------------------
# library(libr)
# 
# # Assign label attributes to all columns
# df <- datastep(mtcars[1:10, ],
#                keep = c("mpg", "cyl", "mpgcat"),
#                calculate = { mean_mpg = mean(mpg) },
#                attrib = list(mpg = dsattr(label = "Miles Per Gallon"),
#                              cyl = dsattr(label = "Cylinders"),
#                              mpgcat = dsattr(label = "Mileage Category")), {
# 
#     if (mpg >= mean_mpg)
#       mpgcat <- "High"
#     else
#       mpgcat <- "Low"
# 
#   })
# 
# # View attributes in dictionary
# dictionary(df)
# # # A tibble: 3 x 10
# #   Name  Column Class     Label            Description Format Width Justify  Rows   NAs
# #   <chr> <chr>  <chr>     <chr>            <chr>       <lgl>  <int> <chr>   <int> <int>
# # 1 df    mpg    numeric   Miles Per Gallon NA          NA        NA NA         10     0
# # 2 df    cyl    numeric   Cylinders        NA          NA        NA NA         10     0
# # 3 df    mpgcat character Mileage Category NA          NA         4 NA         10     0
# 

## ----eval=FALSE, echo=TRUE----------------------------------------------------
# AirPassengers
# #      Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec
# # 1949 112 118 132 129 121 135 148 148 136 119 104 118
# # 1950 115 126 141 135 125 149 170 170 158 133 114 140
# # 1951 145 150 178 163 172 178 199 199 184 162 146 166
# # 1952 171 180 193 181 183 218 230 242 209 191 172 194
# # 1953 196 196 236 235 229 243 264 272 237 211 180 201
# # 1954 204 188 235 227 234 264 302 293 259 229 203 229
# # 1955 242 233 267 269 270 315 364 347 312 274 237 278
# # 1956 284 277 317 313 318 374 413 405 355 306 271 306
# # 1957 315 301 356 348 355 422 465 467 404 347 305 336
# # 1958 340 318 362 348 363 435 491 505 404 359 310 337
# # 1959 360 342 406 396 420 472 548 559 463 407 362 405
# # 1960 417 391 419 461 472 535 622 606 508 461 390 432
# 

## ----eval=FALSE, echo=TRUE----------------------------------------------------
# library(libr)
# 
# # Create AirPassengers Data Frame
# df <- as.data.frame(t(matrix(AirPassengers, 12,
#                     dimnames = list(month.abb, seq(1949, 1960)))),
#                     stringsAsFactors = FALSE)
# 
# # Use datastep array to get year tot, mean, and top month
# dat <- datastep(df,
#                 arrays = list(months = dsarray(names(df))),
#                 attrib = list(Tot = 0, Mean = 0, Top = ""),
#                 drop = "mth",
#                 {
# 
#                   Tot <- sum(months[])
#                   Mean <- mean(months[])
# 
#                   for (mth in months) {
#                     if (months[mth] == max(months[])) {
#                       Top <- mth
#                     }
#                   }
#                 })
# 
# 
# dat
# #      Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec  Tot     Mean Top
# # 1949 112 118 132 129 121 135 148 148 136 119 104 118 1520 126.6667 Aug
# # 1950 115 126 141 135 125 149 170 170 158 133 114 140 1676 139.6667 Aug
# # 1951 145 150 178 163 172 178 199 199 184 162 146 166 2042 170.1667 Aug
# # 1952 171 180 193 181 183 218 230 242 209 191 172 194 2364 197.0000 Aug
# # 1953 196 196 236 235 229 243 264 272 237 211 180 201 2700 225.0000 Aug
# # 1954 204 188 235 227 234 264 302 293 259 229 203 229 2867 238.9167 Jul
# # 1955 242 233 267 269 270 315 364 347 312 274 237 278 3408 284.0000 Jul
# # 1956 284 277 317 313 318 374 413 405 355 306 271 306 3939 328.2500 Jul
# # 1957 315 301 356 348 355 422 465 467 404 347 305 336 4421 368.4167 Aug
# # 1958 340 318 362 348 363 435 491 505 404 359 310 337 4572 381.0000 Aug
# # 1959 360 342 406 396 420 472 548 559 463 407 362 405 5140 428.3333 Aug
# # 1960 417 391 419 461 472 535 622 606 508 461 390 432 5714 476.1667 Jul
# 

## ----eval=FALSE, echo=TRUE----------------------------------------------------
# # Prepare sample data
# dat <- as.data.frame(HairEyeColor)
# 
# # Filter for black hair and blue eyes
# res <- datastep(dat,
#                 where = expression(Hair == "Black" & Eye == "Blue"),
#                 {})
# 
# res
# #    Hair  Eye    Sex Freq
# # 1 Black Blue   Male   11
# # 2 Black Blue Female    9
# 

## ----eval=FALSE, echo=TRUE----------------------------------------------------
# # Delete rows with frequencies less than 25
# res1 <- datastep(dat, {
# 
#          if (Freq < 25)
#            delete()
# 
#        })
# res1
# #     Hair   Eye    Sex Freq
# # 1  Black Brown   Male   32
# # 2  Brown Brown   Male   53
# # 3  Brown  Blue   Male   50
# # 4  Blond  Blue   Male   30
# # 5  Brown Hazel   Male   25
# # 6  Black Brown Female   36
# # 7  Brown Brown Female   66
# # 8  Brown  Blue Female   34
# # 9  Blond  Blue Female   64
# # 10 Brown Hazel Female   29
# 
# # Only output rows for brown-eyes and frequencies over 25
# res2 <- datastep(dat, {
# 
#           if (Eye == "Brown") {
#             if (Freq >= 25) {
# 
#               output()
# 
#             }
#           }
# 
#         })
# 
# res2
# #    Hair   Eye    Sex Freq
# # 1 Black Brown   Male   32
# # 2 Brown Brown   Male   53
# # 3 Black Brown Female   36
# # 4 Brown Brown Female   66
# 

## ----eval=FALSE, echo=TRUE----------------------------------------------------
# # Create metadata
# res3 <- datastep(data.frame(), {
# 
# 
#           name <- "mtcars"
#           rows <- nrow(mtcars)
#           cols <- ncol(mtcars)
#           output()
# 
#           name <- "iris"
#           rows <- nrow(iris)
#           cols <- ncol(iris)
#           output()
# 
# 
#           name <- "beaver1"
#           rows <- nrow(beaver1)
#           cols <- ncol(beaver1)
#           output()
# 
# 
#         })
# 
# res3
# #      name rows cols
# # 1  mtcars   32   11
# # 2    iris  150    5
# # 3 beaver1  114    4
# 

## ----eval=FALSE, echo=TRUE----------------------------------------------------
# # Create sample data
# region <- read.table(header = TRUE, text = '
#   REGION   NAME
#   R01      East
#   R02      West
#   R03      North
#   R04      South
# ', stringsAsFactors = FALSE)
# 
# # First stores dataset
# stores1 <- read.table(header = TRUE, text = '
#   ID  NAME             SIZE REGION FRANCHISE
#   A01 "Eastern Lumber"    L    R01        T
#   A02 "Tri-City Hardwood" M    R02        F
#   A05 "Reliable Hardware" S    R01        T
# ', stringsAsFactors = FALSE)
# 
# # Extra column on this one
# stores2 <- read.table(header = TRUE, text = '
#   ID  NAME             SIZE REGION
#   A03 "AAA Mills"         S    R05
#   A04 "Home and Yard"     L    R03
# ', stringsAsFactors = FALSE)

## ----eval=FALSE, echo=TRUE----------------------------------------------------
# # Set operation
# allstores <- datastep(stores1, set = stores2, {})
# 
# # Extra values filled with NA
# allstores
# #    ID              NAME SIZE REGION FRANCHISE
# # 1 A01    Eastern Lumber    L    R01      TRUE
# # 2 A02 Tri-City Hardwood    M    R02     FALSE
# # 3 A05 Reliable Hardware    S    R01      TRUE
# # 4 A03         AAA Mills    S    R05        NA
# # 5 A04     Home and Yard    L    R03        NA

## ----eval=FALSE, echo=TRUE----------------------------------------------------
# # Create small dataset of missing FRANCHISE values
# franchises <- data.frame(FRANCHISE = c(F, F), stringsAsFactors = FALSE)
# franchises
# #   FRANCHISE
# # 1     FALSE
# # 2     FALSE

## ----eval=FALSE, echo=TRUE----------------------------------------------------
# # Merge in missing FRANCHISE column
# stores2mod <- datastep(stores2, merge = franchises, {})
# stores2mod
# #    ID          NAME SIZE REGION FRANCHISE
# # 1 A03     AAA Mills    S    R05     FALSE
# # 2 A04 Home and Yard    L    R03     FALSE
# 
# # Set again
# allstores <- datastep(stores1, set = stores2mod, {})
# 
# # Now everything is aligned
# allstores
# #    ID              NAME SIZE REGION FRANCHISE
# # 1 A01    Eastern Lumber    L    R01      TRUE
# # 2 A02 Tri-City Hardwood    M    R02     FALSE
# # 3 A05 Reliable Hardware    S    R01      TRUE
# # 4 A03         AAA Mills    S    R05     FALSE
# # 5 A04     Home and Yard    L    R03     FALSE
# 

## ----eval=FALSE, echo=TRUE----------------------------------------------------
# 
# # Merge operation - Outer Join
# res <- datastep(allstores, merge = region,
#                 merge_by = "REGION",
#                 merge_in = c("inA", "inB"), {})
# 
# # View results
# res
# #     ID            NAME.1 SIZE REGION FRANCHISE NAME.2 inA inB
# # 1  A01    Eastern Lumber    L    R01      TRUE   East   1   1
# # 2  A05 Reliable Hardware    S    R01      TRUE   East   1   1
# # 3  A02 Tri-City Hardwood    M    R02     FALSE   West   1   1
# # 4  A04     Home and Yard    L    R03     FALSE  North   1   1
# # 5  A03         AAA Mills    S    R05     FALSE   <NA>   1   0
# # 6 <NA>              <NA> <NA>    R04        NA  South   0   1

## ----eval=FALSE, echo=TRUE----------------------------------------------------
# 
# # Merge operation - Left join and clean up
# res <- datastep(allstores, merge = region,
#                 merge_by = "REGION",
#                 merge_in = c("inA", "inB"),
#                 rename = c(NAME.1 = "STORE_NAME", NAME.2 = "REGION_NAME"),
#                 where = expression(inA == TRUE),
#                 drop = c("inA", "inB"),
#                 {
#                   if (REGION == "R05") {
#                     REGION <- "R04"
#                     NAME.2 <- "South"
#                   }
# 
#                 })
# #'
# # View results
# res
# #    ID        STORE_NAME SIZE REGION FRANCHISE REGION_NAME
# # 1 A01    Eastern Lumber    L    R01      TRUE        East
# # 2 A05 Reliable Hardware    S    R01      TRUE        East
# # 3 A02 Tri-City Hardwood    M    R02     FALSE        West
# # 4 A04     Home and Yard    L    R03     FALSE       North
# # 5 A03         AAA Mills    S    R04     FALSE       South

## ----eval=FALSE, echo=TRUE----------------------------------------------------
# # Subset the input dataset first for only needed rows and columns
# dat <- subset(iris, Species == 'versicolor', c('Petal.Length', 'Petal.Width')) |>
#        datastep({
# 
#          if (Petal.Length < 3.5)
#             Petal.Size <- "Short"
#          else if (Petal.Length > 4.5)
#             Petal.Size <- "Long"
#          else
#             Petal.Size <- "Medium"
# 
#        })
# 
# # View Some Results
# dat[1:10, ]
# #    Petal.Length Petal.Width Petal.Size
# # 1           4.7         1.4       Long
# # 2           4.5         1.5     Medium
# # 3           4.9         1.5       Long
# # 4           4.0         1.3     Medium
# # 5           4.6         1.5       Long
# # 6           4.5         1.3     Medium
# # 7           4.7         1.6       Long
# # 8           3.3         1.0      Short
# # 9           4.6         1.3       Long
# # 10          3.9         1.4     Medium
# 

