加载 seer 数据到 R

loading seer data into R

我正在尝试从 ASCII 文件加载 SEER 数据。只有一个 .sas 加载文件,我试图将其转换为 R 加载命令。

.sas 加载文件如下所示:

filename seer9 './yr1973_2015.seer9/*.TXT';                                           

data in;                                                                              
infile seer9 lrecl=362;                                                             
input                                                                               
@ 1   PUBCSNUM             $char8.  /* Patient ID */                              
@ 9   REG                  $char10. /* SEER registry */                           
@ 19  MAR_STAT             $char1.  /* Marital status at diagnosis */             
@ 20  RACE1V               $char2.  /* Race/ethnicity */                          
@ 23  NHIADE               $char1.  /* NHIA Derived Hisp Origin */                
@ 24  SEX                  $char1.  /* Sex */    

我有以下代码来尝试复制类似的加载过程:

data <- read.table("OTHER.TXT", 
col.names = c("pubcsnum", "reg", "mar_stat", "race1v", "nhaide", "sex"),
sep = c(1, 9, 19, 20, 23, 24))

如果我使用 sep 参数,我会收到以下错误:

Error in read.table("OTHER.TXT", col.names = c("pubcsnum", "reg", "mar_stat",
:invalid 'sep' argument

如果我不使用 sep 参数,我会收到以下错误:

Error in scan(file = file, what = what, sep = sep, quote = quote, dec = dec,
: 
  line 1 did not have 133 elements

有没有人有加载 seer 数据的经验?有没有人建议为什么这不起作用?

*值得注意的是,当我使用 fill = TRUE 参数时,第二个错误 line 1 did not have 133 elements 不再发生,但是当我评估前几个观察结果时数据不正确。我通过评估一个已知变量进一步确认 sex :

> summary(data$sex)
     Min.   1st Qu.    Median      Mean   3rd Qu.      Max. 
0.000e+00 2.000e+00 3.020e+03 7.852e+18 9.884e+13 2.055e+20 

其中值为 1/2,摘要毫无意义

固定宽度的文件,如 .sas 文件所描述的文件,使用 foreign 包中的 read.fwf 函数读取。恐怕普林斯顿主办的格式很好的网页在如何使用 read.table 方面完全错误。实际上没有分隔符,只有位置。在这种情况下,您可以使用(假设您的工作目录中有一个名为 "yr1973_2015.seer9" 的目录):

 library(utils)  #not really needed, just correcting my faulty memory 
 inputdf <- read.fwf( "yr1973_2015.seer9/OTHER.TXT",
                       widths= c(1, 9, 19, 20, 23, 24),
          col.names = c("pubcsnum", "reg", "mar_stat", "race1v", "nhaide", "sex"))

你会丢失大部分信息,因为 lrecl 值告诉我们每行有 362 个字符,但这将是一个很好的测试用例,然后你可以切换到 SAScii 函数....感谢@AnthonyDamico:

packageDescription("SAScii")
#---------------
Package: SAScii
Type: Package
Title: Import ASCII files directly into R using only a SAS
      input script
Version: 1.0
Date: 2012-08-18
Authors@R: person( "Anthony Joseph" , "Damico" , role = c(
      "aut" , "cre" ) , email = "ajdamico@gmail.com" )
Description: Using any importation code designed for SAS
      users to read ASCII files into sas7bdat files, the
      SAScii package parses through the INPUT block of a
      (.sas) syntax file to design the parameters needed
      for a read.fwf function call.  This allows the user
      to specify the location of the ASCII (often a .dat)
      file and the location of the .sas syntax file, and
      then load the data frame directly into R in just one
      step.
License: GPL (>= 2)
URL: https://github.com/ajdamico/SAScii
Depends: R (>= 2.14)
LazyLoad: Yes
Packaged: 2012-08-17 08:35:18 UTC; AnthonyD
Author: Anthony Joseph Damico [aut, cre]
Maintainer: Anthony Joseph Damico <ajdamico@gmail.com>
Repository: CRAN
Date/Publication: 2012-08-17 10:55:15
Built: R 3.4.0; ; 2017-04-20 18:55:31 UTC; unix

-- File: /Library/Frameworks/R.framework/Versions/3.4/Resources/library/SAScii/Meta/package.rds 

我不确定那些长行中的尾随信息是否会被有效地忽略,但通过 ?read.fwf 页面上第一个示例的这个轻微 mod 进行了检查:

> ff <- tempfile()
> cat(file = ff, "12345689", "98765489", sep = "\n")
> read.fwf(ff, widths = c(1,2,3))
  V1 V2  V3
1  1 23 456
2  9 87 654
>unlink(ff)

我检查了我的记忆,使用 Anthony 的名字作为搜索词可能会有帮助,并且发现他的网站已经更新。查看:

http://asdfree.com/surveillance-epidemiology-and-end-results-seer.html

所以其他评论和答案指出了大部分内容,但这里有一个更完整的答案来解决您的确切问题。我听说很多人都在为这些 ASCII 文件(包括许多相关但不是很简单的包)而苦苦挣扎,我想为其他搜索的人回答这些问题。

固定宽度文件

这些 SEER "ASCII" 文件实际上是固定宽度的文本文件(ASCII 是编码标准而不是文件格式)。这意味着没有分隔字段(在 .csv 或 .tsv 中)的分隔符(例如“,”或“\t”)。

相反,每个字段由行中的开始和结束位置定义(有时是开始位置和字段 width/length)。这是我们看到的.sas文件中你总结的:

input                                                                               
@ 1   PUBCSNUM             $char8.  /* Patient ID */                              
@ 9   REG                  $char10. /* SEER registry */  
...

这是什么意思?

  • 第一个患者 ID 字段从位置 1 开始,长度为 8(来自 $char8,类似于 SQL 模式等),这意味着它在位置 8 处结束。
  • 第二个字段,SEER 注册表 ID,从位置 9(前一个字段的 1 + 8)开始,长度为 10(同样来自$char10)这意味着它在位置18.
  • 处结束

其中 @ 数字持续增加,因此字段不会重叠。

读取固定宽度的文件

我发现 readr::read_fwf() 函数既好又简单,主要是因为它有几个辅助函数,即 fwf_positions() 告诉它如何通过开始和结束(或宽度, fwf_widths())。

因此,要从文件中读取这两个字段,我们可以这样做:

read_fwf(<file>, fwf_positions(start=c(1, 9), end=c(8, 18), col_names=c("patient_id", "registry_id")))

其中 col_names 仅用于重命名列。

帮助脚本。

我之前一直在努力解决这些问题,所以我实际上写了 some code 来读取该 .sas 文件并提取起始位置、宽度、列名和描述。

这是全部内容,只需替换文件名:

## Script to read the SEER file dictionary and use it to read SEER ASCII data files.

library(tidyverse)
library(stringr)

#### Reading the file dictionary ----
## https://seer.cancer.gov/manuals/read.seer.research.nov2017.sas

sas.raw <- read_lines("https://seer.cancer.gov/manuals/read.seer.research.nov2017.sas")
sas.df <- tibble(raw = sas.raw) %>% 
  ## remove first few rows by insisting an @ that defines the start index of that field
  filter(str_detect(raw, "@")) %>% 
  ## extract out the start, width and column name+description fields
  mutate(start = str_replace(str_extract(raw, "@ [[:digit:]]{1,3}"), "@ ", ""),
         width = str_replace(str_extract(raw, "\$char[[:digit:]]{1,2}"), "\$char", ""),
         col_name = str_extract(raw, "[[:upper:]]+[[:upper:][:digit:][:punct:]]+"),
         col_desc = str_trim(str_replace(str_replace(str_extract(raw, "\/\*.+\*\/"), "\/\*", ""), "\*\/", "" )) ) %>% 
  ## coerce to integers
  mutate_at(vars(start, width), funs(as.integer)) %>% 
  ## calculate the end position
  mutate(end = start + width - 1)

column_mapping <- sas.df %>% 
  select(col_name, col_desc)

#### read the file with the start+end positions----

## CHANGE THIS LINE
file_path = "data/test_COLRECT.txt"

## read the file with the fixed width positions
data.df <- read_fwf(file_path, 
                    fwf_positions(sas.df$start, sas.df$end, sas.df$col_name))
## result is a tibble

希望对您有所帮助!