合并多个 CSV 文件并删除 R 中的重复项

Posted

技术标签:

【中文标题】合并多个 CSV 文件并删除 R 中的重复项【英文标题】:Merge multiple CSV files and remove duplicates in R 【发布时间】:2012-06-13 06:15:19 【问题描述】:

我有近 3000 个格式相同的 CSV 文件(包含推文),我想将这些文件合并到一个新文件中并删除重复的推文。我遇到过讨论类似问题的各种主题,但是文件的数量通常很少。我希望您能帮助我在 R 中编写代码,以高效且有效地完成这项工作。

CSV 文件具有以下格式:

CSV 格式的图像:

我将(在第 2 列和第 3 列中)用户名(在 Twitter 上)更改为 A-E,将“实际名称”更改为 A1-E1。

原始文本文件:

"tweet";"author";"local.time"
"1";"2012-06-05 00:01:45 @A (A1):  Cruijff z'n met-zwart-shirt-zijn-ze-onzichtbaar logica is even mooi ontkracht in #bureausport.";"A (A1)";"2012-06-05 00:01:45"
"2";"2012-06-05 00:01:41 @B (B1):  Welterusten #BureauSport";"B (B1)";"2012-06-05 00:01:41"
"3";"2012-06-05 00:01:38 @C (C1):  Echt ..... eindelijk een origineel sportprogramma #bureausport";"C (C1)";"2012-06-05 00:01:38"
"4";"2012-06-05 00:01:38 @D (D1):  LOL. \"Na onderzoek op de Fontys Hogeschool durven wij te stellen dat..\" Want Fontys staat zo hoog aangeschreven? #bureausport";"D (D1)";"2012-06-05 00:01:38"
"5";"2012-06-05 00:00:27 @E (E1):  Ik kijk Bureau sport op Nederland 3. #bureausport  #kijkes";"E (E1)";"2012-06-05 00:00:27"

不知何故我的标题搞砸了,他们显然应该向右移动一列。每个 CSV 文件最多包含 1500 条推文。我想通过检查第二列(包含推文)来删除重复项,因为它们应该是唯一的并且作者列可以相似(例如,一位作者发布多条推文)。

是否可以将合并文件和删除重复文件结合起来,或者这是在自找麻烦,是否应该将进程分开?作为起点,我包含了两个链接,来自 Hayward Godwin 的两个博客,讨论了合并 CSV 文件的三种方法。

http://psychwire.wordpress.com/2011/06/03/merge-all-files-in-a-directory-using-r-into-a-single-dataframe/

http://psychwire.wordpress.com/2011/06/05/testing-different-methods-for-merging-a-set-of-files-into-a-dataframe/

显然,本网站上也有一些与我的问题相关的主题(例如Merging multiple csv files in R),但我没有找到任何讨论合并和删除重复项的内容。我真的希望你能帮助我和我有限的 R 知识应对这个挑战!

虽然我尝试了一些在网上找到的代码,但这实际上并没有生成输出文件。大约 3.000 个 CSV 文件具有上述格式。我的意思是尝试了以下代码(用于合并部分):

filenames <- list.files(path = "~/")
do.call("rbind", lapply(filenames, read.csv, header = TRUE))              

这会导致以下错误:

Error in file(file, "rt") : cannot open the connection 
In addition: Warning message: 
In file(file, "rt") : 
  cannot open file '..': No such file or directory 

更新

我已经尝试了以下代码:

 # grab our list of filenames
 filenames <- list.files(path = ".", pattern='^.*\\.csv$')
 # write a special little read.csv function to do exactly what we want
 my.read.csv <- function(fnam)  read.csv(fnam, header=FALSE, skip=1, sep=';',     col.names=c('ID','tweet','author','local.time'), colClasses=rep('character', 4)) 
 # read in all those files into one giant data.frame
 my.df <- do.call("rbind", lapply(filenames, my.read.csv))
 # remove the duplicate tweets
 my.new.df <- my.df[!duplicated(my.df$tweet),]

但我遇到以下错误:

