【问题标题】:R Statistics: Read subset of irregular file into dataframeR统计:将不规则文件的子集读入数据帧
【发布时间】:2018-05-27 20:01:32
【问题描述】:

我有一个文本文件,它由 4 个单独的组件(与数据集关联的源、使用和实际数据)组成。我想将每个组件读入一个单独的 R 对象。

文件格式示例如下。每个文件都有关键字 SOURCE、STORY、USAGE 和 DATASET 作为分隔符。

示例数据集

来源 Boxofficemojo.com 故事 这些长度和数量可变的行将包含数据集背后的故事。 用法 “课程”“年”“节”“练习” “课程 1” 5 9 “前 3” “课程 1” 5 9 “前 4” “课程 1” 5 9 “前 5” “课程 2” 5 9 “前 3” “课程 2” 5 9 “前 4” 数据集 带有标题的数据集如下。

我的问题只是将 USAGE 部分作为数据框读取。我编写了一个快速的逐行解析器,它扫描文件中的关键字 USAGE 和 DATASET 并返回它们的行号。但是,此代码有效:

Usage <- read.table(Output.File, skip= 9, nrows = 6, header = TRUE)

但这段代码没有

Usage <- read.table(Output.File, skip= Beginrow, nrows = Endrow - Beginr4w, header = TRUE)

如何使 read.table() 或任何其他函数允许使用变量跳过和行数?或者,是否有更简单的方法可以将 USAGE 和 DATASET 之间的数据作为数据表读入?

USAGE 总是有 4 列,标题名称与上面文件中的相同,但使用的行数可以从 1 到任意数字。

【问题讨论】:

  • 在您呈现的数据中,您只需要skip=7
  • 我从一个稍微不同的文件中粘贴了代码。最终,我将在许多文件上运行它。该代码只是为了表明它在硬编码时可以工作,但在使用变量时会失败。
  • 嗯,差异肯定在其他地方——它不能是“变量”与“硬编码”,因为没有这样的差异。如果您正确计算了skipnrows,您的第二个版本将起作用
  • 可能是Endrow - Beginr4w 中的拼写错误(您可能指的是 Beginrow 而不是 Beginr4w ——您说您粘贴了它,所以我认为拼写错误在原版中)

标签: r text subset read.table


【解决方案1】:

这是一种可扩展的方法。首先,将整个文件读入带有readLines 的变量。我将使用textConnection 在 SO 上进行重现,但您应该从文件中读取。

