обнаружение общих символов в списке строк в определенных позициях - PullRequest
1 голос
/ 18 апреля 2019

У меня очень большой набор данных со множеством столбцов, экспортированных из приложения.Проблема в том, что файл разделен «пустым символом».Чтение в файле с 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

Этот подход работает, но очень медленный при увеличении масштаба (есть список из 1 миллиона строк, каждый из 1500 символов)долго).Я также попытался преобразовать каждый вектор в таблицу data.table, а затем использовать str split ( Разделить текстовую строку в столбцах data.table ), но это представляется еще более неэффективным, учитывая, что в большинствеВ некоторых случаях нет необходимости проверять все строки.

Любые предложения или рекомендации?

ОБНОВЛЕНИЕ: Приведенный выше пример слишком тривиален.Это немного лучше:

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 в строках 2 и 3, учитывая, что позиция 1 в строке 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

Ответы [ 2 ]

2 голосов
/ 18 апреля 2019

Ситуация, в которой вы фактически оказались, заключается в том, что вам нужно прочитать файл фиксированной ширины и не знать, где находятся столбцы, чего я раньше не понимал. Вы можете попробовать использовать readr::read_fwf для этого. fwf_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, добавив начальную и конечную точки и взяв различия. Обратите внимание, что вам не нужно использовать sapply с str_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>

Создано в 2019-04-18 пакетом представ. (v0.2.1)

1 голос
/ 18 апреля 2019

Как насчет 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

Но если вы пытаетесь разбить его на разные столбцы, вы можете использовать комбинацию dplyr и tidyr, чтобы сделать этовсе сразу.

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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...