Anyone have any fun R things they've learned recently?

I'd love to hear them!

7 Likes

I'm excited to try making a command-line tool using base::commandArgs() and the cliapp package. No idea the best way to go about it. I'd love to have it do something in the current working directory. Right now, the actual point of the tool takes a backseat to my desire to make something.

2 Likes

Getting deeper into the purrr library has been a blast, and something I find myself oddly obsessed with. In my free time, I've gone through all my old code and try to refactor it into utilizing more purrr functionality.

Specifically the partial() and compose() functions have been something that strikes me as awesome.

9 Likes

I recently came across this solution to knitting different variations of a .Rmd report that utilize different combinations of parameters using rmarkdown::render and purrr::pmap. It's made creating regional reports easier and it also works for creating multiple books if you're using bookdown.

5 Likes

Holy moly thank you for bringing this up, @dylanjm, because I just tried out compose() for the first time and realized that you can use it to easily say the opposite of %in%

library(purrr)
  
`%in%`(3, c(1, 2, 3))
#> [1] TRUE

not_in <- compose("!", `%in%`)

not_in(3, c(1, 2, 3))
#> [1] FALSE

not_in(4, c(1, 2, 3))
#> [1] TRUE

Created on 2019-01-17 by the reprex package (v0.2.1.9000)

7 Likes

You can also use purrr::negate() in this instance:

library(purrr)

`%in%`(3, c(1, 2, 3))
#> [1] TRUE

not_in <- negate(`%in%`)

not_in(3, c(1,2,3))
#> [1] FALSE

not_in(3, c(1,2,4))
#> [1] TRUE

Created on 2019-01-17 by the reprex package (v0.2.1)

9 Likes

:open_mouth::open_mouth::open_mouth:

I’ve been creating a Shiny App to display patient profiles along with various plots. As a part of that I’ve gone down a huge rabbit hole of learning CSS and figuring out color schemes, etc. Its weirdly been a lot of fun.

4 Likes

base::Negate is enough in this case :slight_smile:

2 Likes

I've been experimenting with some new assignment functions for a few weeks and I like them more and more as their use becomes more natural to me.

`%like%`  <- data.table::`%like%`
`%!like%` <- function(e1, e2){!e1 %like% e2}
`%!in%`   <- function(x, table){!x %in% table}
`==<-`    <- function(e1,e2,value) replace(e1, e1 == e2, value)
`!=<-`    <- function(e1,e2,value) replace(e1, e1 != e2, value)
`<=<-`    <- function(e1,e2,value) replace(e1, e1 <= e2, value)
`>=<-`    <- function(e1,e2,value) replace(e1, e1 >= e2, value)
`><-`     <- function(e1,e2,value) replace(e1, e1  > e2, value)
`<<-`     <- function(e1,e2,value){
  # this one needs extra care so standard base::`<<-` still works
  if (missing(value))
    eval.parent(substitute(.Primitive("<<-")(e1, e2)))
  else
    replace(e1, e1 < e2, value)
}
`%in%<-`    <- function(e1,e2,value) replace(e1, e1 %in% e2, value)
`%!in%<-`   <- function(e1,e2,value) replace(e1, !e1 %in% e2, value)
`%like%<-`  <- function(e1,e2,value) replace(e1, e1 %like% e2, value)
`%!like%<-` <- function(e1,e2,value) replace(e1, !e1 %like% e2, value)

examples:

x <- 1:10
x > 5 <- 42
x
#>  [1]  1  2  3  4  5 42 42 42 42 42

x <- c("ab","bc","cd")
x %!like% "b" <- "!!!"
x
#> [1] "ab"  "bc"  "!!!"

The last one I'm playing with is :

`~<-` <- function(e1,e2,value){  eval.parent(substitute(within(e1, {e2 <- value})))  }

iris2 <- head(iris)
iris2$Species <- as.character(iris2$Species)
iris2 ~ Species[Petal.Width > 0.3] <- "hello"
# equivalent to
# iris2$Species[iris2$Petal.Width > 0.3] <- "hello"
3 Likes

IMO, one of the best parts of a "data science"-ish job is getting to dabble in so many skills.

3 Likes

On the flip side, that same desire that leads down these informative rabbit holes can sometimes border on OCD :smile:

