自动从文本文件导入数据
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
我想将 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