如何在R中读取具有不同列数的CSV文件

55

我有一个稀疏的数据集,它的列数长度不等,并且以csv格式存储。以下是文件文本的示例。

12223, University
12227, bridge, Sky
12828, Sunset
13801, Ground
14853, Tranceamerica
14854, San Francisco
15595, shibuya, Shrine
16126, fog, San Francisco
16520, California, ocean, summer, golden gate, beach, San Francisco

当我使用

read.csv("data.txt", header = F)

R会将数据集解释为有3列,因为其大小是从前5行确定的。是否有办法强制R将数据放入更多列?

有没有办法强制R将数据放入更多列?


你知道你的数据集中最大的列数是多少吗? - Blue Magister
是的,最大列数已知。 - CompChemist
1
我的直觉是,在read.table中指定colClasses参数(最大列数)并与fill = TRUE结合使用应该可以读取文件。 - Blue Magister
1
@BlueMagister 我也是这么想的,但它不起作用。 - Roland
你可以创建一个包含2行正确列数的虚拟 data.frame,然后使用 rbind 函数将文本文件添加到其中吗? - John Paul
5个回答

75

?read.table文档中有如下内容:

数据列的数量是通过查看输入的前五行(或整个文件,如果少于五行),或者通过col.names的长度来确定的,如果指定并且更长,则可能错误。如果fillblank.lines.skip为真,则可能出现错误,因此在必要时请指定col.names(如“示例”中所示)。

因此,让我们将col.names定义为长度为X(其中X是数据集中字段的最大数量),并设置fill = TRUE

dat <- textConnection("12223, University
12227, bridge, Sky
12828, Sunset
13801, Ground
14853, Tranceamerica
14854, San Francisco
15595, shibuya, Shrine
16126, fog, San Francisco
16520, California, ocean, summer, golden gate, beach, San Francisco")

read.table(dat, header = FALSE, sep = ",", 
  col.names = paste0("V",seq_len(7)), fill = TRUE)

     V1             V2             V3      V4           V5     V6             V7
1 12223     University                                                          
2 12227         bridge            Sky                                           
3 12828         Sunset                                                          
4 13801         Ground                                                          
5 14853  Tranceamerica                                                          
6 14854  San Francisco                                                          
7 15595        shibuya         Shrine                                           
8 16126            fog  San Francisco                                           
9 16520     California          ocean  summer  golden gate  beach  San Francisco

如果字段的最大数量未知,您可以使用漂亮的实用函数count.fields(我在read.table示例代码中找到):

count.fields(dat, sep = ',')
# [1] 2 3 2 2 2 2 3 3 7
max(count.fields(dat, sep = ','))
# [1] 7

可能会有帮助的相关阅读:在R中仅读取有限数量的列


这花了我很长时间。非常感谢你! - erksch

7
您可以按照以下方式阅读数据:
dat <- textConnection("12223, University
12227, bridge, Sky
12828, Sunset
13801, Ground
14853, Tranceamerica
14854, San Francisco
15595, shibuya, Shrine
16126, fog, San Francisco
16520, California, ocean, summer, golden gate, beach, San Francisco")

dat <- readLines(dat)
dat <- strsplit(dat, ",")

这将生成一个列表。

2
我手头的数据集非常大。我正在寻找一种无需复制和粘贴文件内容的解决方案。我知道我可以在ruby中打开文件并搜索一行中逗号数量最多的位置,并将该行移动到第一行。然后我可以在R中打开文件,那么问题就解决了,但我希望在R中能有一个简单的解决方案。 - CompChemist
2
显然,您将使用文件连接(请参阅 ?connection)。但是我无法访问您的文件... - Roland
2
@CompChemist 在dat的位置上放置你的文件对象(data.txt)。textConnection被用来快速读取你的示例文件。 - Blue Magister

3
这似乎起作用了(遵循@BlueMagister的建议):
tt <- read.table("~/Downloads/tmp.csv", fill=TRUE, header=FALSE, 
          sep=",", colClasses=c("numeric", rep("character", 6)))
names(tt) <- paste("V", 1:7, sep="")

     V1             V2             V3      V4           V5     V6             V7
1 12223     University                                                          
2 12227         bridge            Sky                                           
3 12828         Sunset                                                          
4 13801         Ground                                                          
5 14853  Tranceamerica                                                          
6 14854  San Francisco                                                          
7 15595        shibuya         Shrine                                           
8 16126            fog  San Francisco                                           
9 16520     California          ocean  summer  golden gate  beach  San Francisco

我刚刚又尝试了一下。如果我使用“text”参数,这个不起作用。 - Roland
啊哈..原来是这个原因..知道了这个区别真好!谢谢你回信。 - Arun

3

我面临着类似的挑战,但是 Blue Magister 的答案中的 count.fields 不能正常工作,可能是因为字段内的逗号与 sep="," 冲突。此外,列数从文件到文件不同。 因此,我只需在 read.table 中定义过多的 col.names(在我的情况下,100就足够了),然后使用 which(!is.na()) 来摆脱多余的列。

dat <- read.table("path/to/file.csv", col.names = paste("V",1:100), fill = T, sep = ",")
dat <- dat[,which(!is.na(dat[1,]))]

太棒了!你是传奇。谢谢你。 - shiny

1
尝试这个,它更加动态...
readVariableWidthFile <- function(filePath){
  con <-file(filePath)
  lines<- readLines(con)
  close(con)
  slines <- strsplit(lines,",")
  colCount <- max(unlist(lapply(slines, length)))

  FileContent <- read.csv(filePath,
                        header = FALSE,
                        col.names = paste0("V",seq_len(colCount)),
                        fill = TRUE)
  return(FileContent)
}

1
请在您的回答中添加更多解释。您的回答有什么不同于当前接受的答案? - Sean Pianka
我同意这种方法更具动态性,因为它允许您遍历 csv 而不需要指定列数。 - mikey

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