x <- readLines(con=textConnection('
SOURCE
Boxofficemojo.com

STORY
These lines, of variable length and number, would contain the story behind the dataset.

USAGE
"Course"    "Year"  "Section"   "Exercise"
"Course1"   5   9   "ex 3"
"Course1"   5   9   "ex 4"
"Course1"   5   9   "ex 5"
"Course2"   5   9   "ex 3"
"Course2"   5   9   "ex 4"

DATASET
Dataset with headers follows.'))

过滤掉前面我介绍的空行:

head(x)
# [1] ""                                                                                       
# [2] "SOURCE"                                                                                 
# [3] "Boxofficemojo.com"                                                                      
# [4] ""                                                                                       
# [5] "STORY"                                                                                  
# [6] "These lines, of variable length and number, would contain the story behind the dataset."
allcaps <- grep("^[A-Z]+$", x)
if (allcaps[1] > 1) x <- x[-(1:(allcaps[1]-1))]

我推断只有大写字母的行表示“标题”。这也可以通过cumsum(x %in% c("USAGE",...)) 来完成:

str( x2 <- split(x, cumsum(grepl("^[A-Z]+$", x))) )
# List of 4
#  $ 1: chr [1:3] "SOURCE" "Boxofficemojo.com" ""
#  $ 2: chr [1:3] "STORY" "These lines, of variable length and number, would contain the story behind the dataset." ""
#  $ 3: chr [1:8] "USAGE" "\"Course\"    \"Year\"  \"Section\"   \"Exercise\"" "\"Course1\"   5   9   \"ex 3\"" "\"Course1\"   5   9   \"ex 4\"" ...
#  $ 4: chr [1:2] "DATASET" "Dataset with headers follows."

(您也可以选择删除尾随的空字符串,也许使用x2 &lt;- lapply(x2, head, n=-1) 之类的东西,尽管最后一个会受到影响,因为它没有它。使用Filter(nchar, x2) 也可能有效,但它假设没有“有意的”空行。交给你。)

下一步可能是装饰性的,但将“标题”作为列表元素名称,随后的行作为数据:

str( x3 <- setNames(lapply(x2, `[`, -1L),
                    sapply(x2, `[`, 1L)) )
# List of 4
#  $ SOURCE : chr [1:2] "Boxofficemojo.com" ""
#  $ STORY  : chr [1:2] "These lines, of variable length and number, would contain the story behind the dataset." ""
#  $ USAGE  : chr [1:7] "\"Course\"    \"Year\"  \"Section\"   \"Exercise\"" "\"Course1\"   5   9   \"ex 3\"" "\"Course1\"   5   9   \"ex 4\"" "\"Course1\"   5   9   \"ex 5\"" ...
#  $ DATASET: chr "Dataset with headers follows."

最后,你可以对嵌入的元素做任何你需要的事情:

x3$USAGE <- read.table(textConnection(x3$USAGE), header=TRUE)
str(x3)
# List of 4
#  $ SOURCE : chr [1:2] "Boxofficemojo.com" ""
#  $ STORY  : chr [1:2] "These lines, of variable length and number, would contain the story behind the dataset." ""
#  $ USAGE  :'data.frame':  5 obs. of  4 variables:
#   ..$ Course  : Factor w/ 2 levels "Course1","Course2": 1 1 1 2 2
#   ..$ Year    : int [1:5] 5 5 5 5 5
#   ..$ Section : int [1:5] 9 9 9 9 9
#   ..$ Exercise: Factor w/ 3 levels "ex 3","ex 4",..: 1 2 3 1 2
#  $ DATASET: chr "Dataset with headers follows."

【讨论】:

  • 好的。这行得通。我希望我在 R 方面做得足够好,能够理解上面出现的 75% 的内容,而我目前还没有得到,所以谢谢!
  • 如果想限制标签的实际名称,这将如何工作?也就是说,不要寻找全部大写的所有内容,而是寻找特定的关键字?
  • x3[ names(x3) %in% c("USAGE","DATASET") ] 会将其减少到只有两个。这种方法有点暴力,这意味着如果你的文件很大,那么它会降低效率。如果是这种情况,您最好使用 R 之外的东西进行过滤。也许readLines(pipe("sed -ne '/USAGE/,/DATASET/p' ProfessorE.txt")) 是一个开始。
【解决方案2】:

这个想法是,首先你必须设法为你选择包含相关数据的字符串的所需部分,然后从你读取的子字符串中选择 csv。在下面的解决方案中,strsplit 函数用于获取 USAGE 和 DATASE 之间的部分,无论有多少行。我基本上把字符串分成了方便的部分。你可以在strsplit了解更多:

str <- 'SOURCE
Boxofficemojo.com

STORY
These lines, of variable length and number, would contain the story behind the dataset.

USAGE
"Course"    "Year"  "Section"   "Exercise"
"Course1"   5   9   "ex 3"
"Course1"   5   9   "ex 4"
"Course1"   5   9   "ex 5"
"Course2"   5   9   "ex 3"
"Course2"   5   9   "ex 4"

DATASET
Dataset with headers follows.'

# get the desired part of the string
datasetStr <- strsplit(paste0(strsplit(str, 'USAGE')[[1]][2]), 'DATASET')[[1]][1]
# read it as data frame
df <- read.csv(text = datasetStr, sep = '\t')

哪个输出

> df
  Course....Year..Section...Exercise
1             Course1   5   9   ex 3
2             Course1   5   9   ex 4
3             Course1   5   9   ex 5
4             Course2   5   9   ex 3
5             Course2   5   9   ex 4

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-06-24
    • 2017-12-24
    • 2015-02-26
    • 2021-09-16
    • 2015-09-18
    • 2017-06-03
    相关资源
    最近更新 更多