2015-06-10 4 views
7

Wenn ich ein Dataset unter Verwendung von PROC EXPORT in das Stata-Format exportiere, fügt SAS 9.4 automatisch ein zusätzliches (leeres) Byte zu jeder Beobachtung jeder String-Variablen hinzu. Zum Beispiel in diesem Datensatz:Wie kann ich verhindern, dass SAS zu jeder String-Variablen ein zusätzliches leeres Byte hinzufügt, wenn ich PROC EXPORT verwende?

data test1; 
    input cust_id $ 1 
      month  3-8 
      category $ 10-12 
      status $ 14-14 
; 
datalines; 
A 200003 ABC C 
A 200004 DEF C 
A 200006 XYZ 3 
B 199910 ASD X 
B 199912 ASD C 
; 
quit; 

proc export data = test1 
    file = "test1.dta" 
    dbms = stata replace; 
quit; 

die Variablen cust_id, category und status sollen str1, str3 und str1 in der endgültigen Stata-Datei sein, und somit nehmen 1 Byte, 3 Byte und 1 Byte für jede Beobachtung. Jedoch fügt SAS jeder Beobachtung automatisch ein zusätzliches leeres Byte hinzu, das ihre Datentypen in den ausgegebenen STATA-Dateien auf den Datentyp str2, str4 und str2 erweitert.

Dies ist äußerst problematisch, denn das ist ein zusätzliches Byte hinzugefügt jede Beobachtung von jedes String-Variable. Bei großen Datensätzen (ich habe einige mit ~ 530 Millionen Beobachtungen und zahlreichen String-Variablen) kann dies der exportierten Datei mehrere Gigabyte hinzufügen.

Sobald die Datei in Stata, der compress Befehl in Stata können diese leeren Bytes automatisch geladen wird entfernt und die Datei schrumpfen, aber für große Datensätze, PROC EXPORT fügt so viele zusätzliche Bytes in die Datei, die ich nicht immer haben genug Speicher, um das Dataset an erster Stelle in Stata zu laden.

Gibt es eine Möglichkeit, zu verhindern, dass SAS die String-Variablen an erster Stelle auffüllt? Wenn ich eine Datei mit einer Variablen mit einer Zeichenkette (zum Beispiel) exportiere, möchte ich, dass diese Variable als eine Zeichenkettenvariable in der Ausgabedatei gespeichert wird.

+0

Ich vermute, SAS fügt einen String-Terminator hinzu, obwohl ich keine Ahnung habe. – Joe

+1

Betrachtet man die Stata-Dokumentation, unterstützt sie '\ 0' String-Terminator (für" Varchar "-Typ Operation). Ich vermute, SAS legt das nach * jeder * Zeichenfolge einfach, wenn ich raten müsste.Ich würde empfehlen, ein Support-Ticket mit SAS-Tech-Support zu setzen; Sie können dies wahrscheinlich a) bestätigen und b) Sie wissen lassen, ob es einen Workaround gibt. Ich sehe keinen, der auf einem kurzen Blick basiert. – Joe

+1

Und wenn Sie vom technischen Support von SAS zurückkommen - fügen Sie bitte eine Antwort mit allen Informationen hinzu, die Sie erhalten, also ist es für andere Suchende verfügbar! – Joe

Antwort

0

Wenn Sie bereit sind, eine Flat-File-Antwort zu akzeptieren, habe ich mit einem recht einfachen Weg gefunden, um eine zu erzeugen, dass ich denke, die Eigenschaften hat Sie benötigen:

data test1; 
    input cust_id $ 1 
      month  3-8 
      category $ 10-12 
      status $ 14-14 
; 
datalines; 
A 200003 ABC C 
A 200004 DEF C 
A 200006 XYZ 3 
B 199910 SD X 
B 199912 D C 
; 
run; 

data _null_; 
file "/folders/myfolders/test.txt"; 
set test1; 
put @; 
_FILE_ = cat(of _all_); 
put; 
run; 

