【问题标题】:parse sas .out into pandas将 sas .out 解析为 pandas
【发布时间】:2015-07-26 13:18:23
【问题描述】:

我收到很多类似这样的数据:

                                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. 删除重复的标题

我想我可以用一个大而愚蠢的多行正则表达式处理三个,但我不知道如何处理 1 和 2(不是 pandas.read_fwf,至少在没有足够的预处理的情况下我无论如何,到那时已经解决了 1 和 2)。

pydata 世界中是否已经有一个库可以做到这一点?如果没有,有什么建议吗?

【问题讨论】:

  • 这并不难,但可能很乏味且耗时。你最好的时间投资可能花在说服(乞求?)程序员输出更方便的东西上。它最终也更加准确。我怀疑是否有一个库(尽管可能有)b/c 这是 CSV、sas 数据集、hd5 等的重点。
  • 谢谢@JohnE,我同意。我想我将研究一种解决最简单情况(无包装)的方法,并将其作为其他人的起点,但昨天的一些工作证实了单调乏味。在这一点上绝对是“乞求”而不是说服。

标签: python pandas text-processing


【解决方案1】:

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-05-18
    • 1970-01-01
    • 1970-01-01
    • 2023-02-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多