0

I Have the following dataset which includes 2 variables:

dt4<-structure(list(a1 = c(4L, 4L, 3L, 4L, 4L), a2 = c(1L, 
3L, 4L, 5L, 4L)), .Names = c("a1", "a2"
), row.names = c(NA, -5L), class = c("tbl_df", "tbl", "data.frame"
))

I Have the following function that add labels and levels to an existing dataset:

Add_Labels_Level_To_Dataset <- function(df, df_name,levels_list,labels_list)   {
  df[] <- lapply( df, ordered)
  for (i in 1:length(colnames(df))) {
    arg0<-paste0(df_name,"[i]", "<-ordered(", df_name, "$'", colnames(df)[i], "', levels=c(", levels_list[[i]], "), labels = c(", labels_list[[i]],"))"  )
    eval(parse(text=arg0))
      }
df
  }

which is run by that R command:

Add_Labels_Level_To_Dataset(dt4, "dt4", level_list, labels_list)

The lists supplied in the R command are the following ones which represents the ordered levels of each variable in the dataset, respectively:

label_list=list("'S','SA','SB','SC,'SD'", "'S','SA','SB','SC,'SD'")
level_list=list("5,4,3,2,1", "5,4,3,2,1")

Why my function is not working properly? I dont know what is wrong with that! When I run the R commands outside R function, they tie levels/ labels to the dataset given. However, when I run my R function, this does not happen!

  df_name="dt4"
  df=dt4
  levels_list=level_list
  labels_list=label_list
  i=3

  df[] <- lapply( df, ordered)
          arg0<-paste0(df_name,"[i]", "<-ordered(", df_name, "$'", colnames(df)[i], "', levels=c(", levels_list[[i]], "), labels = c(", labels_list[[i]],"))"  )
                eval(parse(text=arg0))

Can you help?

Estatistics
  • 874
  • 9
  • 24

2 Answers2

1

Using eval/parse should be avoided. There are tpyically much easier ways to do what you want in R. For example, with this code, we can just write

Add_Labels_Level_To_Dataset <- function(df, levels_list, labels_list)   {
  df[] <- Map(function(data, levels, labels) {
     ordered(data, levels=strsplit(levels,",")[[1]], labels=strsplit(labels, ",")[[1]])
  }, df, levels_list, labels_list)
  df
}

And we can call it like

dt4 <- Add_Labels_Level_To_Dataset(dt4, level_list, label_list)

Note that it returns a new data.frame which you can reassign to dt4 or some other variable. Functions in R should never modify objects outside their own scope which is one of the other reasons you were running into problems with your function.

MrFlick
  • 195,160
  • 17
  • 277
  • 295
1

This is a xy problem. I agree with @MrFlick that parse should be avoided. On the original post the main issue is the function should be returning dt4 and not df. There are some missing ' (single quote) when defining label_list.

We could use mapply and avoid the single quote:

label_list=list(c('S','SA','SB','SC','SD'), c('S','SA','SB','SC','SD'))
level_list=list(c(5,4,3,2,1), c(5,4,3,2,1))

as.data.frame(mapply(function(x, labels,levels ) {ordered(x, labels,levels)}, dt4, level_list, label_list, SIMPLIFY = F))
#  a1 a2
#1 SA SD
#2 SA SB
#3 SB SA
#4 SA  S
#5 SA SA
Marcelo
  • 4,234
  • 1
  • 18
  • 18
  • I voted your responce as a more elegant / efficient / shorter answer. However, why str() command says factors and not ord.factors when I applied your R command - When applying my R command, it says ord.factors @Marcelo? – Estatistics Jun 01 '17 at 07:16
  • 1
    @Elias I have updated the answer. Adding `SIMPLIFY = F` to `mapply` will preserve the ordered factor class. – Marcelo Jun 01 '17 at 15:51