How to set attributes for a variable in R?
Alternatively to using attributes
(see the answer by @CathG) you can use attr
. The first will work on NULL
objects but the second one won't. When you work with R attributes you have to remember there are not a simple as they look and can have some interesting side affects. Quick example:
> x <- 1:10
> class(x)
[1] "integer"
> x
[1] 1 2 3 4 5 6 7 8 9 10
So far so good. Now lets set dim
attribute
> attr(x, 'dim') <- c(2, 5)
> class(x)
[1] "matrix"
> x
[,1] [,2] [,3] [,4] [,5]
[1,] 1 3 5 7 9
[2,] 2 4 6 8 10
class
attribute is fundamental part of the S3 classes:
> foo <- list()
> foo
list()
Lets see what happens if we set attribute class
as a 'data.frame'
> attr(foo, 'class') <- 'data.frame'
> foo
data frame with 0 columns and 0 rows
or we can define custom behavior (BTW this behavior is a reason why it is better to avoid dots when define functions):
> print.foo <- function(x) cat("I'm foo\n")
> attr(foo, 'class') <- 'foo'
> foo
I'm foo
Other attributes like comment
and names
have also special meaning and constraints.
Take away message here is you have to a little bit careful when you work with attributes in R. One simple idea how to deal with is to use prefixes as artificial namespaces:
> x <- 1:10
> attr(x, 'zero323.dim') <- c(2, 5)
> class(x)
[1] "integer"
> x
[1] 1 2 3 4 5 6 7 8 9 10
attr(, 'zero323.dim')
[1] 2 5
In my opinion it particularly useful when you use third party libraries. Usage of the attributes is usually poorly documented, especially when used for some internal tasks, and it is pretty easy to introduce some hard to diagnose bugs if you use conflicting names.
Access variable attributes inside dplyr user defined function
Try this:
my_function<- function(var, ...){
var <- enexpr(var) # use expression, not quosure
group_var <- enquos(...)
df <-random_df
label<-attr(df[[as.character(var)]],'label') # use as.character, not unquoting
df %>%
filter(!is.na(!!var))%>%
group_by(!!!group_var) %>%
count(!!var) %>%
mutate(freq=n/sum(n)) %>%
mutate(!!label:=percent(freq))
}
We use df[[as.character(var)]]
instead of df$!!var
because unquoting with !!
fails in this case. Also note that you probably want expressions, not quosures here. For as.character
we specifically need an expression.
(Thanks for updating with the reproducible example!)
How to get R vector attributes as a variable in my dataframe?
How to figure out what went wrong.
From ?mutate
:
.data: A data frame, data frame extension (e.g. a tibble), or a lazy
data frame (e.g. from dbplyr or dtplyr). See _Methods_,
below, for more details.
This says that the input data (the LHS when used with %>%
, i.e., the data
object here) must be a data.frame
or frame-like.
You have a couple of easy options when starting with a vector:
library(dplyr)
### using @nicola's `stack` suggestion
stack(data)
# values ind
# 1 0 SZC
# 2 12 MSFT
# 3 15 AAPL
# 4 6 GOOG
### same, but renaming
stack(data) %>%
rename(names = ind, data = values)
# data names
# 1 0 SZC
# 2 12 MSFT
# 3 15 AAPL
# 4 6 GOOG
Another:
tibble(data) %>%
mutate(names = names(data))
# # A tibble: 4 x 2
# data names
# <dbl> <chr>
# 1 0 SZC
# 2 12 MSFT
# 3 15 AAPL
# 4 6 GOOG
How to set a specific attribute of an object if the object name is in a variable?
You can use a function to apply the attributes and the assign function to apply them:
add_dummy <- function(obj, name, attribute){
attr(obj, name) <- attribute
return(obj)
}
assign(var, add_dummy(get(var), "attr_name", list(dummy = 123)))
Changing attributes of multiple variables in data frame
Just do DF[] <- replace_labels(DF, new_labels)
at the end so DF is still a dataframe.
Add tag/label/attr/attribute to dataframe columns (variables)
If you want to build extra functionality into data frames using attributes but without specifying a new S3 class, you have to define that functionality somewhere else. It's really pretty easy to do by adding an attribute setter, an attribute getter, and a little subsetting function:
# Subsetter
ss <- function(df, bw) df[sapply(df, function(x) attr(x, "bw") == bw)]
# Gets attributes as vector
get_col_attr <- function(df) sapply(df, attr, "bw")
# Sets attributes to columns from a single vector
set_col_attr <- function(df, attrs)
{
as.data.frame(mapply(function(col, bw) {
attr(col, "bw") <- bw
col
}, df, attrs, SIMPLIFY = FALSE))
}
I think this works quite nicely. Suppose we create a little data frame with two numeric columns and two character columns, and we wish to give the columns the attributes c(1, 1, 2, 2)
. We can just do:
df <- data.frame(A = 1:5, B = 6:10, C = LETTERS[1:5], D = letters[1:5])
df <- set_col_attr(df, c(1, 1, 2, 2))
This still looks and behaves like a normal data frame:
df
#> A B C D
#> 1 1 6 A a
#> 2 2 7 B b
#> 3 3 8 C c
#> 4 4 9 D d
#> 5 5 10 E e
But we can see each column has a bw
attribute:
get_col_attr(df)
#> A B C D
#> 1 1 2 2
And we can use this attribute to subset very easily:
ss(df, bw = 2)
#> C D
#> 1 A a
#> 2 B b
#> 3 C c
#> 4 D d
#> 5 E e
ss(df, bw = 1)
#> A B
#> 1 1 6
#> 2 2 7
#> 3 3 8
#> 4 4 9
#> 5 5 10
Crucially, if we subset the data frame, the attributes are also subsetted appropriately:
df2 <- df[, 2:3]
get_col_attr(df2)
#> B C
#> 1 2
Created on 2020-07-03 by the reprex package (v0.3.0)
Related Topics
How to Request an Early Exit When Knitting an Rmd Document
Time-Series - Data Splitting and Model Evaluation
Override Column Types When Importing Data Using Readr::Read_Csv() When There Are Many Columns
Choosing Eps and Minpts for Dbscan (R)
Sort Matrix According to First Column in R
Filtering Observations in Dplyr in Combination with Grepl
Shared Memory in Parallel Foreach in R
Transparent Equivalent of Given Color
How to Count How Many Values Per Level in a Given Factor
Automatic Documentation of Datasets
How to Highlight Time Ranges on a Plot
How to Write from R to the Clipboard on a MAC
Regression Tables in Markdown Format (For Flexible Use in R Markdown V2)
Avoiding Type Conflicts with Dplyr::Case_When
Deleting Rows That Are Duplicated in One Column Based on the Conditions of Another Column