【问题标题】:How do I use the new line character in R?如何在 R 中使用换行符?
【发布时间】:2019-10-07 19:46:01
【问题描述】:

我需要用“R”中的文本文件制作一个表格,以便对其进行统计。我的文本文件包含特殊字符,如“$”和“下一行符号”(或 Microsoft Word 中的段落 sing,等于 Microsoft Word 中的 ^p)。

我阅读了this post,但它没有回答我的问题。 例如,我的文本文件是这样的:

-The$data 1 is taken on Aug, 2009 at UBC
and is significant with p value <0.01

-The$data 2 is taken on Sep, 2012 at SFU
and is  not significant with p value > 0.06

-....

使用 gsub 进行多个查找/替换,我想制作一个这样的表:

1,Aug,2009,UBC,,p value <0.01
2,Sep,2012,SFU,not, p value > 0.06

如果您知道从文本文件中提取表格的任何包/函数,这也会很有帮助。

【问题讨论】:

  • 这个问题是关于将非标准文件解析为data.frame,使用换行符与它有什么关系?解决这个问题需要一些正则表达式的工作。
  • 我认为你的换行点是指如何组合看似相关的行,我认为stackoverflow.com/a/58208836/3358272 将非常相关(特别是cumsum(grepl(...)))。从那里开始,我认为您的正则表达式将能够更好地处理每次观察的一行。
  • Lionette,这个问题的任何解决方案(正则表达式或其他)的强度将在很大程度上取决于您提供的数据的稳定性。这里有足够的样本来处理仓促的事情,但如果您有明显不同的文本(例如没有p value,或缺少逗号等),那么最好在样本中包含变体行。
  • Lionette,通过删除 regex 标记,您是否暗示您不想要基于正则表达式的解决方案?
  • 哦,对不起,我以为我错误地添加了正则表达式,我不知道什么是正则表达式。我只是用谷歌搜索并找到了。抱歉,我是“R”的新手

标签: r regex


【解决方案1】:

正则表达式解决方案对句子的形成非常敏感,并且由于它们具有不规则的间距,我推断它们要么是人为生成的,要么是通过不规则/不一致的过程生成的。偏离这种模式肯定会导致部分中断。

因此,我将使其尽可能具体和健壮,以便 (1) 即使未找到列也会保留,并且 (2) 不正确的句子不会破坏作品。

我假设您会使用以下内容读取数据:

dat <- readLines("path/to/file.txt")

所以对于示例数据,我将使用

dat <- strsplit("-The$data 1 is taken on Aug, 2009 at UBC
and is significant with p value <0.01

-The$data 2 is taken on Sep, 2012 at SFU
and is  not significant with p value > 0.06

-This$datum is different from the others
and is not significant", "[\n\r]")[[1]]

从这里开始,我将使用 cumsum(grepl(...)) 的技巧来查找我知道一行开始的实例,然后将以下行组合在一起。

cumsum(grepl("^-", dat))
# [1] 1 1 1 2 2 2 3 3
combined <- unlist(as.list(by(dat, cumsum(grepl("^-", dat)), paste, collapse = "\n")), use.names=FALSE)
combined
# [1] "-The$data 1 is taken on Aug, 2009 at UBC\nand is significant with p value <0.01\n"      
# [2] "-The$data 2 is taken on Sep, 2012 at SFU\nand is  not significant with p value > 0.06\n"
# [3] "-This$datum is different from the others\nand is not significant"                       

现在这些行已按逻辑分组,这里有一个冗长但(我相信)最强大的方法来解析您想要的列。 (我应该注意到,编写一个尝试捕获所有内容的单个正则表达式当然是可行的;其中的挑战是,如果您想捕获大多数存在的东西,或者如果某些东西不正确则失败。我倾向于保存什么您可以稍后确定哪个模式不足;如果您宁愿在模式的一小部分不起作用时丢弃整个记录,那么这可能会简化为单个模式。)

patterns <- c(
  "(?<=data )[0-9]+(?= is taken)",
  "(?<=taken on )\\w+(?=, 2)",
  "(?<=, )2[0-9]{3}\\b",
  "(?<= at )\\w+(?=\n)",
  "(?<=and is ).*(?=significant)",
  "(?<=significant with).*"
)

lapply(patterns, function(ptn) {
  trimws(sapply(regmatches(combined, gregexpr(ptn, combined, perl = TRUE)), `length<-`, 1))
})
# [[1]]
# [1] "1" "2" NA 
# [[2]]
# [1] "Aug" "Sep" NA   
# [[3]]
# [1] "2009" "2012" NA    
# [[4]]
# [1] "UBC" "SFU" NA   
# [[5]]
# [1] ""    "not" "not"
# [[6]]
# [1] "p value <0.01"  "p value > 0.06" NA              

可以通过以下方式轻松捕获、命名和框化该输出:

as.data.frame(setNames(
  lapply(patterns, function(ptn) {
    trimws(sapply(regmatches(combined, gregexpr(ptn, combined, perl = TRUE)), `length<-`, 1))
  }),
  c("number", "month", "year", "acronym", "not", "pvalue")),
  stringsAsFactors = FALSE)
#   number month year acronym not         pvalue
# 1      1   Aug 2009     UBC      p value <0.01
# 2      2   Sep 2012     SFU not p value > 0.06
# 3   <NA>  <NA> <NA>    <NA> not           <NA>

【讨论】:

  • 正则表达式既强大又强大,如果被误解,则会造成重大损失。仔细使用它们并理解“不匹配”的含义。既然您在这里学习正则表达式,我会这样说:我的回答特别避免了gsub,因为如果不加小心,它会很高兴地返回整个短语(当什么都没有找到时),而不是您最初想要提取的部分.我敢肯定会有数据会破坏这种正则表达式组合。
  • 非常感谢。文本文件是人工生成的,它有 100 多行。这只是文件的一个示例,我还有 100 多个由不同中心生成的文件。
  • 这能回答你的问题吗?
  • 我之所以这么问,是因为我也想学习(尽我所能)并理解它,以便能够针对不同的情况进行修改。
  • 如果你想测试/尝试我的代码来学习它,那么你需要使用整行代码。对于strsplit,它至少需要两个参数:字符串和拆分模式。在我的示例代码中,您省略了第二个参数"[\n\r]"。但同样,如果您先使用Text1 &lt;- readLines(...),则不需要该行。
猜你喜欢
  • 2021-08-09
  • 2018-04-05
  • 1970-01-01
  • 1970-01-01
  • 2011-08-22
  • 1970-01-01
  • 1970-01-01
  • 2019-12-17
相关资源
最近更新 更多