需要有关使用 R 清理数据的建议

Posted

技术标签:

【中文标题】需要有关使用 R 清理数据的建议【英文标题】:Need advice on using R to clean up data 【发布时间】:2022-01-09 11:19:47 【问题描述】:

我有多个相同格式的 csv 文件需要合并,但在此之前

    标题不是第一行而是第四行。我应该通过跳过删除前 3 行吗?还是我应该重新分配标题? 我需要在合并之前添加一列,该列是文件的 ID(与文件名相同)。 那么我只需要从总共 7 列中提取 4 列。 总结一个类别下的数字。 将所有 csv 文件合并为一个。

这就是我目前所做的第 1、3、4 步,然后只添加 2 个列然后 5 个,不确定我是否应该先在 ID 列中添加?

files = list.files(pattern = "*.csv", full.names = TRUE)

library("tidyverse")
library("dplyr")

data = data.frame()

for (file in files)
    temp <- read.csv(file, skip=3, header = TRUE)
    colnames(temp) <- c("Volume", "Unit", "Category", "Surpass Object", "Time", "ID")
    temp <- temp [, c("Volume", "Category", "Surpass Object")]
    temp <- subset(temp, Category =="Surface")
    mutate(id = file)
    aggregate(temp$Volume, by=list(Category=temp$Category), FUN=sum)
    

我得到了一个错误:

Error in is.data.frame(.data) : 
  argument ".data" is missing, with no default

如果我没有放入 mutate 行,代码很好,所以我认为主要问题来自那里,但任何建议都将不胜感激。

我对 R 很陌生,非常感谢我能在这里找到的所有 cmets。

提前致谢!

【问题讨论】:

您肯定错过了在mutate 中调用数据框。如果您尝试在temp 上执行此操作,则需要在管道中添加。 temp &lt;- subset(temp, Category =="Surface") %&gt;% mutate(id = file) 你也在做所有这些计算,然后丢弃结果,永远不会捕获到一个持续存在的对象中。请参阅***.com/a/24376207/3358227 以了解有关对帧列表进行操作的良好讨论,即执行诸如读取多个文件和处理列表中的数据集之类的操作。在本例中,我们不需要将它们分开(但如果您愿意,绝对可以),但该页面上的前提和其他指导仍然适用。 @AndrewGillreath-Brown 感谢您的评论。我尝试了代码,由于某种原因,id 列中只显示了一个文件名,不确定其他文件名是否被相同的文件名替换? 【参考方案1】:

您可以使用read.csv(),但如果文件很多,我建议使用data.table 包中的fread()。它明显更快。我在这里使用了fread(),但如果你把它换成read.csv(),它仍然可以工作。 fread() 也更高级。你会发现,即使像skip 这样的东西有时也可以省略,仍然可以正确读取。

library(tidyverse)
library(data.table)

add_filename <- function(flnm)
    fread(flnm, skip = 3) %>%   # read file
    mutate(id = basename(flnm)) # creates new col id w/ basename of the file 


# single data frame all CSVs; id in first col
df <- list.files(pattern = "*.csv", full.names = TRUE) %>%
    map_df(~add_filename) %>%
    select(id, Volume, Category, `Surpass Object`)

我得到的印象是您想要聚合但也保留合并的数据框。如果是这种情况,您将聚合与构建数据框分开。

df %>%       # not assigned to a new object, so only shown in console
    filter(Category == "Surface") %>%  # filter for the category desired
    sum(.$Volume)                    # sum the remaining values for volume

如果您不知道,最后一次调用中的时间段是结转的数据,因此在这种情况下,是过滤后的数据。解释 的最简单方法(也许不是最好的方法)是 sum() 不是为处理数据帧而设计的,因此与 dplyr 管道并不友好。

如果您想要每个类别的音量总和,而不仅仅是您在问题中编码的"Surface",那么您可以改用它:

df %>% 
    group_by(Category) %>%
    summarise(sum(Volume))

