对于这种事情,R相对较新,搜索了一下,找不到有用的东西。
我有大约150个.csv文件,每个文件有40,000到60,000行,我试图将每个列中的3列合并为1个大数据帧。我有一个小脚本,从每个文件中提取3个感兴趣的列(" id"," name"和#34; value")并通过" ID"和"名称"使用更大的数据框" MergedData"。这是我的代码(我确定这是一种非常低效的方式,这对我来说现在还可以,但我当然可以选择更好的选项!):
file_list <- list.files()
for (file in file_list){
if(!exists("MergedData")){
MergedData <- read.csv(file, skip=5)[ ,c("id", "name", "value")]
colnames(MergedData) <- c("id", "name", file)
}
else if(exists("MergedData")){
temp_data <- read.csv(file, skip=5)[ ,c("id", "name", "value")]
colnames(temp_data) <- c("id", "name", file)
MergedData <- merge(MergedData, temp_data, by=c("id", "name"), all=TRUE)
rm(temp_data)
}
}
并非每个文件都具有相同的行数,但许多行对于许多文件是通用的。我没有包含行的列表,所以我包括all = TRUE来追加MergedData文件中尚不存在的新行。
我的问题是:许多文件包含2-4行,相同的&#34; id&#34;和&#34;名称&#34;条目,但不同的&#34;值&#34;条目。因此,当我合并它们时,我最终会为每个可能的组合添加行,这会快速失控。最令人沮丧的是,这些重复内容对我来说都没有任何意义。有没有一种简单的方法来获取第一个条目的值,只是忽略任何进一步的重复条目?
谢谢!
答案 0 :(得分:0)
根据您的评论,我们可以堆叠每个文件,然后从&#34; long&#34;转换结果数据框。到&#34;宽&#34;格式:
library(dplyr)
library(readr)
library(reshape2)
df = lapply(file_list, function(file) {
dat = read_csv(file)
dat$source.file = file
return(dat)
})
df = bind_rows(df)
df = dcast(df, id + name ~ source.file, value.var="value")
在上面的代码中,在读取每个文件后,我们添加一个包含文件名(或其修改版本)的新列source.file
。*然后我们使用dcast
来转换数据框来自&#34; long&#34;到&#34;宽&#34;格式为每个文件中的value
创建一个单独的列,每个新列采用我们刚刚在source.file
中创建的名称之一。
另请注意,根据您计划对此数据框执行的操作,您可能会发现将其保留为长格式(即跳过dcast
步骤)进行进一步分析会更方便。
附录:处理Aggregation function missing: defaulting to length
警告。如果您有多个行具有相同的id
,name
和source.file
,则会发生这种情况。这意味着有多个value
必须映射到同一个单元格,从而导致聚合。默认聚合函数是length
(即,该单元格中值的数量)。我所知道的唯一解决方法是(a)以长格式保存数据,(b)使用不同的聚合函数(例如mean
),或(c)添加额外的counter
用于区分具有id
,name
和source.file
的相同组合的多个值的案例的列。我们在下面演示这些。
首先,让我们创建一些假数据:
df = data.frame(id=rep(1:2,2),
name=rep(c("A","B"), 2),
source.file=rep(c("001","002"), each=2),
value=11:14)
df
id name source.file value 1 1 A 001 11 2 2 B 001 12 3 1 A 002 13 4 2 B 002 14
id
,name
和source.file
的每个组合只有一个值,因此dcast
可以正常工作。
dcast(df, id + name ~ source.file, value.var="value")
id name 001 002 1 1 A 11 13 2 2 B 12 14
使用相同的id
,name
和source.file
添加其他行。由于现在有两个value
映射到单个单元格,dcast
必须聚合。默认聚合函数是提供值的计数。
df = rbind(df, data.frame(id=1, name="A", source.file="002", value=50))
dcast(df, id + name ~ source.file, value.var="value")
Aggregation function missing: defaulting to length id name 001 002 1 1 A 1 2 2 2 B 1 1
而是使用mean
作为汇总功能。
dcast(df, id + name ~ source.file, value.var="value", fun.aggregate=mean)
id name 001 002 1 1 A 11 31.5 2 2 B 12 14.0
添加新的counter
列,以区分多个行具有相同id
,name
和source.file
的情况,并将其包括在内dcast
。这会让我们回到每个单元格的单个值,但代价是为某些source.file
设置了多个列。
# Add counter column
df = df %>% group_by(id, name, source.file) %>%
mutate(counter=1:n())
正如您所看到的,counter
值只有id
,name
和{{1}的一种组合时,其值才为1 },但是对于一种情况,其值为1和2,其中有两行具有相同的source.file
,id
和name
(下面的第3行和第5行)。
source.file
df
现在我们 id name source.file value counter
1 1 A 001 11 1
2 2 B 001 12 1
3 1 A 002 13 1
4 2 B 002 14 1
5 1 A 002 50 2
包含dcast
,因此我们为counter
&#34; 002&#34;提供了两列。
source.file
dcast(df, id + name ~ source.file + counter, value.var="value")
*我不确定您的文件名是什么样的,因此您可能需要调整此项创建一个具有唯一文件标识符的命名格式。例如,如果您的文件名遵循&#34; file001.csv&#34;,&#34; file002.csv&#34;等模式,则可以执行以下操作: id name 001_1 002_1 002_2
1 1 A 11 13 50
2 2 B 12 14 NA
。