【问题标题】:R - renaming multiple columns in multiple dataframes, using nested loopR - 使用嵌套循环重命名多个数据框中的多个列
【发布时间】:2017-11-06 04:25:35
【问题描述】:

我有 29 个数据框,分别命名为 Student1 到 Student 29。这 29 个数据框中的每一个都包含变量 Name、Nationality 和 Membership.number,每个变量的末尾都有相应的数字。例如Student1 包含 Name.1、Nationality.1 和 Membership.number.1,Student29 包含 Name.29 等。

我试图通过去掉这些变量名末尾的数字来标准化这些。我对 R 很陌生,但我已经整理了以下代码来尝试自动执行此操作。

for (j in 1:29) {
 for (i in 1:3) {
    oldnames = c(paste('Name', i, sep="."), paste('Nationality', i, sep="."), paste('Membership.number', i, sep="."))
    newnames = c("Name", "Nationality", "Membership.number")
    names(paste("Student",j,sep=""))[names(paste("Student",j,sep=""))==oldnames[i]]=newnames[i]
  }
}

这似乎接近实现我想要的,并且如果我插入 Student1 代替 paste("Student",j,sep=""),但对于单个数据帧,它应该可以正常工作,但是粘贴 ("Student ",j,sep="") 代码似乎由于“分配目标扩展到非语言对象”而失败。我在这里做错了什么简单的事情吗?

【问题讨论】:

    标签: r loops dataframe


    【解决方案1】:

    问题在于 paste() 返回一个字符串,因此您的代码实际上是在执行以下操作:

    names("Student1")[names("Student1")==oldnames[i]] = newnames[i]
    

    但是,当然,字符串"Student1" 与包含您的数据框的变量Student1 不同,所以这不会让您走得太远。该错误消息有点令人困惑,但最终意味着您正在尝试分配给无法分配的东西。

    最简单的解决方案是使用函数get()assign(),它们以字符串命名变量(如字符串"Student1")并允许您检索和分配变量。例如,这将重命名Student1 的列之一:

    dfname = "Student1"
    df = get(dfname)
    names(df)[names(df)=="Name.1"] = "Name"
    assign(dfname, df)
    

    所以,你可以写:

    for (j in 1:29) {
        oldnames = c(paste('Name', j, sep="."), 
                     paste('Nationality', j, sep="."),
                     paste('Membership.number', j, sep="."))
        newnames = c("Name", "Nationality", "Membership.number")
        dfname = paste("Student", j, sep="")
        df = get(dfname)
        for (i in 1:3) {
            names(df)[names(df) == oldnames[i]] = newnames[i]
        }
        assign(dfname, df)
    }
    

    请注意,我修复了 oldnames 定义以使用 j 而不是 i 并将仅依赖于 j 的定义移出内部循环。这里需要注意的是,这只适用于“顶级”(即,在 R 提示符下输入)。如果你把它放在一个函数中,那么assign() 会变得更棘手,因为你需要指定 where 你想要分配的变量(在顶层,其余的全局变量,在函数内,等等.).

    此代码仍有待改进。原来你对oldnames的定义可以改写为:

    oldnames = paste(c("Name","Nationality","Membership.number"), j, sep=".")
    

    这意味着你实际上可以写:

    newnames = c("Name","Nationality","Membership.number")
    oldnames = paste(newnames, j, sep=".")
    

    您可以更进一步,使用函数match。此函数在其第二个参数中获取其第一个参数的每个元素的索引,并可用于同时检索names() 向量中所有oldnames 的位置。然后,您甚至不需要内部循环:

    for (j in 1:29) {
        newnames = c("Name","Nationality","Membership.number")
        oldnames = paste(newnames, j, sep=".")
        dfname = paste("Student", j, sep="")
        df = get(dfname)
        names(df)[match(oldnames, names(df))] = newnames
        assign(dfname, df)
    }
    

    这种使用match 来查找和替换向量中的值是一种非常常见的 R 技术。

    最后,如果数据框中没有任何其他列(所以您真的只想删除所有名称末尾包含句点和一些数字的所有后缀),那么 R 中的一个常见技巧是使用sub() 使用正则表达式修改名称:

    for (j in 1:29) {
        newnames = c("Name","Nationality","Membership.number")
        oldnames = paste(newnames, j, sep=".")
        dfname = paste("Student", j, sep="")
        df = get(dfname)
        names(df) = sub("\\.[0-9]+$", "", names(df))
        assign(dfname, df)
    }
    

    注意,在R中,正则表达式中的反斜杠需要加倍,所以上面的"\\."会匹配一个句点。在清理在一堆列名上具有不需要的前缀和后缀的数据集时,我一直使用这种基于 sub 的技术。

    R-ing 快乐!

    【讨论】:

    • 这太棒了,谢谢 - 以及对我的问题的回答,一些有用的额外提示和修复来清理我的代码。我只是在 R 的第二天,所以这将有助于清除一些锈迹!非常感谢。
    猜你喜欢
    • 2021-02-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多