【问题标题】:Python output fixed width format text file with special lines as SAS doPython 输出固定宽度格式的文本文件,其中包含 SAS 的特殊行
【发布时间】:2021-09-13 23:09:26
【问题描述】:

我的样本数据如下:

# df
VAR1   SEQ    VAR2    VAR3       DATE    VAR4     VAR5    VAR6    VAR7
AAA      1     YYY      01   20000630      AL    11111    ABCD      PA
BBB      1     YYY      01   20100701      GA    12345    EDED      NY
BBB      2     YYY      01   20150815      GA    12345              NY
BBB      3     YYY      01   19950105      GA    12345    YTRU      NY
BBB      4     YYY      01   20000701      GA    12345    IIII      NY
BBB      5     YYY      01   20210701      GA    12345              NY
CCC      1     NNN      01   20210630      CA    33333    SSSS      NJ
CCC      2     NNN      01   20210629      CA    33333              NJ

SAS中,我们可以导出固定宽度的格式文件如下:

BLANK_VAR1 = " "

%MACRO FRIST;
    PUT @  1  "00FIRST"
        @  8  VAR1       $CHAR5.
        @ 13  BLANK_VAR1 $CHAR2.
        @ 15  VAR2       $CHAR3.
    ;
%MEND FRIST;

%MACRO SECOND;
    PUT @  1  "00SECOND"
        @  9  VAR3       $CHAR2.
        @ 11  BLANK_VAR1 $CHAR2.
        @ 13  VAR4       $CHAR2.
        @ 15  VAR5       $CHAR5.
    ;
%MEND SECOND;

%MACRO THIRD(sequence);
    num = &sequence.;
    PUT @  1  num        Z2.0
        @  3  "THIRD"    $CHAR5.
        @  8  DATE       $CHAR8.
    ;
%MEND THIRD;

%MACRO FOURTH(sequence);
    num = &sequence.;
    PUT @  1  num        Z2.0
        @  3  "FOURTH"   $CHAR5.
        @  9  VAR6       $CHAR25.
        @ 34  BLANK_VAR1 $CHAR2.
        @ 36  VAR7       $CHAR2.
    ;
%MEND FOURTH;

filename outtmp "/home/folder/outfile_tmp";  

DATA _NULL_;                                                                    
   SET df;    
 
   BY VAR1 SEQ;                                                           
   FILE outtmp;  
                                                                
   IF FIRST.VAR1 THEN DO;
      %FRIST;
      %SECOND;
      REC_CNT = 0;                                                             
   END;                                                                       
   REC_CNT + 1;
   IF REC_CNT LE 3 THEN DO;
      %THIRD(REC_CNT);
      IF VAR6 NE ' ' THEN DO;
         %FOURTH(COUNTN);
      END;
   END;                                                         
RUN;


filename output "/home/folder/output"; 


%MACRO INREC;                                                                     
   PUT 001 RECIN $CHAR150.;
%MEND INREC;


%MACRO FILE_FIRST;
    DATE = TODAY();
    PUT @  1  "###FIRSTLINE###"
        @ 16  DATE       JULIAN5.
        @ 21  BLANK_VAR1 $CHAR2.
        @ 23  "###FIRSTLINEEND###"
    ;
%MEND FILE_FIRST;


%MACRO FILE_LAST;
    DATE = TODAY();
    PUT @  1  "###LASTLINE###"
        @ 15  DATE       JULIAN5.
        @ 20  BLANK_VAR1 $CHAR2.
        @ 22  "###LASTLINEEND###"
    ;
%MEND FILE_LAST;


DATA output;                                                                  
   INFILE outtmp truncover;                                                               
   INPUT                                                                       
      @ 001 RECIN $CHAR150.;                                                                         
RUN; 

DATA _NULL_;
   SET output  end=last;  
   file output  lrecl=256 ;
   IF _N_ = 1 THEN DO;
      %FILE_FIRST;
   END;

   %INREC;  
                                                                  
   IF last THEN DO;
      %FILE_LAST; 
   END;
RUN; 

这是输出:

