将sas .out解析为熊猫

时间:2015-05-14 19:18:11

标签: python pandas text-processing python-textprocessing

我收到了很多看起来像这样的数据:

                                Even_
                  Long_var_     longer_var
  Obs Var1        name          name            ...
  =================================================
    1 xxx         23            lolz            ...
    2 yyy         34            foo             ...
    3 zzz         96            bar             ...

以SAS的.out文件形式。

如果这些是简单的制表符分隔文件,那就没有问题了,但SAS会做一些神奇的漂亮打印,它会换行变量名称以保持列排列并每隔60或70重复一次标题线条左右。因为变量具有不同的长度(如示例中所示),所以有时这会产生两行变量名称,有时会产生三行,我可以想象会变为四行。

让我们说一下,我无法说服以这种方式提供数据的程序员抛弃一个干净的csv或其他东西。

挑战是3:

  1. 拆分变量名称
  2. 换行
  3. 删除重复的标题
  4. 我想我可以使用一个很大的愚蠢的多行正则表达式处理三个,但我不知道我如何处理1和2(不是pandas.read_fwf,至少不是没有足够的预处理,无论如何我已经解决了1和2)。

    在pydata宇宙中的某个地方是否已经存在这样做了吗?如果没有,有什么建议吗?

1 个答案:

答案 0 :(得分:0)

TXR:

方法:使用固定宽度变量来提取令人讨厌的变量名称列。一些Lisp代码重构它们。在数据上行进时,使用@(maybe)通过可选的空行显示来识别标题的重复。如果有,@(skip)该空行和后续内容直到下一个=====....

@(collect)
@{col1-hdr 3}@{col2-var 12}@{col3-var 14}@{col4-var}
@(last)
@/=====.*/
@(end)
@(set (col1-hdr col2-var col3-var col4-var)
      @[mapcar (opip (mapcar trim-str) cat-str)
               (list col1-hdr col2-var col3-var col4-var)])
@(collect)
 @col1 @col2 @col3 @col4
@  (maybe)

@  (skip)
@/=====.*/
@  (end)
@(end)
@(output)
@{col1-hdr 20} @{col2-var 20} @{col3-var 20} @{col4-var}
@  (repeat)
@{col1     20} @{col2     20} @{col3     20} @col4
@  (end)
@(end)

执行命令

$ cat data
                              Even_
                Long_var_     longer_var
Obs Var1        name          name
========================================
  1 xxx         23            lolz
  2 yyy         34            foo
  3 zzz         96            bar

                              Even_
                Long_var_     longer_var
Obs Var1        name          name
========================================
  4 aaa         12            quux
  5 bbb         45            xyzzy
  6 ccc         78            bork

$ txr data.txr data
Obs                  Var1                 Long_var_name        Even_longer_varname
1                    xxx                  23                   lolz
2                    yyy                  34                   foo
3                    zzz                  96                   bar
4                    aaa                  12                   quux
5                    bbb                  45                   xyzzy
6                    ccc                  78                   bork

这个节目作弊!这取决于"最长的varname"是最右边的。如果数据包含较短的行,如$表示行尾?

,该怎么办?
longest     $
var         shorter$
name        name        shortest$

我们可以做的一件事就是使用空格填充输入流本身直到给定列:确保所有行都填充最多256个字符。 TXR模式语言实际上处理从数据源隐式生成的字符串的惰性列表。我们可以将其重定向到一个明确创建的懒惰列表,我们按摩它。例如,可以通过将此行添加到顶部来完成此操作:

@(next :list @(mapcar* (op format nil "~<256a") (get-lines)))

我们还修改了列收集匹配,以便不在col4变量中包含尾随空格。

 @col1 @col2 @col3 @col4@/ +/

最后,由于我们使用(get-lines)从标准输入读取(当没有给出参数时),我们使用:

$ txr data.txr < data