Get value based on another column in dplyr - r

I have the following dataset:
df <- mtcars[1:4,c("wt","qsec")]
df
wt qsec
Mazda RX4 2.620 16.46
Mazda RX4 Wag 2.875 17.02
Datsun 710 2.320 18.61
Hornet 4 Drive 3.215 19.44
How to achieve the following by using dynamic variable via dplyr?
df %>%
mutate(wt=floor(wt[which.min(qsec)]))
This is what I tried so far:
myvar<-"wt"
df %>%
mutate(!!myvar :=floor(!!as.name(myvar)[which.min(qsec)]))
Error in which.min(qsec) : object 'qsec' not found
Please let me know if you know why does the above code failed. Thank you!

In the latest versions of dplyr, you use := to set names with a character value and you use .data[[]] to get columns with a character value. Your transformation would look like this
df %>% mutate("{myvar}" := floor(.data[[myvar]][which.min(qsec)]))

Related

R function that works with NSE and Shiny Inputs

I am looking for an easy way to have my function work with input the comes from Shiny (i.e. string input) or with typical interactive use that is Tidyverse functions enable with NSE. Without the need to duplicate my code to handle each case separately.
An example of usage:
library(dplyr)
flexible_input <- function(var){
mtcars %>%
select(var)
}
# This works for NSE
nse_input <- function(var){
mtcars %>%
select({{ var }})
}
# This works for shiny but now I am duplicated my code essentially
shiny_input <- function(var){
mtcars %>%
select(.data[[var]])
}
flexible_input(mpg)
flexible_input('mpg')
If we need flexible_input to take string and unquoted input, convert to symbol and evaluate (!!)
flexible_input <- function(var){
mtcars %>%
dplyr::select(!! rlang::ensym(var))
}
-testing
> flexible_input(mpg) %>% head
mpg
Mazda RX4 21.0
Mazda RX4 Wag 21.0
Datsun 710 22.8
Hornet 4 Drive 21.4
Hornet Sportabout 18.7
Valiant 18.1
> flexible_input("mpg") %>% head
mpg
Mazda RX4 21.0
Mazda RX4 Wag 21.0
Datsun 710 22.8
Hornet 4 Drive 21.4
Hornet Sportabout 18.7
Valiant 18.1

Create subset of ranges and individual items

I'm using R and have a dataset with ~3000 psychological test data. The data is all dyadic in male-female partners (though this shouldn't matter for you). I'm creating a new data frame with just the variables of interest, most of them are not sequentially listed in the original data so I select them by name like below:
new_df <- subset(data, select=c("MQ4", "FQ4", #RX STATUS
"MQ9", "FQ9", #ETHNICITY
"MQ10", "FQ10", #RACE
"MQ465", "FQ465", #SEX
"MQ13", "FQ13", #GENDER
"MQ14", "FQ14", #SEXORIENT
"MQ180", "MQ181", "MQ182", "MQ182" ### HERE IS WHERE I NEED HELP
))
However, I have about 150 unique items that are listed sequentially and I'd like to select them without writing out "MQ180" through "MQ310" to select them all. I've been trying to figure out a way to select the range as well to the individual items I have been doing. This is currently what I'm trying:
new_df <- subset(data, select=c("MQ4", "FQ4", #RX STATUS
"MQ9", "FQ9", #ETHNICITY
"MQ10", "FQ10", #RACE
"MQ465", "FQ465", #SEX
"MQ13", "FQ13", #GENDER
"MQ14", "FQ14", #SEXORIENT
163:310 ### HERE IS WHERE I NEED HELP
))
One option:
dplyr::select(mtcars, "cyl", 5:8)
This subsets the mtcars dataframe to just the cyl column and the 5th thru 8th column:
cyl drat wt qsec vs
Mazda RX4 6 3.90 2.620 16.46 0
Mazda RX4 Wag 6 3.90 2.875 17.02 0
Datsun 710 4 3.85 2.320 18.61 1
Here's a base R alternative but there's probably a better way:
cbind(mtcars[, 'cyl'], mtcars[, 5:8])
mtcars originally:
5 6 7 8
mpg cyl disp hp drat wt qsec vs am gear carb
Mazda RX4 21.0 6 160.0 110 3.90 2.620 16.46 0 1 4 4
Mazda RX4 Wag 21.0 6 160.0 110 3.90 2.875 17.02 0 1 4 4
Datsun 710 22.8 4 108.0 93 3.85 2.320 18.61 1 1 4 1
In the index part of subset select can use names
subset(data, select=c("MQ4", "FQ4", #RX STATUS
"MQ9", "FQ9", #ETHNICITY
"MQ10", "FQ10", #RACE
"MQ465", "FQ465", #SEX
"MQ13", "FQ13", #GENDER
"MQ14", "FQ14", #SEXORIENT
names(data)[163:310]
))
The issue arises because of the property of vector which can only have a single class. So, when we have both character and integer, the integers are converted to character and thus it will look for column names that matches the name "163" instead of the position index

How to use a short script to eliminate all but one duplicate column variables based on the prefix of the colname

