在R中合并多个CSV文件并去除重复行

5
我有近3000个CSV文件(包含推文),格式相同,我想将这些文件合并成一个新文件并删除重复的推文。我已经看到了许多类似问题的讨论,但通常文件数量很少。我希望你能帮我编写一段R代码,既高效又有效地完成此任务。
CSV文件的格式如下:
CSV格式图像: Example CSV files 我更改了第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/

很明显,这个网站上也有一些与我的问题相关的主题(例如在R中合并多个CSV文件),但我没有找到任何同时讨论合并和去重复的内容。我真的希望你能帮助我和我有限的R知识来处理这个挑战!
虽然我尝试了一些在网上找到的代码,但实际上并没有生成输出文件。约3000个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

在第四行之后,我得到了:
  Error: object 'my.df' not found

我怀疑这些错误是由于csv文件写入过程中出现了一些故障造成的,因为有些情况下作者/本地时间在错误的列中。它们应该在左侧或右侧,这导致了一个额外的列。我手动调整了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

我做错了什么?


我编辑了我的问题,希望这是你想要的? - Gert
filename 包含你想要导入的正确文件列表吗?这段代码显然在一个 read.csv 语句上出现问题。可能需要更改 list.files() 以返回完整路径。你的工作目录是什么? - Andrie
工作目录是包含所有CSV文件的文件。因此,list.files()应该“加载”我需要的CSV文件。对于文件名部分,这是由list.files加载的文件指定的,不是吗? - Gert
你说 list.files 应该可以获取正确的文件。它能行吗?你有检查过吗?如果你的工作目录与 ~/ 不同,那么它就不会起作用。 - Andrie
我刚刚检查了它,确实获取到了正确的文件!我再次尝试了这段代码,现在得到了响应:'NULL'。 - Gert
显示剩余2条评论
1个回答

8

首先,进入文件所在的文件夹,尝试将模式设置为仅读取以“.csv”结尾的文件,例如:

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

这应该会得到一个包含所有推文内容的数据框。另一个问题是csv文件中的标题。幸运的是你知道所有文件都是相同的,所以可以像这样处理它们:
read.csv('fred.csv', header=FALSE, skip=1, sep=';',
    col.names=c('ID','tweet','author','local.time'),
    colClasses=rep('character', 4))

注意:所有列都已更改为字符类型,并使用“;”分隔。

如果需要,稍后可以解析时间...

另一个独立的问题是数据框中推文的唯一性 - 但我不清楚您是否希望它们对用户唯一还是全局唯一。对于全局唯一的推文,可以使用以下方法:

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),]

根据第三行之后修订的警告,这是一个关于列数不同的文件的问题。通常情况下很难修复,除非按照您建议的在规范中使用过多的列。如果删除规范,则在尝试将数据框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),]

我有一些空闲时间,因此决定测试你的建议Sean。在尝试代码的第一部分后,我得到了以下错误..read.table(file = file, header = header, sep = sep, quote = quote, : more columns than column names - Gert
你好,能否发布一下你的CSV文件的前几行(如果可以的话),并指出它们是否都具有相同的格式? - Tim P
Tim,我已经编辑了我的问题,并包含了一个CSV文件的示例图像。我选择了一张图片,因为简单的复制粘贴会破坏问题的布局。所有CSV文件都具有相同的格式,推文数量随着每个CSV文件最多可达1500条而有所不同。 - Gert
你的CSV文件头似乎不适合列。你能检查一下吗? - fotNelton
我认为你的意思是标题(tweet,author和local.time)都应该向右移动1列,如果是这样,那么你是正确的。对于所有的csv文件都是如此。如果不是这样,我该如何检查呢? - Gert
显示剩余11条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接