需要有关使用 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 <- subset(temp, Category =="Surface") %>% 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) <- 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 清理数据的建议的主要内容,如果未能解决你的问题,请参考以下文章