читать прямоугольные блоки данных с отдельными тегами как новые столбцы - PullRequest
0 голосов
/ 30 мая 2019

Я чувствую, что моя ситуация является типичным случаем использования в экспериментах, когда данные записываются в виде текстового файла для понимания человеком, но не для машинного потребления. Теги перемежаются с фактическими данными для описания следующих данных. Для анализа данных теги должны быть интегрированы со строками данных, чтобы быть полезными. Ниже приведен пример.

TAG1, t1_1

DATA_A, 5, 3, 4, 8
DATA_A, 3, 4, 5, 7

TAG1, t1_2
TAG2, t2_1

DATA_B, 1, 2, 3, 4, 5

DATA_A, 1, 2, 3, 4

Желаемыми результатами разбора должны быть два кадра данных. Один для DATA_A,

X1, X2, X3, X4, TAG1, TAG2
5, 3, 4, 8, t1_1, NA
3, 4, 5, 7, t1_1, NA
1, 2, 3, 4, t1_2, t2_1

и один для DATA_B

X1, X2, X3, X4, X5, TAG1, TAG2
1, 2, 3, 4, 5, t1_2, t2_1

Текущий метод (реализованный в Python) проверяет файл строка за строкой. Если он начинается с «T», то соответствующая переменная тега обновляется; если он начинается с «DATA», то значения тегов добавляются в конец строки «DATA», а завершенная строка добавляется в соответствующий файл CSV. В конце файлы CSV считываются во фреймы данных для анализа данных.

Интересно, можно ли выполнить этот импорт данных быстрее за один шаг? Что я имею в виду, это


library(tidyverse)

text_frame <- read_lines(clipboard(), skip_empty_rows = TRUE) %>% 
  enframe(name = NULL, value = "line") 

text_frame %>% 
  separate(line, into = c("ID", "value"), extra = "merge", sep = ", ") 

, который производит

# A tibble: 7 x 2
  ID     value        
  <chr>  <chr>        
1 TAG1   t1_1         
2 DATA_A 5, 3, 4, 8   
3 DATA_A 3, 4, 5, 7   
4 TAG1   t1_2         
5 TAG2   t2_1         
6 DATA_B 1, 2, 3, 4, 5
7 DATA_A 1, 2, 3, 4  

Следующим шагом является создание новых столбцов «TAG1» и «TAG2» со значением, добавленным в строку. Вот где я застрял. Это как gather для отдельных строк. Как я мог это сделать? Обоснован ли общий подход? Есть предложения?

Быстрые и эффективные по памяти решения приветствуются, поскольку мне нужно иметь дело с сотнями ~ 10 МБ текстовых файлов (они имеют одинаковую структуру).

1 Ответ

1 голос
/ 30 мая 2019

Использование входных данных

text <- '
TAG1, t1_1

DATA_A, 5, 3, 4, 8
DATA_A, 3, 4, 5, 7

TAG1, t1_2
TAG2, t2_1

DATA_B, 1, 2, 3, 4, 5

DATA_A, 1, 2, 3, 4
'

Вы можете получить теги из второго столбца импортированных данных V2, выбрав элементы V2, где первый столбец V1 - TAG [1 | 2], и сделайте это для каждой группы.Группы идентифицируются переменной, начинающейся с 0 и увеличивающейся на 1 после каждого вхождения [V1 содержит TAG, тогда V1 не содержит TAG].

Затем с тегами в качестве собственных столбцов вы можете удалить строки TAG и разделить данные в соответствии с тем, содержит ли первый столбец 'B'

library(data.table)

df <- fread(text, fill = T, blank.lines.skip = T)

df[, `:=`(TAG1 = V2[V1 == 'TAG1'],
          TAG2 = V2[V1 == 'TAG2']),
   by = .(g = (rleid(grepl('TAG', V1)) - 1) %/% 2)]

df <- df[-grep('TAG', V1)] 

split(df, df[, grepl('B', V1)])

# $`FALSE`
#        V1 V2 V3 V4 V5 V6 TAG1 TAG2
# 1: DATA_A  5  3  4  8 NA t1_1 <NA>
# 2: DATA_A  3  4  5  7 NA t1_1 <NA>
# 3: DATA_A  1  2  3  4 NA t1_2 t2_1
# 
# $`TRUE`
#        V1 V2 V3 V4 V5 V6 TAG1 TAG2
# 1: DATA_B  1  2  3  4  5 t1_2 t2_1

Если вы не всегда 2теги и может иметь больше или меньше, вы можете заменить шаг после fread выше на

n_tags <- df[, as.numeric(gsub('[^0-9]', '', max(grep('TAG', V1, value = T))))]
df[, g := (rleid(grepl('TAG', V1)) - 1) %/% 2]
for(i in seq_len(n_tags))
  df[, paste0('TAG', i) := V2[V1 == paste0('TAG', i)], g]
...