读取带有单独标签的矩形数据块作为新列

时间:2019-05-30 16:57:22

标签: r parsing data.table tidyverse

我觉得我的情况是实验中的典型用例,其中数据记录为文本文件,供人类理解,而不是机器消耗。标签会散布在实际数据中,以描述随后的数据。对于数据分析,标记需要与数据行集成在一起才有用。下面是一个虚构的示例。

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。我该怎么办?通用方法是否合理?有什么建议吗?

欢迎快速/内存高效的解决方案,因为我需要处理数百个〜10MB的文本文件(它们具有相同的结构)。

1 个答案:

答案 0 :(得分:0)

使用输入数据

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是TAG [1 | 2])从导入数据V1的第二列中获取标签,然后执行每个组。组由变量标识,从0开始,每次出现[V1包含TAG,然后V1不包含TAG]后,递增1。

然后将标记作为自己的列,您可以删除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]