请注意,我在这里使用了 summarize 的英式拼写。函数summarize() 在很多包中。我刚刚发现,每当我想确保它是我调用的 dplyr 函数时,对这个函数使用英国拼写更容易。 (我认为,tidyverse 几乎所有函数都接受美式和英式拼写。)

【讨论】:

谢谢凯特!你的回答很有帮助。我很高兴能够在其中添加 id 列。但是,对于最后一部分,代码倾向于汇总列中的所有内容,而不是根据类别。所以我有两个类别(A 和 B),Surpass 对象是子类别(A1、A2、B1 和 B2),对于这一部分,我只想总结 A1、A2、B1 和 B2。 你能把你的数据快照发给我吗?a reproducible example?我会更容易理解正在发生的事情。 嗨,Kat,感谢您的跟进。在一位同事的建议下,我设法让代码正常工作。基本上是我错过了一些东西,但你的台词有效!也适用于 map_df(add_filename) 而不是带有 ~ 的那个。谢谢!【参考方案2】:

由于您似乎在尝试使用dplyr,所以我会坚持使用该主题。

library(dplyr)
library(purrr)
files = list.files(pattern = "*.csv", full.names = TRUE)
results <- map_dfr(setNames(nm = files), ~ read.csv(.x, skip=3, header=TRUE), .id = "filename") %>%
  select(filename, Category, Volume, Surpass) %>% # no idea why you want Surpass
  group_by(filename, Category) %>%
  summarize(Volume = sum(Volume))                 # Surpass is discarded here

演练:

    purrr::map_dfr 在每个输入(files 中的每个文件)上迭代我们的函数 (read.csv(...)) 并将其进行行连接。由于我们用它们自己命名文件(setNames(nm=files) 类似于 names(files) &lt;- files),我们可以使用 id="filename" 添加一个“文件名”列,以反映每行是从哪个文件中获取的。

    select(...) 你说你需要的任何四列。坦率地说,既然你在汇总,我们真的只需要c("filename", "Category", "Volume"),其他任何东西,你可能在你的解释中遗漏了一些东西。

    group_by(..) 将允许我们为每个文件名获取一行,每个Category,其中Volume 是一个总和(在下一步中计算,summarize)。

【讨论】:

感谢您的回答和评论。我这样做的原因是由于标题问题,我尝试在组合 ID(或文件名)消失之前和之后组合所有 csv 文件。是的,对于您的第 2 点,我错过了一条重要信息。原始文件有一个 ID 列,它不是文件名。我打算使用文件名作为真实 ID。为此,您认为我应该为真实 ID 列分配不同的名称吗?我需要 Surpass 对象作为列之一,因为其中有两种类型的数据。 如果您需要"Surpass",那么您是否也需要对其进行分组?汇总不能在既不是 (a) 分组变量之一,也不是 (b) 在汇总中计算的字段上工作。在我的答案中添加了作为 id 的文件名。除了您的第四列之外,我认为这段代码可以满足您的要求,对吗? 我运行了代码,它给了我一个错误。错误:必须按在.data 中找到的变量分组。 * 未找到列 filename。任何想法?谢谢! 这意味着您的select(..) 明确省略了filename。为了明确起见,我正在编辑此答案以包含它,但我仍然不知道您需要的其余列名。我猜,要解决一个不完整的问题真的很令人沮丧。 感谢 r2evans。 Select() 中的四列是我需要的,最后我会根据体积来总结。超越是类别的一种子类别,这就是为什么我不能省略它。我再次运行了代码,但出现了一个错误,即 Surpass 不存在。无论如何,感谢您的 cmets。

以上是关于需要有关使用 R 清理数据的建议的主要内容,如果未能解决你的问题,请参考以下文章

R - 为 Google BigQuery 导入清理数据

R自定义功能来清理数据

使用 R 清理大数据中不必要的变量

如何清理Nginx缓存

会话数据库表清理

R语言数据清理:视频游戏数据案例研究