I want to copy data frame a to a new data frame b inside a function.
a <- mtcars
saveData <- function(x, y){
y <- x
return(y)
}
saveData(a, b)
In this example, the function should create the object/data frame b. b should be a copy of a (i.e., mtcars)
The crux is to flexibly "name" objects.
I excessively played around with assign(), deparse(), and substitute(), but I could not make it work.
It is not a good pracrtice to save the data in global environment from a function. However if you want to do it here is a way :
saveData <- function(x, y){
assign(deparse(substitute(y)), x, envir = parent.frame())
}
a <- mtcars
b
Error: object 'b' not found
saveData(a, b)
b
# 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
#Hornet 4 Drive 21.4 6 258.0 110 3.08 3.215 19.44 1 0 3 1
#Hornet Sportabout 18.7 8 360.0 175 3.15 3.440 17.02 0 0 3 2
#...
Another idea is to use list2env, but you have to convert to a named list, so your second argument will need to be a character, i.e.
saveData <- function(x, y) {
v1 <- setNames(list(x), y)
list2env(v1, envir = .GlobalEnv)
}
saveData(a, 'b')
b
# 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
#Hornet 4 Drive 21.4 6 258.0 110 3.08 3.215 19.44 1 0 3 1
#Hornet Sportabout 18.7 8 360.0 175 3.15 3.440 17.02 0 0 3 2
#.....
NOTE: I wouldn't recommend adding staff to your global environment. It is better to keep them in lists
Related
Using the R inbuilt dataset
mtcars
I want to make a column called "want".
mtcars$want<-NA
When column "carb" is equal to 1 (Column A), input value of column "qsec" (Column B) in column "want" (Column C).
If carb is not equal to 1 do nothing.
The first 5 rows of the new dataset should look like this:
mpg cyl disp hp drat wt qsec vs am gear carb want
Mazda RX4 21.0 6 160.0 110 3.90 2.620 16.46 0 1 4 4 NA
Mazda RX4 Wag 21.0 6 160.0 110 3.90 2.875 17.02 0 1 4 4 NA
Datsun 22.8 4 108.0 93 3.85 2.320 18.61 1 1 4 1 18.61
Hornet Drive 21.4 6 258.0 110 3.08 3.215 19.44 1 0 3 1 19.44
Hornet Sportabout 18.7 8 360.0 175 3.15 3.440 17.02 0 0 3 2 NA
This should do the job:
mtcars$want <- ifelse(mtcars$carb == 1, mtcars$qsec, NA)
head(mtcars, 5)
mpg cyl disp hp drat wt qsec vs am gear carb want
Mazda RX4 21.0 6 160 110 3.90 2.620 16.46 0 1 4 4 NA
Mazda RX4 Wag 21.0 6 160 110 3.90 2.875 17.02 0 1 4 4 NA
Datsun 710 22.8 4 108 93 3.85 2.320 18.61 1 1 4 1 18.61
Hornet 4 Drive 21.4 6 258 110 3.08 3.215 19.44 1 0 3 1 19.44
Hornet Sportabout 18.7 8 360 175 3.15 3.440 17.02 0 0 3 2 NA
If you only want to achieve it in the print out you could try the following (in the data.frame itself this will still be shown as NA):
mtcars$want <- ifelse(mtcars$carb == 1, mtcars$qsec, "")
head(mtcars, 5)
mpg cyl disp hp drat wt qsec vs am gear carb want
Mazda RX4 21.0 6 160 110 3.90 2.620 16.46 0 1 4 4
Mazda RX4 Wag 21.0 6 160 110 3.90 2.875 17.02 0 1 4 4
Datsun 710 22.8 4 108 93 3.85 2.320 18.61 1 1 4 1 18.61
Hornet 4 Drive 21.4 6 258 110 3.08 3.215 19.44 1 0 3 1 19.44
Hornet Sportabout 18.7 8 360 175 3.15 3.440 17.02 0 0 3 2
If it is helpful, I am of the impression that a loop over the columns should work. One can modify the loop or add further conditionals as appropriate to fill in the other values of the column.
#written in R version 4.2.1
data(mtcars)
mtcars$want = 0
for(i in 1:dim(mtcars)[1]){
if(mtcars$carb[i] == 1){
mtcars$want[i] = mtcars$qsec[i]
}}
Result:
head(mtcars)
# mpg cyl disp hp drat wt qsec vs am gear carb want
#Mazda RX4 21.0 6 160 110 3.90 2.620 16.46 0 1 4 4 0.00
#Mazda RX4 Wag 21.0 6 160 110 3.90 2.875 17.02 0 1 4 4 0.00
#Datsun 710 22.8 4 108 93 3.85 2.320 18.61 1 1 4 1 18.61
#Hornet 4 Drive 21.4 6 258 110 3.08 3.215 19.44 1 0 3 1 19.44
#Hornet Sportabout 18.7 8 360 175 3.15 3.440 17.02 0 0 3 2 0.00
#Valiant
What you can do is first set a value to your new column "want" for example 2. You can use ifelse to do your criteria and return "want" if do nothing like this:
mtcars$want <- 2
library(dplyr)
mtcars %>%
mutate(want = ifelse(carb == 1, qsec, want)) %>%
head(5)
#> mpg cyl disp hp drat wt qsec vs am gear carb want
#> Mazda RX4 21.0 6 160 110 3.90 2.620 16.46 0 1 4 4 2.00
#> Mazda RX4 Wag 21.0 6 160 110 3.90 2.875 17.02 0 1 4 4 2.00
#> Datsun 710 22.8 4 108 93 3.85 2.320 18.61 1 1 4 1 18.61
#> Hornet 4 Drive 21.4 6 258 110 3.08 3.215 19.44 1 0 3 1 19.44
#> Hornet Sportabout 18.7 8 360 175 3.15 3.440 17.02 0 0 3 2 2.00
Created on 2022-06-30 by the reprex package (v2.0.1)
When I create a new variable, is there a way to specify in the function where to place it?
Right now, it adds it to the end of the dataframe, but for ease of viewing in Excel for example, I'd like to place a new calculated column beside the columns I used for the calculation.
Here's an example of code:
rawdata2 <- (rawdata1 %>% unite(location, locations1,locations2, locations3,
na.rm = TRUE, remove=TRUE)
%>% select(-location7, -location16)
%>% unite(Sector, Sectors, na.rm=TRUE, remove=TRUE)
%>% unite(TypeofSpace, TypesofSpace, type.of.spaceOther, na.rm=TRUE,
remove=TRUE)
)
You can rearrange the columns in your data frame. It looks like you are using dplyr::select in your example.
library(dplyr)
head(mtcars)
# mpg cyl disp hp drat wt qsec vs am gear carb
# Mazda RX4 21.0 6 160 110 3.90 2.620 16.46 0 1 4 4
# Mazda RX4 Wag 21.0 6 160 110 3.90 2.875 17.02 0 1 4 4
# Datsun 710 22.8 4 108 93 3.85 2.320 18.61 1 1 4 1
# Hornet 4 Drive 21.4 6 258 110 3.08 3.215 19.44 1 0 3 1
# Hornet Sportabout 18.7 8 360 175 3.15 3.440 17.02 0 0 3 2
# Valiant 18.1 6 225 105 2.76 3.460 20.22 1 0 3 1
mtcars2 <- mtcars %>%
select(mpg, carb, everything()) ## moves carb up behind mpg
head(mtcars2)
# mpg carb cyl disp hp drat wt qsec vs am gear
# Mazda RX4 21.0 4 6 160 110 3.90 2.620 16.46 0 1 4
# Mazda RX4 Wag 21.0 4 6 160 110 3.90 2.875 17.02 0 1 4
# Datsun 710 22.8 1 4 108 93 3.85 2.320 18.61 1 1 4
# Hornet 4 Drive 21.4 1 6 258 110 3.08 3.215 19.44 1 0 3
# Hornet Sportabout 18.7 2 8 360 175 3.15 3.440 17.02 0 0 3
# Valiant 18.1 1 6 225 105 2.76 3.460 20.22 1 0 3
You can do the same thing with base subsetting, for example with a data frame with 11 columns you can move the 11th behind the second by
mtcars3 <- mtcars[,c(1,11,2:10)]
identical(mtcars2, mtcars3)
# [1] TRUE
I ended up using relocate, documentation here: dplyr.tidyverse.org/reference/relocate.html
I am trying to convert my list consisting of 52 components to a dataframe for each of the components.
Without using the for loop will look something like this which is tedious:
df1 = as.data.frame(list[1])
df2 = as.data.frame(list[2])
df3 = as.data.frame(list[3])
.
.
.
df50 = as.data.frame(list[50])
How do I achieve this using the for loop? My attempt:
for (i in seq_along(list)) {
noquote(paste0("df", i)) = as.data.frame(list[i])
}
Error: target of assignment expands to non-language objec
I think I'll have to invovle assign.
If you have list of dataframes in list, you can name them and then use list2env to have them as separate dataframes in the environment.
names(list) <- paste0('df', seq_along(list))
list2env(list, .GlobalEnv)
Using a reproducible exmaple,
temp <- list(mtcars, mtcars)
names(temp) <- paste0('df', seq_along(temp))
list2env(temp, .GlobalEnv)
head(df1)
# mpg cyl disp hp drat wt qsec vs am gear carb
#Mazda RX4 21.0 6 160 110 3.90 2.620 16.46 0 1 4 4
#Mazda RX4 Wag 21.0 6 160 110 3.90 2.875 17.02 0 1 4 4
#Datsun 710 22.8 4 108 93 3.85 2.320 18.61 1 1 4 1
#Hornet 4 Drive 21.4 6 258 110 3.08 3.215 19.44 1 0 3 1
#Hornet Sportabout 18.7 8 360 175 3.15 3.440 17.02 0 0 3 2
#Valiant 18.1 6 225 105 2.76 3.460 20.22 1 0 3 1
head(df2)
# mpg cyl disp hp drat wt qsec vs am gear carb
#Mazda RX4 21.0 6 160 110 3.90 2.620 16.46 0 1 4 4
#Mazda RX4 Wag 21.0 6 160 110 3.90 2.875 17.02 0 1 4 4
#Datsun 710 22.8 4 108 93 3.85 2.320 18.61 1 1 4 1
#Hornet 4 Drive 21.4 6 258 110 3.08 3.215 19.44 1 0 3 1
#Hornet Sportabout 18.7 8 360 175 3.15 3.440 17.02 0 0 3 2
#Valiant 18.1 6 225 105 2.76 3.460 20.22 1 0 3 1
However, note that
list is an internal function in R, so it is better to name your variables something else.
As #MrFlick suggested try to keep your data in a list as lists are easier to manage rather than creating numerous objects in your global environment.
We can use assign instead of noquote from the OP's function
for (i in seq_along(list)) {
assign(paste0("df", i), value = list[[i]])
}
As an intermediate step I generate a data frame with one column as character strings and the rest are numbers. I'd like to convert it to a matrix, but first I have to convert that character column into row names and remove it from the data frame.
Is there a simpe way to do this in dplyr? A function like to_rownames() that is opposite to add_rownames()?
I saw a solution using a custom function, but it's really out of dplyr philosophy.
You can now use the tibble-package:
tibble::column_to_rownames()
This provides NSE & standard eval functions:
library(dplyr)
df <- data_frame(a=sample(letters, 4), b=c(1:4), c=c(5:8))
reset_rownames <- function(df, col="rowname") {
stopifnot(is.data.frame(df))
col <- as.character(substitute(col))
reset_rownames_(df, col)
}
reset_rownames_ <- function(df, col="rowname") {
stopifnot(is.data.frame(df))
nm <- data.frame(df)[, col]
df <- df[, !(colnames(df) %in% col)]
rownames(df) <- nm
df
}
m <- "rowname"
head(as.matrix(reset_rownames(add_rownames(mtcars), "rowname")))
## mpg cyl disp hp drat wt qsec vs am gear carb
## Mazda RX4 21.0 6 160 110 3.90 2.620 16.46 0 1 4 4
## Mazda RX4 Wag 21.0 6 160 110 3.90 2.875 17.02 0 1 4 4
## Datsun 710 22.8 4 108 93 3.85 2.320 18.61 1 1 4 1
## Hornet 4 Drive 21.4 6 258 110 3.08 3.215 19.44 1 0 3 1
## Hornet Sportabout 18.7 8 360 175 3.15 3.440 17.02 0 0 3 2
## Valiant 18.1 6 225 105 2.76 3.460 20.22 1 0 3 1
head(as.matrix(reset_rownames_(add_rownames(mtcars), m)))
## mpg cyl disp hp drat wt qsec vs am gear carb
## Mazda RX4 21.0 6 160 110 3.90 2.620 16.46 0 1 4 4
## Mazda RX4 Wag 21.0 6 160 110 3.90 2.875 17.02 0 1 4 4
## Datsun 710 22.8 4 108 93 3.85 2.320 18.61 1 1 4 1
## Hornet 4 Drive 21.4 6 258 110 3.08 3.215 19.44 1 0 3 1
## Hornet Sportabout 18.7 8 360 175 3.15 3.440 17.02 0 0 3 2
## Valiant 18.1 6 225 105 2.76 3.460 20.22 1 0 3 1
Perhaps to_rownames() or set_rownames() makes more sense. ¯\_(ツ)_/¯ YMMV.
If you really need a matrix you can just save the character column to a separate variable, drop it, and then create the matrix
library(dplyr)
df <- data_frame(a = sample(letters, 4), b = c(1:4), c = c(5:8))
letters <- df %>% select(a)
a.matrix <- df %>% select(-a) %>% as.matrix
Not sure what you are going to do after that, but this gets you as far as you asked for...
I pass data frame name as string into a function. How do I get content of referenced data frame from the string? Suppose I have string 'mtcars' and I want to print data frame mtcars:
printdf <- function(dataframe) {
print(dataframe)
}
printdf('mtcars');
I think you'll need a get in there if the input is a string. Also, depending on your usage of the function, the explicit print might not be necessary:
printdf <- function(dataframe) {
get(dataframe)
# print(get(dataframe))
}
head(printdf("mtcars"))
# mpg cyl disp hp drat wt qsec vs am gear carb
# Mazda RX4 21.0 6 160 110 3.90 2.620 16.46 0 1 4 4
# Mazda RX4 Wag 21.0 6 160 110 3.90 2.875 17.02 0 1 4 4
# Datsun 710 22.8 4 108 93 3.85 2.320 18.61 1 1 4 1
# Hornet 4 Drive 21.4 6 258 110 3.08 3.215 19.44 1 0 3 1
# Hornet Sportabout 18.7 8 360 175 3.15 3.440 17.02 0 0 3 2
# Valiant 18.1 6 225 105 2.76 3.460 20.22 1 0 3 1