【问题标题】:"Select" argument in R's data.table::freadR 的 data.table::fread 中的“选择”参数
【发布时间】:2015-10-23 19:22:53
【问题描述】:

我正在尝试使用 fread() 从 csv 中读取选定的列。我发现我可以使用列号向量,但不能使用列名。关于“选择”参数,文档只是说“要保留的列名或数字的向量,删除其余部分。”他们还提供了

的例子
fread(data, select=c("A","D"))

那么,为什么我的代码会抛出 subscript out of bounds 错误?这是我的代码的要点,希望可以推广到其他用户:

test = data.frame(matrix(c(1:50),ncol = 5))
names(test) = c("A", "B", "C", "D", "E")
write.table(test, file = "/Users/me/Desktop/test.txt", sep = ",")
fread("/Users/me/Desktop/test.txt", sep = ",", header = TRUE, select = c("A","B"))

给予

Error in ans[[1]] : subscript out of bounds

但是,这将第一列以及行号作为一列给出:

fread("/Users/me/Desktop/test.txt", sep = ",", header = TRUE, select = c(1,2))
    1  1
1:  2  2
2:  3  3
3:  4  4
4:  5  5
5:  6  6
6:  7  7
7:  8  8
8:  9  9
9: 10 10

...而且 read.table() 能够顺利读取整个数据集:

read.table("/Users/me/Desktop/test.txt", sep = ",", header = TRUE)
    A  B  C  D  E
1   1 11 21 31 41
2   2 12 22 32 42
3   3 13 23 33 43
4   4 14 24 34 44
5   5 15 25 35 45
6   6 16 26 36 46
7   7 17 27 37 47
8   8 18 28 38 48
9   9 19 29 39 49
10 10 20 30 40 50

rownames 和 header 显然有问题,但我不确定如何解决它。我试过有无标题。我正在使用的数据集(不在此示例中)已经具有行名,因此不能使用 rownames = FALSE 重写它。

【问题讨论】:

  • 当然。我无法分享数据,但我会提供一个近似值。
  • 只是想知道,拥有header=FALSE 然后根据名称进行选择是否有意义?
  • 那么,如果你告诉 fread 实际忽略列名,你如何期望 fread 知道列名是 ABC
  • 好点,是的,我试过 header=TRUE。 Fwiw, header=FALSE 也不起作用。这只是当前版本的 nonworking 代码。我现在正在研究一个可重现的例子。感谢您的帮助!
  • 我的测试文件出现了愚蠢的“空文件”错误,所以同时我会说我查看了 data.table::fread 源代码并且几乎没有使用“选择”参数。可能是一个有趣的思想实验。

标签: r csv data.table fread


【解决方案1】:
library(data.table)
library(readr)

# save mtcars as CSV w/o row names or column names

write_csv(mtcars, "mtcars.csv", col_names=FALSE)

# read in the same file with fread but since we tell it
# to not use a header, we have to specify the column names
# the way fread will create them otherwise you get your error

fread("mtcars.csv", header=FALSE, select=c("V1", "V4"))

##      V1  V4
## 1: 21.0 110
## 2: 21.0 110
## 3: 22.8  93
## 4: 21.4 110
## 5: 18.7 175
## 6: 18.1 105

# try again, this time keeping column names in the 
# data file
write.csv(mtcars, file = "mtcars.csv", row.names=FALSE)

# now read it back in and select based on column names
# I picked different columns
head(fread("mtcars.csv", select=c("mpg", "qsec")))

##     mpg  qsec
## 1: 21.0 16.46
## 2: 21.0 17.02
## 3: 22.8 18.61
## 4: 21.4 19.44
## 5: 18.7 17.02
## 6: 18.1 20.2

【讨论】:

    【解决方案2】:

    此答案假定您的原始数据不是通过write.table() 生成的,您获得了一个文件并尝试通过fread() 读取它(问题中也有说明)。


    我相信您遇到此问题是因为文件中的行名。我还没有想出将fread() 应用于数据的直接方法,但我认为这种解决方法将是安全的,并且不会在效率方面花费太多。以下是步骤...

    1) 使用scan() 读取文件的第一行,并在开头添加一个额外的"" 元素。这是为了抵消标题行以说明文件中的行名。

    nm <- c("", scan("test.txt", "", nlines = 1, sep = ","))
    

    2) 定义您想要的列并在nm 中找到它们。现在偏移量不再是 1 和 4,而是为我们提供了 2 和 5,并说明了行名。

    sel <- nm %in% c("A", "D")
    

    3) 读取文件,从第二行开始(即没有标题),并在选择参数中使用sel

    library(data.table)
    dt <- fread("test.txt", skip = 1, select = which(sel))
    

    4) 现在我们已经读取了我们想要的数据,我们可以重置列名。

    setnames(dt, nm[sel])[]
    #      A  D
    #  1:  1 31
    #  2:  2 32
    #  3:  3 33
    #  4:  4 34
    #  5:  5 35
    #  6:  6 36
    #  7:  7 37
    #  8:  8 38
    #  9:  9 39
    # 10: 10 40
    

    如果您给出的示例很好地代表了实际数据,那么我看不出有任何原因导致这不起作用。希望它对你有用。

    【讨论】:

      【解决方案3】:

      问题不在于您的 fread,而在于您的 write.table。 默认情况下,它将每一行的名称写入第一列。看看写入的文件。

      试试这个:(明确不写 row.names)

      write.table(test, file = "/Users/me/Desktop/test.txt", 
                  sep = ",", row.names=FALSE)
      

      然后做你的 fread()。它会起作用的。

      【讨论】:

      • 请注意南希的最后一句话,在您发布答案前 2 小时编辑的版本中:“我正在使用的数据集(不在此示例中)已经有行名,所以用行名重写它= FALSE 不是一个选项。"
      【解决方案4】:

      这个例子说明了为什么您总是需要仔细检查您正在生成的文件的格式。 read.tablefread 有一些区别;这里的问题来自行名以及它们是如何由write.table 编写的。与往常一样,仔细阅读文档 (?write.table) 会有很大帮助。

      write.table 默认写入行名。但方法如下:

      filename<-"somefilename.txt"
      write.table(test, file = filename, sep = ",")
      readLines(filename,2)
      #[1] "\"A\",\"B\",\"C\",\"D\",\"E\"" 
      #"\"1\",1,11,21,31,41"
      

      我阅读了生成文件的前两行。仔细阅读它们,您会发现这不是“标准”CSV。为什么?因为标题有 4 个逗号,而“数据”行有 5 个。对于标准 CSV,您应该在第一个列名 之前 放置一个逗号。这是通过在write.table 中添加col.names=NA 来实现的:

      write.table(test, file = filename, sep = ",", col.names=NA)
      #now works
      fread(filename, sep = ",", header = TRUE, select = c("A","B"))
      

      您可以检查并看到现在出现了一个逗号作为文件的第一个字符。或者,您可以避免编写将row.names=FALSE 放入write.table 的行名称,但这并不总是可行的,因为有时它们是有意义的。

      【讨论】:

        猜你喜欢
        • 2013-01-04
        • 1970-01-01
        • 2015-12-30
        • 2013-07-09
        • 2012-09-20
        • 2020-08-23
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多