2017-11-22 11 views
1

下記のattributes.txtファイル(Sawtooth調査調査からの出力)を解析して、出力結果が下図のようになるようにします。あなたは私の試みを以下で見ることができます。できます。しかし、それは非常に醜いです。より良い方法が必要でしょう、そうですか?パースからR構造のテキストファイルの解析R

================================================================================ 
ATTRIBUTES AND LEVELS 
================================================================================ 

======================================== 
Display Text 
======================================== 

<Same structure as shown below. But I do not want to extract any of this text> 

======================================== 
Internal Labels 
======================================== 

[Attribute List]: 

1 brand 
2 rating 
3 price 

--------------------------- 
Attribute 1: 
    brand 

Levels: 
1 brand01 
2 brand02 
3 brand03 
4 otherbrand 

--------------------------- 
Attribute 2: 
    rating 

Levels: 
1 1 
2 2 
3 3 
4 4 
5 5 

--------------------------- 
Attribute 3: 
    price 

Levels: 
1 99 
2 199 
3 299 

所望の出力:

attribute,level,label 
1,1,brand01 
1,2,brand02 
1,3,brand03 
1,4,otherbrand 
2,1,1 
2,2,2 
2,3,3 
2,4,4 
2,5,5 
3,1,99 
3,2,199 
3,3,299 

私の試み:

attributes.txtを(彼らが利用できるなら、私はtidyverseソリューションを好みます)

library(stringr) parse_attributes_file <- function(ATTRIBUTES_FILE_PATH) { con = file(ATTRIBUTES_FILE_PATH, "r") reached_internal_labels <- FALSE attribute_num <- NA datalist <- list() idx <- 0 while (TRUE) { line = readLines(con, n = 1) if (length(line) == 0) { break } if (!reached_internal_labels) { reached_internal_labels <- str_detect(line, "Internal Labels") } else { attribute_num_extract <- str_match(line, "Attribute ([[:digit:]]+): ")[,2] if(!is.na(attribute_num_extract)) { attribute_num <- attribute_num_extract } else { if (!is.na(attribute_num)) { my_match <- str_match(line, "([[:digit:]]+)\t(.*)") if(!is.na(my_match[,1])) { idx <- idx + 1 datalist[[idx]] <- c(attribute_num, my_match[,2], my_match[,3]) } } } } } close(con) attributes = do.call(rbind, datalist) colnames(attributes) <- c("attribute", "level", "label") return(attributes) } 

答えて

1

tidyverse関数を使用して同じことを行うコードが少し少なくなりました。まず、サンプルデータを読み込みます。

# you'd do something like 
# text <- readLines("yourtextfile") 
# but for this sample... 
text <- strsplit("================================================================================\nATTRIBUTES AND LEVELS\n================================================================================\n\n========================================\nDisplay Text\n========================================\n\n<Same structure as shown below. But I do not want to extract any of this text>\n\n========================================\nInternal Labels\n========================================\n\n[Attribute List]:\n\n1 brand\n2 rating\n3 price\n\n---------------------------\nAttribute 1: \nbrand\n\nLevels: \n1 brand01\n2 brand02\n3 brand03\n4 otherbrand\n\n---------------------------\nAttribute 2: \nrating\n\nLevels: \n1 1\n2 2\n3 3\n4 4\n5 5\n\n---------------------------\nAttribute 3: \nprice\n\nLevels: \n1 99\n2 199\n3 299", "\n")[[1]] 

ファイルを解析します。 「レベル:」と今、私たちはただの属性を組み合わせて、空白行

markers <- case_when(str_detect(lines, "^Levels:")~2, 
      str_detect(lines, "^$")~1, 
      TRUE~0) 
levels <- markers %>% accumulate(function(a,b) case_when(b==2~TRUE, b==1~FALSE, TRUE~a), .init=FALSE) %>% head(-1) %>% 
    modify_if(markers==3, function(x) FALSE) %>% unlist 

で停止まず、との行を探して、各ラインすると

library(tidyverse) 
attributes <- str_match(lines, "Attribute (\\d)")[, 2] %>% 
    accumulate(function(a, b) coalesce(b,a)) 

「レベル」のブロックを見つけるために右の属性を見つけます

を返し、レベルデータテーブルにだけ readr

tibble

read_table(paste(attributes[levels], lines[levels], collapse="\n"), 
      col_names=c("attribute", "level", "label")) 
にそれを解析
# A tibble: 12 x 3 
    attribute level  label 
     <int> <int>  <chr> 
1   1  1 brand01 
2   1  2 brand02 
3   1  3 brand03 
4   1  4 otherbrand 
5   2  1   1 
6   2  2   2 
7   2  3   3 
8   2  4   4 
9   2  5   5 
10   3  1   99 
11   3  2  199 
12   3  3  299 
+0

ちょっとファンキー。私を一生懸命にしなかった。しかし、これは私が見た中で最高です。それで、それを答えとしてマークしてください。 – lowndrul

関連する問題