迭代数据帧中的列,以替换数据帧列表中匹配数据的值

我有兴趣构建一个使用apply / sapply或Map的函数,它将迭代dta中的可用列,并用来自数据帧的无名列表中的数据帧的匹配值替换每列中的值,列表项索引对应于dta数据帧的列号.

给定对象:

set.seed(1)
size <- 20

# Data set
dta <-
    data.frame(
        unitA = sample(LETTERS[1:4], size = size, replace = TRUE),
        unitB = sample(letters[16:20], size = size, replace = TRUE),
        unitC = sample(month.abb[1:4], size = size, replace = TRUE),
        someValue = sample(1:1e6, size = size, replace = TRUE)
    )

# Meta data
lstMeta <- list(
    # Unit A definitions
    data.frame(
        V1 = c("A", "B", "D"),
        V2 = c("Letter A", "Letter B", "Letter D")
    ),
    # Unit B definitions
    data.frame(
        V1 = c("t", "q"),
        V2 = c("small t", "small q")
    ),
    # Unit C definitions
    data.frame(
        V1 = c("Mar", "Jan"),
        V2 = c("March", "January")
    )
)

期望的结果

当应用于dta时,该函数应返回与以下提取对应的data.frame:

unitA       unitB    unitC      someValue
Letter B    small t  Apr        912876
Letter B    small q  March      293604
       C    s        Apr        459066
Letter D    p        March      332395
Letter A    small q  March      650871
Letter D    small q  Apr        258017
Letter D    p        January    478546
C           small q  Feb        766311
C           small t  March      84247
Letter A    small q  March      875322
Letter A    r        Feb        339073
Letter A    r        Ap         839441
C           r        Feb        346684
Letter B    p        January    333775
Letter D    small t  January    476352
(...)

现有方法

replaceLbls <- function(dataSet, lstDict) {
    sapply(seq_along(dataSet), function(i) {
        # Take corresponding metadata data frame
        dtaDict <- lstDict[[i]]

        # Replace values in selected column
        # Where matches on V1 push corrsponding values from V2
        dataSet[,i][match(dataSet[,i], dtaDict[,1])] <- dtaDict[,2][match(dtaDict[,1], dataSet[,i])]  
    })
}

# Testing -----------------------------------------------------------------

replaceLbls(dataSet = dta, lstDict = lstMeta)

当然,上面提出的方法不起作用,因为它会尝试在分配中使用NA;但它总结了我想要实现的目标:

Error in x[...] <- m : NAs are not allowed in subscripted assignments
In addition: Warning message: In [<-.factor(*tmp*, match(dataSet[,
i], dtaDict[, 1]), value = c(NA,
: invalid factor level, NA
generated

补充说明

源数据集

数据的关键特征是:

>列表是无名的,因此子集必须通过项目编号而不是名称来完成
>项目编号对应于列编号
>数据列表中可用的元数据数据帧与数据中可用的单位列之间没有完全匹配
> someValue列也应该迭代,因为它可能包含应该替换的标签

>我对基于dplyr/data.table / sqldf的解决方案不感兴趣.
>我对嵌套的for循环不感兴趣

最佳答案
以下方法适用于示例数据:

replaceLbls <- function(dataSet, lstDict) {
  dataSet[seq_along(lstDict)] <- Map(function(x, lst) {
    x <- as.character(x)
    idx <- match(x, as.character(lst$V1))
    replace(x, !is.na(idx), as.character(lst$V2)[na.omit(idx)])
  }, dataSet[seq_along(lstDict)], lstDict)
  dataSet
}


head(replaceLbls(dta, lstMeta))
#      unitA   unitB unitC someValue
# 1 Letter B small t   Apr    912876
# 2 Letter B small q March    293604
# 3        C       s   Apr    459066
# 4 Letter D       p March    332395
# 5 Letter A small q March    650871
# 6 Letter D small q   Apr    258017

这假定您要将更改应用于与元列表一样长的数据的第一个X列.您可能希望包含一个额外的步骤来转换回因子,因为此方法将调整后的列转换为字符类.

关于因素的另一个评论:您可以通过仅处理任何因子变量的级别而不是整个列来加速性能.一般过程类似,但需要更多步骤来检查课程等.

转载注明原文:迭代数据帧中的列,以替换数据帧列表中匹配数据的值 - 代码日志