问题在于 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 快乐!