###FIRSTLINE###21182  ###LASTLINEEND###
00FIRSTAAA  YYY
00SECOND01  AL11111
01THIRD20000630
01FOURTHABCD                       PA
00FIRSTBBB  YYY
00SECOND01  GA12345
01THIRD20100701
01FOURTHEDED                       NY
02THIRD20150815
03THIRD19950105
03FOURTHYTRU                       NY
00FIRSTCCC  NNN
00SECOND01  CA33333
01THIRD20210630
01FOURTHSSSS                       NJ
###LASTLINE###21182  ###LASTLINEEND###

上述程序的逻辑是:

  1. 需要输出四个部分。
  2. 如果有多个相同的VAR1,则只输出FIRSTSECOND一次。
  3. SEQ 的输出THIRD 部分小于3。如果SEQ 大于3,则不输出。忽略。
  4. 在第三个逻辑之后输出FOURTH 部分,并且如果VAR6 没有丢失。
  5. 注意:在THIRDFOURTH 部分中,前两个字符串应从01 更改为03,具体取决于记录。

如何在Python 中复制这种格式?
我发现np.savetxt()fmt 参数可能是link 的一种方式;但是,该文件应与原始数据帧的顺序相同。

pandas 具有read_fwf() 读取固定宽度格式文件的功能;但是,没有要导出的 to_fwf() 函数。

我已经卡了好几天了,所以任何想法都应该有帮助!

【问题讨论】:

  • 我想你只要把整行变成一个字符串,然后写那个?
  • @Joe 第一行和最后一行可以通过这个来完成,但如果你有一个大数据集,中间部分就很难做到。
  • 明确地说,您只是希望您的数据以固定宽度或其他方式导出?我无法从您发布的输出中看出?
  • @PeterChen 我的意思是,这在 SAS 中也很困难,但是......这基本上就是你正在做的即使在 SAS 中 - 你正在将记录转换为字符串(在文本文件),然后将它们读回并再次写出。 (在 SAS 中执行此操作可能比您正在执行的操作要容易得多,老实说,但把它放在一边……)老实说,这里更大的问题只是说明您遵循的规则 - 不清楚规则是什么,当然超出程序指令。如果前三行有值,你写 First Second 一次,Third 三次,Fourth 写?
  • @JonSG 固定格式是他在 SAS 中所做的,至少。但它更像是被分割成一堆行,有点像旧的“卡片列”格式,但也不完全是……我认为它一定是银行系统的东西,因为没有其他东西会这样奇怪。

标签: python pandas numpy text sas


【解决方案1】:

这并不是一个很好的方法,但也许它可以让您了解如何执行逻辑。我只是在写一个列表,然后您可以将列表写出来-但您可能应该按照 JonSG 在他的(已删除)答案中使用文件编写器的方式进行操作。使用数据类可能有更好的方法,但这不是我的专长。

import pandas as pd

df = pd.read_csv(r"h:\temp\df_text.csv")

outlist = []

for index,row in df.iterrows():
    if(row['SEQ']==1):
        tempstr = '00FIRST'+row.VAR1+'  '+row.VAR2
        outlist.append(tempstr)
        tempstr = '00SECOND'+str(row.VAR3)+'  '+str(row.VAR4)+str(row.VAR5)
        outlist.append(tempstr)
    if(row['SEQ'] <= 3):
        seqval ='0'+str(row.SEQ) if  row.SEQ < 10 else str(row.SEQ)
        tempstr = str(row['SEQ'])+'THIRD'+str(row.DATE)
        outlist.append(tempstr)
        if (row.VAR6 != '  '):
            tempstr = str(row['SEQ'])+'FOURTH'+row.VAR6+'  '+row.VAR7
            outlist.append(tempstr)

    
    

【讨论】:

  • 您的答案符合逻辑,但唯一的是每个输出宽度/长度(似乎您直接使用空间来这样做,酷!)..我也找到了他的删除答案,但它好像暂时没有记录可以追踪
  • 是否可以在列表中设置元组并将其用于FIRSTSECONDTHIRDFOURTH 输出?
  • 我这样做的方式,不,这无济于事 - 不是我能看到吗?我认为做到这一点的“最佳”方法是使用dataclass 将输出作为一种方法内置在其中,老实说,但上面的列表或文件编写器应该可以完成你想要的 - 也许用正如 Jon 所展示的,使用 {: &lt;4} 类型格式化程序更关心格式化。
  • 似乎我们无法检查@JonSG 发布的已删除答案...
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-01-01
  • 2016-02-08
相关资源
最近更新 更多