0

My goal is to set the column names on a data frame. The name of this data frame is stored in a variable name_of_table.

name_of_table<-"table_13"

assign(name_of_table,read.csv("table_13_air_vehicle_risks_likelihood_and_cost_effects.csv", header=FALSE))
# This works fine, like table_13 <- read.csv(...)

first_level_header <- c("one","two","three","four","five")

colnames(get(name_of_table)) <- first_level_header
# Throws error: 
#Error in colnames(get(name_of_table)) <- first_level_header : 
#  could not find function "get<-"

Obviously if I substitute table_13 for get(name_of_table) this works. If instead I try:

colnames(names(name_of_table)) <- first_level_header
#Throws error: Error in `colnames<-`(`*tmp*`, value = c("one", "two", "three", "four", : attempt to set 
#'colnames' on an object with less than two dimensions

I was pointed to this post earlier: R using get() inside colnames

But eval(parse(paste0("colnames(",name_of_table,")<- first_level_header"))), besides being hideous, does not work either: Error in file(filename, "r") : cannot open the connection

I don't understand the suggestion involving SetNames.

I apologize if get/assign is not the right approach, of course I want to do this the "right" way, I appreciate the guidance.

leviemb
  • 49
  • 6
  • 3
    It is rarely a good idea to use `assign` to programmatically read in CSV files and assign to frames; if you're doing it dynamically, better to read them in to a [list of frames](https://stackoverflow.com/a/24376207/3358272), since when doing that, it is common to do the same thing to all frames in the list. – r2evans Aug 10 '20 at 16:57
  • 2
    I would put the data.frame in a list and then `names(myList) <- name_of_table`. Now, to mess around with the column names, you do ` `colnames(myList[[name_of_table]]) <- first_level_header`. – lmo Aug 10 '20 at 16:57
  • 2
    Further, the use of `get` and `assign` can be meaningful in some choice examples but typically indicate a flawed approach to data management. This might be a subjective approach, but I think you'll find most R aficionados (and -adas) avoid them in most situations. – r2evans Aug 10 '20 at 16:58
  • But to answer your question, I think the error is clear: don't nest `get` inside `\`colnames<-\``. If you must use `get`, then `df <- get(...); colnames(df) <- ...; assign(df, ...)` – r2evans Aug 10 '20 at 16:59
  • Another two "furthers": (1) you're using `parse` incorrectly, the first argument is a **file**, not a string, and that error is also very direct, see `parse(text=...)`. And (2) the use of `eval(parse(...))` to try to set column names is draconian and I strongly recommend against this brute-force method you're attempting. I applaud the effort, but there are so many ways this can and will go wrong, when there are direct and less-problematic *idiomatic* approaches available. – r2evans Aug 10 '20 at 17:02
  • 1
    since you are already using `assign`, you could do `assign(name_of_table, \`names<-\`(get(name_of_table), first_level_header))` or even `assign(name_of_table, setNames(get(name_of_table), first_level_header))` – Onyambu Aug 10 '20 at 17:03
  • I tried @lmo and r2evans's suggestion and simply created a list with one element, read the file into that, and then instead of using get(name_of_variable) I can use name_of_list[[name_of_variable]]. I'll post the precise code that works in case someone stumbles on this later. Thank you!! – leviemb Aug 10 '20 at 17:19
  • `my_table_name <- "table_13"` `list_of_files <- list("table_13_air_vehicle_risks_likelihood_and_cost_effects.csv") ` `list_of_tables <- lapply(list_of_files,read.csv,header=FALSE)` `names(list_of_tables) <- list(my_table_name)` `colnames(list_of_tables[[my_table_name]]) <- c("one","two","three","four","five")` – leviemb Aug 10 '20 at 17:29

1 Answers1

1

You could use library(data.table)

table_13 = data.table(1:5, 1:5, 1:5, 1:5, 1:5) 
setnames(get(name_of_table), first_level_header)  # N.B. also works for a data.frame
#    one two three four five
# 1:   1   1     1    1    1
# 2:   2   2     2    2    2
# 3:   3   3     3    3    3
# 4:   4   4     4    4    4
# 5:   5   5     5    5    5
dww
  • 30,425
  • 5
  • 68
  • 111