【问题标题】:Function not saving changes to DataFrame函数不保存对 DataFrame 的更改
【发布时间】:2016-08-10 23:11:20
【问题描述】:

您好,我正在尝试编写一个接收数据框的函数,如果名称中有特殊字符或空格,则修复其各自的列标题。该功能似乎可以工作,因为打印了结果,但它似乎没有将相应的更改保存到原始数据帧。关于如何解决这个问题的想法?我用来测试它的数据是 tbl_df,所以我不确定这是否与它没有正确更新的原因有关。谢谢。

nameChange <- function(df) {
  for(i in 1:length(colnames(df)[i])) {
  if(str_detect(colnames(df[i]),"[:punct:]|[:space:]") == TRUE) {
  #Could use "\\s" to find space
  names(df) <- str_replace_all(names(df)," *",'')
  names(df) <- str_replace_all(names(df),"-",'')
  #df <- df
  assign('df',df, envir=.GlobalEnv)
  #return(df)
  print("Worked")
  }

    else{
      print("Function did not replace anything")
    }
  }
}

这是我用来测试功能的数据:

#data from: http://www.tableau.com/learn/tutorials/on-demand/getting-started-data
orders_path <- file.path("/Users/petergensler/Desktop/Global Superstore.xls")
order_table <- read_excel(orders_path, sheet = "Orders")
nameChange(order_table)

一旦我在 order_table 上调用 colnames,您应该能够看到 Product Sub-Category 中的连字符已被删除,并且每个列名称内的所有空格都不再存在。

【问题讨论】:

  • 只是为了检查...str_replace_all(names(df)," *",'')str_replace_all(names(df),"-",'') 给你想要的输出?
  • 是的,我知道部分功能可以正常工作。我可以使用 \\s 来查找字符串中的空格,或者使用 [:space:] 来检测它们。我真正的问题是,当我将它传递给 tbl_df 时,它会显示所做的更改,但是当我在 tbl_df 上调用 colnames 时,看起来并没有保存更改。
  • 它说它有效,但它似乎仍然没有保存结果。
  • 也许 MWE 会有所帮助。
  • @petergensler 您是否希望它修改输入数据框并将其保存为相同的名称,以便如果您调用 nameChange(hey) 会修改“嘿”data.frame?如果是这样,那么您只是对事物的运作方式有误解。您将直接保存到“df”,因此如果您查看全局环境,您应该会看到保存为“df”的结果

标签: r dataframe


【解决方案1】:

您的功能可以简化:

nameChange <- function(df) {
  names(df) <- str_replace_all(names(df), "[:punct:]|[:space:]",  "")
  return(df)
}

例子:

library(dplyr)
library(stringr)

df <- tbl_df(mtcars)
names(df)[1] <- "m p g"
names(df)[2] <- "c-y-l"
names(df)
#  [1] "m p g" "c-y-l" "disp"  "hp"    "drat"  "wt"    "qsec"  "vs"    "am"   
# [10] "gear"  "carb" 

df <- nameChange(df)
names(df)
#  [1] "mpg"  "cyl"  "disp" "hp"   "drat" "wt"   "qsec" "vs"   "am"   "gear"
# [11] "carb"

【讨论】:

  • 这根本不是我想要做的。我想定义一个接收数据帧的函数,根据 [:punct:]|[:space:] = 搜索字符,并将结果保存到我提供的数据帧中。
  • 上面的例子完全符合您的要求。 df 是提供的数据帧。 str_replace_all 函数搜索带图案的字符串(在此处替换您想要的图案)。然后返回 df 并将结果保存到原始数据框中。
【解决方案2】:

除了任何其他问题(在 cmets 中提到;for 循环中的 i 未定义),问题似乎是您没有分配回原始数据对象:

 assign('df',df, envir=.GlobalEnv)

分配给对象df,我猜你会在成功运行函数后在你的环境中找到它。

大概是你想要的

 dfname <- deparse(substitute(df))
 assign(dfname, df, envir=.GlobalEnv)

这似乎对测试有效。

【讨论】:

  • i 应该是数据框中的总列数(即 24)。长度(列名(订单表)[])。所以对于从 1 到 24 开始的每个元素,当 IF 语句为 TRUE 时,它就会被执行。所以它应该在每次运行时递增。
  • @petergensler 您的问题中有for(i in 1:length(colnames(df)[i]));第二个i 没有定义。无论如何,1:ncol(df) 或更好的seq_along(df) 有什么问题?
  • 对不起,我认为我发布了错误版本的代码....如果您编写 colnames(superstore[1]),它会返回“行 ID”,这是数据集中的第一个列名
  • 这大概是 OP 试图实现的最佳答案。很抱歉,尽管如此,我无法投票。具有这种副作用的函数只是糟糕的代码。不应该鼓励未来的读者做这种事情。正如您在评论中指出的那样,在@WeihuangWong 的回答中返回对象是处理这种情况的正确方法。
【解决方案3】:

下面是回答我问题的代码:

test1 <- function(df){
    names(df) <- str_replace_all(names(df), "[:punct:]|[:space:]","")
    df <<- df
    return(df)
}

使用 df 作为参数没有任何问题,但是您确实需要使用全局赋值

【讨论】:

  • 是的,我很高兴看到那些反对票越来越多。虽然我很高兴你找到了一些有用的东西,但这并不能回答你的问题“这有什么问题?” &lt;&lt;- 相当于我的回答,而不是对回答过你的人的启示。无论如何使用它被认为是非常糟糕的做法。返回 df 并分配是标准的 R 方法。
猜你喜欢
  • 1970-01-01
  • 2022-01-13
  • 1970-01-01
  • 2012-11-01
  • 1970-01-01
  • 2012-12-18
  • 1970-01-01
  • 1970-01-01
  • 2016-07-13
相关资源
最近更新 更多