2015-02-05 19 views
5

Ho ottenuto (e riceverò in futuro) molti file CSV che usano il punto e virgola come delimitatore e la virgola come separatore decimale. Finora non sono riuscito a scoprire come importare questi file in SAS utilizzando l'importazione di proc - o in qualsiasi altro modo automatizzato senza la necessità di fare confusione con i nomi delle variabili manualmente.Come importare un file CSV con delimitatore come ";" e separatore decimale come "," in SAS?

Crea alcuni dati di esempio:

%let filename = %sysfunc(pathname(work))\sap.csv; 

data _null_; 
    file "&filename"; 
    put 'a;b'; 
    put '12345,11;67890,66'; 
run; 

Il codice importazione:

proc import out = sap01 
datafile= "&filename" 
dbms = dlm; 
delimiter = ";"; 
GETNAMES = YES; 
run; 

Dopo l'importazione di un valore per la "quantità" variabile come 350,58 (che corrisponde a 350,58 nel Formato USA) sembrerebbe 35.058 (ovvero trentacinque e ...) in SAS (e dopo la riesportazione verso l'EXCEL tedesco sembrerebbe 35.058,00). Una soluzione semplice ma sporca sarebbe il seguente:

data sap02; set sap01; 
AMOUNT = AMOUNT/100; 
format AMOUNT best15.2; 
run; 

Mi chiedo se c'è un modo semplice per definire il separatore decimale per il CVS-import (simile alle specifiche del delimitatore). ..o qualsiasi altra soluzione "più pulita" rispetto alla mia soluzione alternativa. Molte grazie in anticipo!

+0

35.358,00, questo appare come una variabile stringa. È 35.058,00? –

+0

grazie, ho modificato il mio post! – Joz

risposta

5

Si dovrebbe tecnicamente utilizzare dbms=dlm non dbms=csv, anche se non capisce le cose. CSV significa "valori separati da virgola", mentre DLM significa "delimitato", che è corretto qui.

Non penso che ci sia un modo diretto per fare leggere SAS con la virgola tramite PROC IMPORT. È necessario comunicare a SAS di utilizzare l'informazione NUMXw.d durante la lettura dei dati e non vedo un modo per forzare tale impostazione in SAS. (C'è un'opzione per uscita con una virgola, NLDECSEPARATOR, ma non credo che funziona qui.)

La cosa migliore è o scrivere codice passaggio dei dati da soli, o per eseguire il PROC IMPORT, andare al registra e copia/incolla il codice letto nel tuo programma; quindi per ciascuno dei record letti aggiungere :NUMX10. o qualunque sia la larghezza massima appropriata del campo. Finirà per assomigliare a qualcosa del genere:

data want; 
    infile "whatever.txt" dlm=';' lrecl=32767 missover; 
    input 
    firstnumvar :NUMX10. 
    secondnumvar :NUMX10. 
    thirdnumvar :NUMX10. 
    fourthnumvar :NUMX10. 
    charvar :$15. 
    charvar2 :$15. 
    ; 
run; 

Genera anche un sacco di codice informatico e formato; in alternativa, è possibile convertire gli informats in NUMX10. anziché in BEST. anziché aggiungere l'informazione al read-in. Puoi anche rimuovere gli informats, a meno che tu non abbia campi data.

data want; 
    infile "whatever.txt" dlm=';' lrecl=32767 missover; 
    informat firstnumvar secondnumvar thirdnumvar fourthnumvar NUMX10.; 
    informat charvar $15.; 
    format firstnumvar secondnumvar thirdnumvar fourthnumvar BEST12.; 
    format charvar $15.; 
    input 
    firstnumvar 
    secondnumvar 
    thirdnumvar 
    fourthnumvar 
    charvar $ 
    ; 
run; 
+0

Grazie per il tuo aiuto, Joe! Ho appena modificato il mio post sull'opzione dbms. Le tue altre idee sono piuttosto interessanti ma ancora del tipo di soluzione. Difficile credere che la SAS non riesca a gestire un problema così banale. Ma temo che tu possa avere ragione ... – Joz

+0

SAS può gestirlo e Joe ti ha mostrato come. PROC IMPORT non è altro che un'utilità da leggere nei file di base - scrive un passo dati per leggere il file. Se il file non è conforme alla sua idea di "base", allora devi scrivere il passo dei dati. – DomPazz

+0

Modifica: Difficile credere che SAS non possa gestire un problema così banale in modo automatico. Ma attualmente sto lavorando con la soluzione di Joe, grazie ancora! – Joz

0

La cosa migliore è o scrivere codice passaggio dei dati da soli, o per eseguire l'IMPORT PROC, andare al registro, e copia/incolla il lettura in codice in vostro programma

Questo ha uno svantaggio. Se si verifica una modifica nella struttura del file csv, ad esempio un ordine di colonna modificato, è necessario modificare il codice nel programma SAS.
Quindi è più sicuro cambiare l'input, sostituendo nei campi numerici la virgola con punto e passando SAS l'input modificato.

La prima idea era quella di utilizzare un programma perl per questo, e quindi usare in SAS un nome file con una pipe per leggere l'input modificato.
Sfortunatamente c'è una restrizione SAS nell'importazione proc: la procedura di IMPORTAZIONE non supporta i tipi di dispositivo oi metodi di accesso per l'istruzione FILENAME tranne per DISK.
Quindi è necessario creare un file di lavoro su disco con l'input corretto.

Ho usato il pacchetto CVS_PP per leggere il file csv.
testdata.csv contiene i dati csv da leggere.
substitute_commasep.perl è il nome del programma perl

codice Perl:

# use lib "/........"; # specifiy, if Text::CSV_PP is locally installed. Otherwise error message: Can't locate Text/CSV_PP.pm in ....; 
use Text::CSV_PP; 
use strict; 
    my $csv = Text::CSV_PP->new({ binary => 1 
           ,sep_char => ';' 
          }) or die "Error creating CSV object: ".Text::CSV_PP->error_diag(); 
    open my $fhi, "<", "$ARGV[0]" or die "Error reading CSV file: $!"; 
    while (my $colref = $csv->getline($fhi)) { 
     foreach (@$colref) {    # analyze each column value 
     s/,/\./ if /^\s*[\d,]*\s*$/; # substitute, if the field contains only numbers and , 
     } 
     $csv->print(\*STDOUT, $colref); 
     print "\n"; 
    } 
    $csv->eof or $csv->error_diag(); 
    close $fhi; 

codice SAS:

filename readcsv pipe "perl substitute_commasep.perl testdata.csv"; 
filename dummy "dummy.csv"; 
data _null_; 
    infile readcsv; 
    file dummy; 
    input; 
    put _infile_; 
run; 
proc import datafile=dummy 
    out=data1 
    dbms=dlm 
    replace; 
    delimiter=';'; 
    getnames=yes; 
    guessingrows=32767; 
run; 
Problemi correlati