Example: Wanting to create an AE timeline plot and have arrows at the end of the bars that looked like extensions of the bars. Ran into issues with geom_segment's arrow functions when changing the size of the bars so spent about a day and a half working on it until I got them looking how I wanted them. One might argue my time may have been better spent elsewhere.

2 Likes

I've only been learning R (as in serious study, not just occasional dabbling) for a couple of months. So practically every time I code something I'm forced to discover something new.

It's about 50/50 so far whether these discoveries strike me as "fun R things" versus "annoying obscure R things". My latest discovery was annoying until I figured it out and now seems fun to know, I guess. It's how to cram stuff together in a list object inside a function:

res <- cbind(select(dat, time, grp, simindex, y),
cf_grp0, cf_grp1, pop)
names(res) <- c("time", "grp", "simindex", "y",
"cf_grp0", "cf_grp1", "pop")
return(list(res,model_params))

And then tease it apart with a couple of foreach() %do% loops:

moddata <- matrix()
moddata <- foreach (m=1:nreps,.combine='rbind') %do% return(result_list[[m]][[1]])

modparams <- matrix()
modparams <- foreach (k=1:nreps,.combine='rbind') %do% return(result_list[[k]][[2]])
colnames(modparams) <- c("Intercept", "Time", "Grp", "Zvar", "SD_Intercept")

Sorry for the snippets but a full reprex woudl be huge.

1 Like

I've been using R since 1997 and still practically every time I code I discover something new.

That's about when I started using SAS on a daily basis. Honestly I can't recall when the "learn something new in SAS every day" phase tapered off. Now it's more like something new every few months, maybe.

I suspect, although I won't know for a few years I guess, that R tends to maintain that edge of new discovery possibility much longer than things like SAS or Stata. It's an interesting human factors question whether that's a good thing or a bad thing!

1 Like

I am just starting out on the data science journey, and everything about R during this process is tons of fun, so I can't point to just any one thing.

1 Like

This is a tiny little thing but, coming from 20+ years of SAS programming, is typical of the minor amazements I find constantly in R. I decided to "center" a variable used in one of my models. Even I know enough R to realize I could use something like

mutate(age=age-mean(age))

when reading in my data. That's a bit easier than what I'd have to do in SAS, right there. But then just out of curiosity I decided to try the ULTIMATE shortcut and put it right in my model statement.

glmer(y~time + grp + age + time:grp + (1|subj)...

becomes

glmer(y~time + grp + I(age-mean(age)) + time:grp + (1|subj)...

Darned if it doesn't work just the same. In SAS there is absolutely no concept of anything remotely like that being possible within a model statement. There is a complete separation of data manipulation and modeling stages of a given program.

I also surprised myself last night by adding, on the spur of the moment, a new column to a dataframe which designates how many rows that subject-ID has in the data. What I mean is, if there are three rows with subject=101 then a new "N" column has the value 3 in each of those rows. And if there are two rows for subject=102 then "N" becomes 2.

The surprising thing was I could cobble together off the top of my head (OK plus one quick trip to Google) a combination of dplyr group_by(subj), then a dplyr tally() and finally a full_join() (that's the part I had to look up, all those joins confuse me). And it worked, maybe five minutes start to finish. It would have taken me almost that long to do it in SAS which I know like the back of my hand.

Not to be too self-congratulatory but just 2-1/2 months into learning R it seems I'm coming along...

1 Like

The surprising thing was I could cobble together off the top of my head (OK plus one quick trip to Google) a combination of dplyr group_by(subj), then a dplyr tally() and finally a full_join() (that's the part I had to look up, all those joins confuse me). And it worked, maybe five minutes start to finish. It would have taken me almost that long to do it in SAS which I know like the back of my hand.

dplyr::add_count(subj) might do what you want in one function.

2 Likes

Thanks for sharing cliapp, it looks awesome! And would pair nicely with docopt to make an awesome command line interface.

1 Like

Nice, that does it all in one go. I put the add_count(subj) method into my program as a reminder for the next time I need to do that. With repeated-measures data that's going into a random intercept (or similar) model, the "long" format is a common arrangement for me. This sort of per-subject thing is needed every time I turn around.

Thanks!