/* Print contents of the file to the log (for debugging only)*/ 
data _null_; 
infile "/folders/myfolders/test.txt"; 
input; 
put _infile_; 
run; 

Dies sollte funktionieren, wie sie ist Wenn die Gesamtlänge aller Variablen in Ihrem Dataset kleiner als 32767 ist (das Limit der cat-Funktion in der Datenschrittumgebung), gilt die untere Grenze von 200 Zeichen nicht, da Sie nur cat verwenden, um ein Objekt zu erstellen Variable, der keine Länge zugewiesen wurde). Darüber hinaus kann es zu Problemen beim Abschneiden kommen. Ein Workaround, wenn das passiert, ist nur cat zusammen eine begrenzte Anzahl von Variablen zu einer Zeit - ein manueller Prozess, aber viel weniger mühsam als das Schreiben Put Anweisungen basierend auf der Länge aller Variablen, und je nach Ihren Daten kann es nie wirklich ausdenken.

Alternativ können Sie einen komplexere Makro Weg gehen, immer variable Längen entweder von der vlength Funktion oder dictionary.columns und diejenigen, sowie die Variablennamen mit dem erforderlichen put statement (s) zu konstruieren.

+0

Ich mag Ihre Idee von CAT, um die Zeile zu formatieren, aber es funktioniert nicht für numerische Variablen. Sie können nicht auf die Umwandlung von Zahlen in Zeichen zählen, um Werte mit derselben Breite zu erzeugen. Was diese Arbeit (ich denke) machen würde, ist eine CAT-Funktionsversion, die alle Variablen mit der VVALUE-Funktion formatiert. –

+0

@data_null_ - leider existiert keine solche hypothetische 'catv'-Funktion, und' vvalue' und ähnliche Funktionen können nicht innerhalb einer 'proc fcmp'-Definition verwendet werden, da sie nur innerhalb eines Datenschrittes gültig sind. Einige Arrays und Makro-Logik wären erforderlich, um numerische vars in Text mit fester Breite zu konvertieren. – user667489

1

So können Sie bestehende Funktionen verwenden.

filename FT41F001 temp; 
data _null_; 
    file FT41F001; 
    set test1; 
    put 256*' ' @; 
    __s=1; 
    do while(1); 
     length __name $32.; 
     call vnext(__name); 
     if missing(__name) or __name eq: '__' then leave; 
     substr(_FILE_,__s) = vvaluex(__name); 
     putlog _all_; 
     __s = sum(__s,vformatwx(__name)); 
     end; 
    _file_ = trim(_file_); 
    put; 
    format month f6.; 
    run; 

Um die Verwendung von _FILE_ zu vermeiden;

data _null_; 
    file FT41F001; 
    set test1; 
    __s=1; 
    do while(1); 
     length __name $32. __value $128 __w 8; 
     call vnext(__name); 
     if missing(__name) or __name eq: '__' then leave; 
     __value = vvaluex(__name); 
     __w = vformatwx(__name); 
     put __value $varying128. __w @; 
     end; 
    put; 
    format month f6.; 
    run; 
+0

'call vnext' und' vformatwx' sind die Puzzleteile, die ich vermisste - es ist viel schwieriger, ohne sie alles ordentlich zusammenzusetzen. Es wäre jedoch immer noch besser, '_file_' zu vermeiden, da dies jede Ausgabezeile auf 32767 Zeichen begrenzt. – user667489

+0

Ich würde auch vorschlagen, 'substr' anstelle von' trim' für den letzten Aufräumschritt zu verwenden, da dies verhindert, dass gültige gültige Leerzeichen aus der letzten Variablen im Quelldatensatz entfernt werden. – user667489

+0

Sieht jetzt sehr gut aus - die einzige Optimierung, die ich vornehmen würde, wäre 'lrecl = 1000000' oder ähnlich, um zu vermeiden, dass lange Zeilen auf die Standardlänge gekürzt werden. – user667489