Investigación reproducible: convierta archivos de datos sas7bdat a archivos csv invocando a statTransfer usando GNU make

PREGUNTA:

Soy muy nuevo en GNU Make. ¿Hay una mejor manera de convertir programáticamente conjuntos de datos estadísticos de sas7bdat a archivos csv y mantenerlos sincronizados entre sí utilizando GNU Make para promover la investigación reproducible? ¿Te acercarías a este problema de forma diferente desde una perspectiva de codificación o existe una forma mejor de promover la investigación reproducible? ¿Puedo agregar un requisito previo adicional (es decir, statTransferOptions.txt ) al usar reglas de patrones estáticos?

La solución necesita:

  • Find all sas7bdat files in all subdirectories
  • Read statTransfer options
  • Convert the sas7bdat file to csv file using statTransfer command line tool with options
  • Given the current limitations of statTransfer, I think this will require a two step process:
    • Build statTransfer command file (.stcmd) for each SAS data file (.sas7bdat)
    • Build csv file for each stcmd file by executing statTransfer (st) using options in stcmd file
    • target stcmd and csv files should reside in same subdirectory as pre-requisite sas7bdat file
    • Find out-of-date stcmd and csv files and update them if a new sas7bdat file exists or if base option file changes

CONTEXTO:

Heredé un gran informe estadístico que se publica anualmente. En años anteriores, el análisis se realizó en SAS. Ahora estamos usando R. Algunos de los archivos sas7bdat generados por SAS Enterprise Guide no se importan correctamente con el paquete sas7bdat . StatTransfer, un producto comercial, tiene una interfaz de línea de comandos y convierte archivos sas7bdat a archivos csv correctamente; Sin embargo, hay opciones que mejoran la conversión (por ejemplo, la escritura de formatos de fecha). Los archivos sas7bdat se encuentran en múltiples subdirectorios correspondientes al tipo de conjunto de datos y el año.

Este enfoque fue impulsado por:

Gandrud, Christopher (2013-06-21). Reproducible Research with R and RStudio (Chapman & Hall/CRC The R Series) (pp. 104-105). Chapman and Hall/CRC. Kindle Edition.

SOLUCIÓN DE PROBLEMAS:

SUGERIDO MAKEFILE?

RDIR := .

######
#PREP#
######
# Use BASH shell to create list of source sas7bdat files
SASDATA = $(shell find $(RDIR) -type f -name '*.sas7bdat')

# Use pattern substring functions to define variable list of filenames
# to be used as targets in recipes
STCMD_OUT = $(patsubst $(RDIR)/%.sas7bdat, $(RDIR)/%.stcmd, $(SASDATA))
CSV_OUT = $(patsubst $(RDIR)/%.sas7bdat, $(RDIR)/%.csv, $(SASDATA))

#########
#TARGETS#
#########

all: $(STCMD_OUT) $(CSV_OUT)

# I think the name "static pattern rules" is misleading
# but I found this to be helpful:
# http://www.gnu.org/software/make/manual/make.html#Static-Pattern

# can I add statTransferOptions.txt as a pre-requisite while using static pattern rules?

$(STCMD_OUT): $(RDIR)/$(@D)/%.stcmd: $(RDIR)/$(@D)/%.sas7bdat
    cp $(RDIR)/statTransferOptions.txt [email protected]
    echo copy $(RDIR)/$< delim $(RDIR)/$(basename $<).csv -v >> [email protected]
    echo quit >> [email protected]

$(CSV_OUT): $(RDIR)/$(@D)/%.csv: $(RDIR)/$(@D)/%.stcmd
    st $(RDIR)/$<

clean:
    rm $(STCMD_OUT)
    rm $(CSV_OUT)

MAKEFILE REVISADO DESPUÉS DE LA ENTRADA DE TANTO:

RDIR := .

######
#PREP#
######
# Create list of source sas7bdat files
SASDATA := $(shell find $(RDIR) -type f -name '*.sas7bdat')

STCMD_OUT := $(patsubst $(RDIR)/%.sas7bdat, $(RDIR)/%.stcmd, $(SASDATA))
CSV_OUT := $(patsubst $(RDIR)/%.sas7bdat, $(RDIR)/%.csv, $(SASDATA))

#########
#TARGETS#
#########

all: $(STCMD_OUT) $(CSV_OUT)

$(STCMD_OUT): %.stcmd: %.sas7bdat statTransferOptions.txt
    cp $(RDIR)/statTransferOptions.txt [email protected]
    echo copy $(RDIR)/$< delim $(RDIR)/$(basename $<).csv -v -y >> [email protected]
    echo quit >> [email protected]