在第三行之后我得到:

  Error in read.table(file = file, header = header, sep = sep, quote = quote,  :  more columns than column names

在第 4 行之后我得到:

  Error: object 'my.df' not found

我怀疑这些错误是由 csv 文件的写入过程中的一些失败引起的,因为有些情况下 author/local.time 在错误的列中。在他们应该在的位置的左侧或右侧,这会导致额外的列。我手动调整了 5 个文件,并在这些文件上测试了代码,我没有收到任何错误。然而,它似乎什么也没发生。我没有从 R 得到任何输出?

为了解决多列问题,我稍微调整了代码:

 #grab our list of filenames
 filenames <- list.files(path = ".", pattern='^.*\\.csv$')
 # write a special little read.csv function to do exactly what we want
 my.read.csv <- function(fnam)  read.csv(fnam, header=FALSE, skip=1, sep=';',   col.names=c('ID','tweet','author','local.time','extra'), colClasses=rep('character', 5)) 
 # read in all those files into one giant data.frame
 my.df <- do.call("rbind", lapply(filenames, my.read.csv))
 # remove the duplicate tweets
 my.new.df <- my.df[!duplicated(my.df$tweet),]

我在所有文件上都尝试了这段代码,虽然 R 显然开始处理,但我最终得到了以下错误:

 Error in read.table(file = file, header = header, sep = sep, quote = quote,  : more columns than column names
 In addition: Warning messages:
 1: In read.table(file = file, header = header, sep = sep, quote = quote,  : incomplete final line found by readTableHeader on 'Twitts -  di mei 29 19_22_30 2012 .csv'
 2: In read.table(file = file, header = header, sep = sep, quote = quote,  : incomplete final line found by readTableHeader on 'Twitts -  di mei 29 19_24_31 2012 .csv'

 Error: object 'my.df' not found

我做错了什么?

【问题讨论】:

显示一些你正在使用的代码。您可能向您的read.csv() 发送了错误的header 参数。 你的问题已经很清楚了,但不清楚你到目前为止做了什么以及为什么它不起作用。显示用于读取文件的 read.csv() 调用。然后我们可以评论你做错了什么。 我编辑了我的问题,希望这是你想要的吗? filename 是否包含您要导入的文件的正确列表?这段代码显然落在了read.csv 语句之一上。您可能需要更改 list.files() 以返回完整路径。你的工作目录是什么? 工作目录是包含所有 CSV 文件的文件。因此 list.files() 应该“加载”我所追求的 CSV 文件。对于文件名部分,这是由 list.files 加载的文件指定的,不是吗? 【参考方案1】:

首先,通过位于文件所在的文件夹中来简化问题,并尝试将模式设置为只读文件结尾为“.csv”的文件,例如

filenames <- list.files(path = ".", pattern='^.*\\.csv$')
my.df <- do.call("rbind", lapply(filenames, read.csv, header = TRUE))

这应该会为您提供一个包含所有推文内容的 data.frame

另一个问题是 csv 文件中的标题。幸好你知道所有文件都是相同的,所以我会处理这样的事情:

read.csv('fred.csv', header=FALSE, skip=1, sep=';',
    col.names=c('ID','tweet','author','local.time'),
    colClasses=rep('character', 4))

铌。已更改,因此所有列都是字符,并且 ';'分开

如果需要,我会在稍后解析出时间...

另一个单独的问题是 data.frame 中推文的唯一性 - 但我不清楚您是否希望它们对用户是唯一的或全局唯一的。对于全球唯一的推文,类似

my.new.df <- my.df[!duplicated(my.df$tweet),]

对于作者的独特性,我会附加这两个字段 - 但是如果没有真实数据,很难知道什么是有效的!

my.new.df <- my.df[!duplicated(paste(my.df$tweet, my.df$author)),]

因此,将所有内容放在一起,并在此过程中假设一些事情......

# grab our list of filenames
filenames <- list.files(path = ".", pattern='^.*\\.csv$')
# write a special little read.csv function to do exactly what we want
my.read.csv <- function(fnam)  read.csv(fnam, header=FALSE, skip=1, sep=';',
    col.names=c('ID','tweet','author','local.time'),
    colClasses=rep('character', 4)) 
# read in all those files into one giant data.frame
my.df <- do.call("rbind", lapply(filenames, my.read.csv))
# remove the duplicate tweets
my.new.df <- my.df[!duplicated(my.df$tweet),]

根据第 3 行之后的修订警告,这是具有不同列数的文件的问题。这通常不容易修复,除非您建议在规范中有太多列。如果您删除规范,那么当您尝试将 data.frames rbind() 结合在一起时会遇到问题...

下面是一些使用 for() 循环和一些调试 cat() 语句的代码,可以更明确地说明哪些文件已损坏,以便您修复问题:

filenames <- list.files(path = ".", pattern='^.*\\.csv$')

n.files.processed <- 0 # how many files did we process?
for (fnam in filenames) 
  cat('about to read from file:', fnam, '\n')
  if (exists('tmp.df')) rm(tmp.df)
  tmp.df <- read.csv(fnam, header=FALSE, skip=1, sep=';',
             col.names=c('ID','tweet','author','local.time','extra'),
             colClasses=rep('character', 5)) 
  if (exists('tmp.df') & (nrow(tmp.df) > 0)) 
    cat('  successfully read:', nrow(tmp.df), ' rows from ', fnam, '\n')
    # now lets append a column containing the originating file name
    # so that debugging the file contents is easier
    tmp.df$fnam <- fnam

    # now lets rbind everything together
    if (exists('my.df')) 
      my.df <- rbind(my.df, tmp.df)
     else 
      my.df <- tmp.df
    
   else 
    cat('  read NO rows from ', fnam, '\n')
  

cat('processed ', n.files.processed, ' files\n')
my.new.df <- my.df[!duplicated(my.df$tweet),]

【讨论】:

Thnx Sean,明天就试试吧!文件夹里只有.csv文件,所以pattern部分好像没必要.. 我有一些空闲时间,因此决定测试肖恩的建议。尝试代码的第一部分后出现以下错误。read.table 中的错误(file = file,header = header,sep = sep,quote = quote,:比列名更多的列 您好,您能否发布一个 csv 文件的前几行(假设没问题)并指出它们是否都具有相同的格式? 蒂姆,我已经编辑了我的问题并包含了一张图片作为我的 csv 文件的示例。我选择了一个图像,因为简单地复制粘贴破坏了问题的布局。所有 CSV 文件都具有相同的格式,推文的数量最多不同。每个 csv 文件最多 1500 个。 似乎您的 CSV 文件的标题不适合列。你能检查一下吗?

以上是关于合并多个 CSV 文件并删除 R 中的重复项的主要内容,如果未能解决你的问题,请参考以下文章

删除多个 CSV 文件之间的重复项

Python:合并文件并删除重复项

如何从 r 中的数据框中删除标题行? [复制]

我需要计算行的实例并根据多个列值删除重复项

合并两个 Eloquent Collections 并删除所有重复项。

使用值将数组中对象的属性合并在一起并删除重复项