I want to know to use a short script to eliminate all but one duplicate column variables based on the prefix of the colname without inputting the variables I want to remove by hand.
For example, I created repeats of the mtcars$am variables, called am1, am2, am3, and am4 in a data frame called mtcars_example_2. I removed the original am variable in the mtcars_example_2 data frame.
I can use the script below to eliminate all variables with the prefix "am" but the am1 variable into a new variable called mtcars_example_3 using the code below, which inputs all variables to remove by hand:
## long way of removing all variable with am prefix that were not am1
mtcars_example_3 <-
mtcars_example_2 %>%
select(
-c(
"am2", "am3", "am4"
)
)
But this seems like the long way of doing this. Is there a faster way that does not require me to individual type in the names of each of the variables that I want to remove from the data.
Is this possible? If so, how can this be done?
Thanks ahead of time.
Here is the code for the example:
# example data
## loads packages
library(tidyverse)
## creates mtcars_example data
mtcars_example_1 <- data.frame(mtcars)
mtcars_example_2 <- data.frame(mtcars_example_1)
## creates duplicate variables, based on am variable
mtcars_example_2$am1 <- mtcars_example_1$am
mtcars_example_2$am2 <- mtcars_example_1$am
mtcars_example_2$am3 <- mtcars_example_1$am
mtcars_example_2$am4 <- mtcars_example_1$am
## removes original variable
mtcars_example_2 <-
mtcars_example_2 %>%
select(
-c(
"am"
)
)
## long way of removing all variable with am prefix that were not am1
mtcars_example_3 <-
mtcars_example_2 %>%
select(
-c(
"am2", "am3", "am4"
)
)
You can remove all the variables that start with am but keep am1 :
library(dplyr)
mtcars_example_2 %>% select(-starts_with('am'), am1) %>% head
# mpg cyl disp hp drat wt qsec vs gear carb am1
#Mazda RX4 21.0 6 160 110 3.90 2.620 16.46 0 4 4 1
#Mazda RX4 Wag 21.0 6 160 110 3.90 2.875 17.02 0 4 4 1
#Datsun 710 22.8 4 108 93 3.85 2.320 18.61 1 4 1 1
#Hornet 4 Drive 21.4 6 258 110 3.08 3.215 19.44 1 3 1 0
#Hornet Sportabout 18.7 8 360 175 3.15 3.440 17.02 0 3 2 0
#Valiant 18.1 6 225 105 2.76 3.460 20.22 1 3 1 0
Depending on your actual scenario you can also use regex to remove columns.
mtcars_example_2 %>% select(-matches('am[2-4]')) %>% head
We could also do
library(dplyr)
mtcars_example_2 %>%
select(-contains('am'), am1)

Indexing by column name to the end of the dataframe - R

I'm wondering if there is a way to select a group of columns by the name of the first column in the group and then all the next columns either a) to the end of the data frame, or b) to another column, also using its name.
a) As an example for the first question, in the mtcars dataset, is there a way to select the columns from drat to the end of the data frame? (Something like mtcars[,'drat':ncol(mtcars)])
b) For the second question, is there a way to select the columns starting at cyl and ending at wt? (Something like mtcars[,'cyl':'wt'])
Many elegant solutions already provided but one can even use base-R to get the desired result using which as:
Ans a:
mtcars[,which(names(mtcars) == "drat"):ncol(mtcars)]
Ans b:
mtcars[,which(names(mtcars) == "cyl"):which(names(mtcars) == "wt")]
# cyl disp hp drat wt
#Mazda RX4 6 160.0 110 3.90 2.620
#Mazda RX4 Wag 6 160.0 110 3.90 2.875
#Datsun 710 4 108.0 93 3.85 2.320
#Hornet 4 Drive 6 258.0 110 3.08 3.215
#Hornet Sportabout 8 360.0 175 3.15 3.440
#......so on
We can do with this with select from dplyr
Answer a)
mtcars %>% select(drat:get(last(names(.))))
Answer b)
mtcars %>% select(cyl:wt)
In dplyr, the select function does exactly this (no quotes needed):
mtcards %>%
select(cyl:wt)
If we need to use a quoted string, convert it to sym (symbol) and then do the evaluation (!!
mtcars %>%
select(!! (rlang::sym("cyl")): !!(rlang::sym("wt")))
It would be when these are stored in an object
a <- "cyl"
b <- "wt"
mtcars %>%
select(!! (rlang::sym(a)): !!(rlang::sym(b)))
Or another option is
mtcars %>%
select(!! rlang::parse_expr(glue::glue("{a}:{b}")))

is there a way to use the ggplot aes callout without inputing the column name but by just inputting the column #?

EXAMPLE DATASET:
mtcars
mpg cyl disp hp drat wt ...
Mazda RX4 21.0 6 160 110 3.90 2.62 ...
Mazda RX4 Wag 21.0 6 160 110 3.90 2.88 ...
Datsun 710 22.8 4 108 93 3.85 2.32 ...
............
Recommended ggplot way:
ggplot(mtcars,aes(x=mpg)) + geom_histogram
They way I want to do it:
ggplot(mtcars,aes(x=[,1]) +geom_histogram
or
ggplot(mtcars,aes(x=[[1]]))+geom_histogram
Why can't ggplot let me call out my variable by its column? I need to call it out by column number not name. Why is ggplot so strict here? Any work around for this?
The problem you're facing is that the ggplot aes argument evaluates within the data.frame that you pass it. A column name is a string, and can't be properly evaluated the same way.
Fortunately, there is a solution: use the aes_string option, as follows:
library(ggplot2)
my_data <- mtcars
names(my_data)
ggplot(my_data, aes_string(x=names(my_data)[1]))+
geom_histogram()
This works because names(my_data)[1] returns a string, and is perfectly acceptable for the aes_string option.

Resources