自动从文本文件导入数据

Automate importing data from a text file

我想将 Instituto Nacional de Estadística (INE) 的西班牙家庭调查用于研究项目。数据来自一个文本文件,其中调查的答案被困在一个连续的数字中,辅助文件告诉你从数字 1 到 5 它对应于变量,从 6 到 8 到变量 2,等等。这文件也是一个文本文件。

有没有办法在导入数据时使用这个辅助文件,而不是手动告诉 R、Stata 等如何分隔列?

辅助文件如下所示:

其中第一列是变量名,第二列是变量的位数,第三列是变量在数据文本文件中的位置,如下所示:

这确实是一个非常愚蠢的数据文件,但这让挑战变得更加有趣。这也许是一个解决方案。当您发布屏幕截图时,我无法在您的文件上对其进行测试,但我已尽力复制元数据文件和原始数据文件。

要在对文件进行测试之前复制我的代码,请先在计算机的某个位置创建一个文件夹。复制该文件夹的路径并将其粘贴到我代码第一行的 local folder "path/to/your/folder" 中。

然后将此块复制到一个 txt 文件中,并在该文件夹中另存为 meta_data.txt


********************* text *********************
********************* text *********************

@1    VAR1      .     /*   1     4  */
      VAR2      .     /*   5     9  */
      VAR3      .     /*  10    11  */
      VAR4      .     /*  12    13  */
      VAR5      .     /*  14    16  */

然后将此块复制到一个 txt 文件中,并在同一文件夹中另存为 raw_data.txt。我添加了一个空行和一个空单元格,混合 str/numric 等以确保我的代码可以处理最明显的违规行为。

A11122222334455
B11122222334455
C11122222  4455

D11122222334455
201200001-9AA12

那么你应该可以运行这个代码。注释应该解释每一行的作用。希望它可以在您的实际文件上运行而无需过多修改。如果您遇到无法解决的错误,请尽可能详细地解释您遇到的错误,并像我一样在代码块中提供您的文件示例,而不是图像。

    local folder "path/to/your/folder"
    local meta_data_file "`folder'/meta_data.txt"
    local raw_data_file  "`folder'/raw_data.txt"
    local csv_data_file  "`folder'/csv_data.csv"
 
    tempname meta_data raw_data csv_data
    
    *****************
    * Get column numbers from meta data
    
    file open `meta_data' using "`meta_data_file'", read 
    file read `meta_data' line
    local varnames ""
    local colnums ""
    
    *Loop over meta data file, line by line
    while r(eof)==0 {
            
        display `"`line'"'
        
        *Split the line where it has the first "/"
        gettoken varname_str colnum_str : line, parse("/")
        
        *Lines without "/" do not have col nums so skip them
        if "`colnum_str'" != "" {
            
            * Get the varname (first word that does not have "@" in it)
            tokenize "`varname_str'"
            if strpos("`1'","@") == 0 local varname = "`1'"
            else                      local varname = "`2'"
            local varnames "`varnames',`varname'"
            
            *Split string into each string seprated by space, f.ex. "/*","1","4","*/"
            tokenize "`colnum_str'"
            local colnums "`colnums' `2':`3'"
        }
        local linenum = `linenum' + 1
        file read `meta_data' line
    }   
    file close `meta_data'
    
    display "`varnames'"
    display "`colnums'"
    
    
    *****************
    * Convert silly file to csv file
    
    *Open silly data
    file open `raw_data' using "`raw_data_file'", read 
    file read `raw_data' old_row
    *Prepare csv file to read from
    file open `csv_data' using "`csv_data_file'", write text replace
    
    *Write varnames on first row
    file write `csv_data' "`varnames'" _n
    
    *Loop over silly data file, line by line
    while r(eof)==0 {
            
        local new_row ""
        
        *Loop over the colnums preared above
        foreach varcols of local colnums {
            
            *split each colnum pair on ":" and 
            tokenize "`varcols'", parse(":")
            local startcol = `1'
            local value_len = `3' - `1' + 1
            
            *Get the value from the row in the old dataset
            local value = substr("`old_row'",`startcol',`value_len')
            
            *Prepare the new row in csv format by inserting ","
            local new_row "`new_row',`value'"
        }
        
        *Write the new row in csv format tot he file
        display "old row: `old_row'"
        display "new row: `new_row'"
        display ""
        file write `csv_data' "`new_row'" _n
        
        *Read next line in the old data
        local linenum = `linenum' + 1
        file read `raw_data' old_row
    }   
    
    *Close both files
    file close `raw_data'
    file close `csv_data'
    
    *Import the csv file
    import delimited "`csv_data_file'", clear
    drop v1