【问题标题】:detecting common characters in a list of strings, at specific positions在特定位置检测字符串列表中的常见字符
【发布时间】:2019-09-09 01:22:11
【问题描述】:

我有一个非常大的数据集,其中包含许多列,是从应用程序导出的。问题是文件是“空字符”分隔的。使用 readLines 读入文件会产生一个字符串列表,每个字符串具有相同数量的字符。

确定列位置的一种可能方法是检查每个字符串(比如位置 5)是否有一个空字符。因此,可以从向量 1 开始继续搜索,直到找到一个非空字符。

d <- data.frame("V1" = c(" f ggh", "aa hh", "a  qq" ), stringsAsFactors = 
F)


first.char <- function(col){
current <- 0
j <- 1
while(j <= length(d)){
tmp <- substr(d[j], col, col)
if(!grepl("^\\s*$", tmp)){
  current <- 1
  break}
j <- j+1
}
return(current)
}

row_dummies <- lapply( c(1:6), first.char) %>% unlist

这种方法有效,但在扩展时非常慢(有 100 万个字符串的列表,每个 1500 个字符长)。我还尝试将每个向量转换为 data.table,然后使用 str split (Split text string in a data.table columns),但这似乎更加低效,因为在大多数情况下不需要检查所有行。

有什么建议或意见吗?

更新: 上面的例子太琐碎了。这个好一点:

text <- c("df ggh a a h h a  qq",
          "       aa  hh  ab qt",
          " fggh   aa hh  a    ")

想要的输出是

 list( c("df ggh", "a a", "h h", "a",   "qq"),
       c(NA,       "aa",  "hh",  "ab",  "qq"),
       c(" fggh",  "aa",  "hh",  "a",   NA)

 )

str_locate_all 效果很好,因为它指示在哪里拆分字符串:

cuts_in <- sapply(text, function(x) x %>%  str_locate_all(. , "\\s") ) 
cuts_in <- lapply(cuts_in,  data.table) # to data.table    
cuts_in <- rbindlist(cuts_in)
cuts_in <- cuts_in[, .N, by=start] 
cuts_in[ N==3 ,"start"]

   start
   1:     7
   2:    11
   3:    15
   4:    18

但是,这可能不是最有效的方式(有 15 个文件,每个文件一百万行,每行有 1500 个字符)。例如,如果第 1 行位置 1 不是空格,则无需检查第 2 行和第 3 行中位置 1 处的字符。 read_table2 似乎也不是解决方案:

read_table2(text, col_names = FALSE)

  X1    X2    X3    X4    X5    X6    X7    X8   
 <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr>
1 df    ggh   a     a     h     h     a     qq   
2 aa    hh    ab    qt    NA    NA    NA    NA   
3 fggh  aa    hh    a     NA    NA    NA    NA

【问题讨论】:

  • read.table(text = d$V1, as.is = TRUE) 为例。
  • 是的,我的例子太简单了。一个可能的区别可能是我不能在每个空字符处拆分。使用 read.table 我得到以下信息: 扫描错误(file = file,what = what,sep = sep,quote = quote,dec = dec,:第 2 行没有 79 个元素
  • 我想我对所需的输出有点困惑;每行具有相同数量的字符并不意味着由于空格数量不同,您将拥有相同数量的列。你想要什么而不是 read_table2 给你的?
  • 我不知道事前的列数。我需要找出来,并找出他们在哪里。由于数据的导出方式,如果一个单元格(在数据库中)是一个 NA,它会在我的 txt 文件中打印为“”。这意味着我可以通过逐列查看“”来了解列。在上面的示例中,列拆分候选因此位于位置 7、11、15、18。

标签: r substring strsplit


【解决方案1】:

您实际遇到的情况是您需要读取一个固定宽度的文件并且不知道列在哪里,这是我以前不了解的。您可以尝试为此使用readr::read_fwffwf_empty 将查看一些行,默认为 100,并尝试找出相交列的位置。根据您希望在 1500 个字符中包含多少列,您可能需要增加 n 以获得正确的输出。

library(tidyverse)
text <- c("df ggh a a h h a  qq",
          "       aa  hh  ab qt",
          " fggh   aa hh  a    ")
read_fwf(text, fwf_empty(text, n = 100))
#> # A tibble: 3 x 5
#>   X1     X2    X3    X4    X5   
#>   <chr>  <chr> <chr> <chr> <chr>
#> 1 df ggh a a   h h   a     qq   
#> 2 <NA>   aa    hh    ab    qt   
#> 3 fggh   aa    hh    a     <NA>

或者,如果您已经在使用str_locate_all 并且想要查看所有行,您可以通过添加起点和终点并获取差异将生成的位置转换为与fwf_widths 一起使用的宽度。请注意,您不需要将sapplystr_locate_all 一起使用,它已经被矢量化了。这可能会比较慢,因为它会检查每一行,如果您没有得到正确的输出,我会尝试先增加 n

locations <- text %>%
  str_locate_all("\\s") %>%
  map(~.[, 1]) %>%
  reduce(intersect)

widths <- c(1, locations, str_length(text[1])) %>% diff()

read_fwf(text, fwf_widths(widths))
#> # A tibble: 3 x 5
#>   X1     X2    X3    X4    X5   
#>   <chr>  <chr> <chr> <chr> <chr>
#> 1 df ggh a a   h h   a     q    
#> 2 <NA>   aa    hh    ab    q    
#> 3 fggh   aa    hh    a     <NA>

reprex package (v0.2.1) 于 2019 年 4 月 18 日创建

【讨论】:

  • 更新了,因为我更好地理解了这个问题
【解决方案2】:

str_locate_all 来自stringr 怎么样:

library(stringr)

d <- data.frame("V1" = c(" f ggh", "aa hh", "a  qq" ), stringsAsFactors = 
F)

str_locate_all(d$V1, "\\s")


[[1]]
     start end
[1,]     1   1
[2,]     3   3

[[2]]
     start end
[1,]     3   3

[[3]]
     start end
[1,]     2   2
[2,]     3   3

但是,如果您想将其拆分为不同的列,您可以使用 dplyrtidyr 的组合来一次完成所有操作。

library(tidyverse)

d %>%
 mutate(V1 = str_trim(V1, side = "both")) %>%
 separate(V1, c("string_1", "string_2"), sep = "\\s+")

  string_1 string_2
1        f      ggh
2       aa       hh
3        a       qq

【讨论】:

  • 是的,有效,然后可以根据从相交结果中检索到的位置进行拆分。谢谢
  • 更新了答案,以便您将其拆分为具有不同功能的人。随意标记为已回答,这样问题就结束了;)
猜你喜欢
  • 1970-01-01
  • 2022-01-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-08-11
  • 2020-02-23
  • 2020-02-26
  • 2017-09-17
相关资源
最近更新 更多