$(CSV_OUT): %.csv: %.stcmd
    st $(RDIR)/$<

clean:
    rm $(STCMD_OUT)
    rm $(CSV_OUT)

Sin embargo, la opción correcta podría ser depurar el paquete sas7bdat de CRAN para que toda la cadena de herramientas esté disponible en lugar de invocar statTransfer patentado.

0
Lamentablemente no. El paquete funciona con otros archivos sas7bdat y los archivos con errores son grandes (> 100 MB) y tienen información patentada que no se puede compartir.
agregado el autor penguinv22, fuente
@Thomas, estoy de acuerdo. Cuando finalice el informe en el que estoy trabajando, tendré que volver a consultar el tema de por qué falló la conversión con el paquete sas7bdat (cancelado después de ejecutarse durante horas en un i7 con 16 GB de RAM). Parecía un proceso desalentador destilarlo a un ejemplo reproducible mínimo que podía compartir con el mantenedor del paquete.
agregado el autor penguinv22, fuente
¿Ha informado sobre el error de importación al responsable de mantenimiento de sas7bdat con un archivo sas de ejemplo?
agregado el autor Spacedman, fuente
Si se reduce a la estructura de los datos (en lugar de su tamaño), entonces podría ser fácil crear un archivo pequeño que falle de la misma manera. Pero no importa.
agregado el autor Spacedman, fuente
No creo que incorporar StatTransfer en el flujo de trabajo requerido para la reproducción sea una buena idea. Es propietario y, por lo tanto, conlleva todas las desventajas asociadas con eso. Es mejor hacer la conversión, guardar la secuencia de comandos necesaria para hacer esa conversión y luego distribuir ese código junto con el conjunto de datos guardado en un mejor formato. La reproducibilidad significa que cualquiera puede reproducir el análisis, por lo que requiere límites de StatTransfer para poder reproducirlo.
agregado el autor Thomas, fuente

1 Respuestas

En SO, generalmente no tenemos el tiempo o la energía (o, a menudo, el interés) para ir a leer documentos relacionados, opciones, alternativas, etc. Funciona mejor si simplemente y especifica claramente el código con el que tienes problemas (en este caso, el archivo MAKE que se proporciona así que es genial), el problema exacto que tiene incluye mensajes de error o resultados incorrectos (esto no es obvio por su pregunta), lo que quería que sucediera que no sucedió, porque esto no siempre es claro, y tal vez cualquier pensamiento o dirección adicional que hayas probado y no haya funcionado.

No estoy seguro de cuál es exactamente el problema que está teniendo, pero veo una serie de problemas con su archivo MAKE. Primero, esto funcionará pero es altamente ineficiente:

SASDATA = $(shell find $(RDIR) -type f -name '*.sas7bdat')

Debería usar la forma de asignación : = aquí. Probablemente deberías usarlo cuando estableces STCMD_OUT y CSV_OUT también, aunque esto es menos crítico.

Lo más importante, sin embargo, estas reglas no son correctas:

$(STCMD_OUT): $(RDIR)/$(@D)/%.stcmd: $(RDIR)/$(@D)/%.sas7bdat

No puede usar variables automáticas como $ @ (o cualquiera de sus formas alternativas) en las listas de requisitos previos o de destino. Las variables automáticas solo se definen dentro de la receta de la regla. Puede usar expansión secundaria para esto, pero no estoy seguro de por qué está tratando de hacer esto. ¿Por qué no solo usar:

$(STCMD_OUT): %.stcmd: %.sas7bdat

? Lo mismo para la otra regla de patrón estático?

En cuanto a su pregunta, sí, está perfectamente bien agregar prerrequisitos adicionales como statTransferOptions.txt a la regla de patrón estático.

0
agregado
He estado luchando con este Makefile durante la mayor parte de dos días y quería compartir mi exploración y obtener comentarios. De una versión anterior, pensé que me enseñé a mí mismo que $ (STCMD_OUT):% .stcmd:% .sas7bdat no encontraría la dependencia o volcaría el destino en el directorio base en lugar de en el mismo directorio como el archivo sas7bdat; sin embargo, probé tu solución y funciona. Gracias.
agregado el autor penguinv22, fuente
Según el comentario de @MadScientist, lo siguiente parece funcionar y ejecutará la receta si el archivo de opciones base se actualiza: $ (STCMD_OUT):% .stcmd:% .sas7bdat statTransferOptions.txt
agregado el autor penguinv22, fuente