How to Set Attributes for a Variable in R

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



Leave a reply



Submit