【问题标题】:R data.table: referring to data table column with externally assigned column nameR data.table:引用外部分配列名的数据表列
【发布时间】:2019-05-17 19:25:32
【问题描述】:

我正在阅读大量包含每种产品每月价格信息的文件。

我想获得一个合并所有这些文件的数据表。

此表的键将是带有产品标识符和日期的 2 列。

然后第三列包含零售价。

在源文件中,每个价格列都有一个格式为 RETAILPRICE_[dd.mm.yyyy] 的名称。

为了防止我的最终数据表包含大量列,我需要用零售价重命名该列并创建一个包含日期的新列。

以下代码遇到错误,因为data.table 不理解对其一列的外部引用。

# this is how I obtain the list of files that have to be read in
# list the files
# files <- list.files(path = "path",
#                    pattern = "^Publications.*$",
#                    full.names = T)

# the data looks like this, although it is contained in an excel file.
# sample data
ProdID <- list(836187, 2398159, 2398165, 2398171, 2398188, 1800180, 2320105, 2320128, 2320140, 2320163, 1714888, 2516340)
RETAILPRICE_01.01.2003 <- c(12.50, 43.50, 65.50, 45.60, 69.45, 21.30, 81.15, 210.70, 405.00, 793.60, 116.50, 162.60)
Publications_per_2003.01.01 <- data.table(ProdID,RETAILPRICE_01.01.2003)

# uncomment if you want to write this to excel
# using .xls on purpose, because that's what they used back in the days
# xlsx::write.xlsx(Publications_per_2003.01.01,
#    "Publications_per_2003.01.01.xls",
#    row.names = F)
# files <- list.files(path = "path",
#                    pattern = "^Publications.*$",
#                    full.names = T)

# create data table
price_list <- data.table(
                 prodID = character(),
                 date = character(),
                 retail_price = numeric())


price_list <- lapply(files, function(x){

  # obtain date from file name
  # date in file name has the structure yyyy_mm_dd
  # while in the column name date has the structure
  # dd.mm.yyyy
  date <- substr(sapply(strsplit(x,"_"),"[",3),1,10)

  # obtain day, month and year separately
  day <- substr(date,9,10)
  month <- substr(date,6,7)
  year <- substr(date,1,4)

  # store the name of the column containing the retail price
  priceVar <- as.name(paste0("RETAILPRICE_",day,".",month,".",year))

  # read the xls file with the price info and in one go
  # keep only the relevant columns
  file <- data.table(read_excel(x))[
    ,.(prodID= as.character(ProdID),
       retail_price = priceVar,
       date = as.character(gsub("\\.","-",date)))#,with = F
    ]

  # merge the new file with the existing data table
  price_list <- merge(price_list,file,"ProdID")
})

这会导致错误消息

Error in rep(x[[i]], length.out = mn) : 
  attempt to replicate an object of type 'symbol'

如果我评论该部分

retail_price = priceVar,

没有错误。

所以问题在于对列的引用以某种方式不起作用。

我也试过

priceVar <- as.name(paste0("RETAILPRICE_",day,".",month,".",year))

file <- data.table(read_excel(x))

setnames(file, priceVar, "retail_price")

但我得到了错误(列名已修改以适合示例):

Error in setnames(file, priceVar, "retail_price") : 
  Items of 'old' not found in column names: RETAILPRICE_dd.mm.yyyy.

如果有人能启发我,我将永远感激不尽。

【问题讨论】:

  • 这里真的需要使用data.table吗?使用带有列选择的良好旧数据框会更简单:read_excel(x)[, c("ProdID", paste0("RETAILPRICE_",day,".",month,".",year))]。然后,根据需要设置列名。
  • 还有一点:不能在函数内部修改全局变量price_list。使用您编写的内容,将在函数内部创建price_list 的本地副本,并且将不可见地返回合并结果。但是全局变量不会被修改,也不会产生预期的累积效果。解决方法:函数返回file,在lapply(...)之后多出一步:file_list &lt;- do.call(rbind, file_list)
  • 由于文件量很大,我更喜欢使用data.table,因为它更快。
  • 感谢您对合并的提醒。还没有专注于那部分。将实施它。
  • 在这种情况下不会有任何影响:read_excel 返回一个tibble,因此您必须将转换的价格支付给data.table。由于您只有 3 列,因此无需直接进行此转换,即使行数很大

标签: r data.table


【解决方案1】:

在这种情况下,使用普通数据帧而不是 data.table 会容易得多。

price_list <- lapply(files, function(x){
  date <- substr(sapply(strsplit(x,"_"),"[",3),1,10)

  day <- substr(date,9,10)
  month <- substr(date,6,7)
  year <- substr(date,1,4)

  # make it a character, not a name
  priceVar <- paste0("RETAILPRICE_",day,".",month,".",year)

  one_df <- readxl::read_excel(x)[, c("ProdID", priceVar)]
  colnames(one_df) <- c("prodID", "retail_price")
  one_df$prodID = as.character(one_df$prodID) # NB: as.integer would be much more efficient, but be careful for values above 2.0e9
  one_df$date = as.character(gsub("\\.","-",date))

  one_df
})

# Watch out: this will pile up the records from all files
# In your initial code you were using merge(...) which computes the intersection
price_list <- do.call(rbind, price_list)

# Optional:
data.table::setDT(price_list)

【讨论】:

    【解决方案2】:

    如果您提供您正在使用的数据的示例,我们可以使用数据示例尝试您的代码。 我还阅读了您的代码并在此行:

    price_list <- merge(prijslijst,file,"ProdID")
    

    您从未提到变量“prijslijst”,所以问题可能就在那里。

    【讨论】:

    • 感谢您指出这一点。我翻译了变量名称以提高理解,但我向您保证这不是问题的根源。我将添加一个数据样本。
    猜你喜欢
    • 1970-01-01
    • 2021-04-21
    • 2021-12-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-12-25
    • 2017-01-20
    • 2016-02-02
    相关资源
    最近更新 更多