【问题标题】:Save Dataframe with fixed-width columns使用固定宽度的列保存数据框
【发布时间】:2020-05-07 12:37:33
【问题描述】:

我需要编辑来自使用固定宽度列的程序的输入。我设法正确加载它并计算出我需要的内容,但我不知道如何保存编辑后的文件以保持相同的列宽。

import pandas as pd

file = pd.read_fwf('file.inp', 
                  colspecs = [(0, 6), (6, 11), (11, 16), (16, 20), (20, 22), 
                              (22, 26), (26, 38), (38, 46), (46, 54), (54, 61),
                              (61, 68), (68, 90)])

问题是列之间的空格数或数据字符串的长度不同,所以我不能简单地在列之间添加固定数量的空格。

要编辑的文件如下所示:

ATOM    873  N   ALA A  59      41.629  23.754-163.394  1.00 12.93           N
ATOM   5089  NH1 ARG A 315      21.344 -13.371 187.612  1.00 66.09           N1+
ATOM   7839 H5''   A B   3      31.406  -4.882-165.817  1.00 16.98           H 
HETATM 7766 H161 G3A B   1      42.941   1.714-165.146  1.00 14.70           H  

它是数字、字符串、特殊字符和列粘在一起的混合体。

【问题讨论】:

  • @jezrael - 我这样做了,元组列表中的宽度是正确的。该文件已正确加载到数据框中。我只是在使用相同宽度的列再次保存时遇到问题。
  • 有趣的是,我找到了read_fwf,但没有找到write_fwf

标签: python pandas text


【解决方案1】:

正如我评论的那样,我在 pandas 中找不到 write_fdf 方法。但是,我认为您可以使用tabulate 实现您想要的。我将以下代码基于this post 并没有运行它:

import pandas as pd
from tabulate import tabulate


df = pd.read_fwf('file.inp', 
                  colspecs = [(0, 6), (6, 11), (11, 16), (16, 20), (20, 22), 
                              (22, 26), (26, 38), (38, 46), (46, 54), (54, 61),
                              (61, 68), (68, 90)])


with open("...", "w") as f:
    f.write(
        tabulate(
            [list(row) for row in df.values],
            tablefmt="plain"
        )
    )

再次注意,我没有运行这个,只是为了演示如何使用制表:

  • 我没有传递headers参数,如果需要可以使用
  • 我使用“plain”格式来避免任何类似桌子的装饰

更多关于制表的信息here

更新:我意识到输出需要与特定列对齐,因此以下内容似乎足够接近(可能需要进行小规格编辑):

import pandas as pd
import sys


# Mock data
lst = [
    ["ATOM", 873, "N", "ALA", "A", 59, 41.629, 23.754, -163.394, 1.00, 12.93, "N"],
    ["ATOM", 5089, "NH1", "ARG", "A", 315, 21.344, -13.371, 187.612, 1.00 ,66.09, "N1+"],
    ["ATOM", 7839, "H5''", "A", "B", 3, 31.406, -4.882, -165.817, 1.00, 16.98, "H" ],
    ["HETATM", 7766, "H161", "G3A", "B", 1, 42.941, 1.714, -165.146, 1.00, 14.70, "H"],
]

# NOTE the spaces at the end, only when needed
colspecs = [
    "{: <6} ", # left, width=6
    "{: >4} ", # right, width=4
    "{: >4} ",
    "{: >3} ",
    "{: >1} ",
    "{: >3} ",
    "{: >11} ",
    "{: >7}",
    "{: >8} ",
    "{: >5} ",
    "{: <15} ",
    "{: <3}",
]


def write_fdf(fpath, pd, specs):
    """
    Write a Pandas dataframe in fixed width column format with the given
    column specs

    Args:
        fpath: File path
        ps: Dataframe
        specs: A list of python formats
    """
    with open(fpath, "w") as f:
        for _, row in df.iterrows():
            for idx, value in enumerate(row):
                sys.stdout.write(specs[idx].format(value))
                f.write(specs[idx].format(value))

            f.write("\n")
            print("")


df = pd.DataFrame(lst)
write_fdf("/tmp/out.dat", pd, colspecs)

输出:

$ python ~/tmp/test.py
ATOM    873    N ALA A  59      41.629  23.754-163.394   1.0 12.93           N
ATOM   5089  NH1 ARG A 315      21.344 -13.371 187.612   1.0 66.09           N1+
ATOM   7839 H5''   A B   3      31.406  -4.882-165.817   1.0 16.98           H
HETATM 7766 H161 G3A B   1      42.941   1.714-165.146   1.0 14.7            H


$ cat /tmp/out.dat
ATOM    873    N ALA A  59      41.629  23.754-163.394   1.0 12.93           N
ATOM   5089  NH1 ARG A 315      21.344 -13.371 187.612   1.0 66.09           N1+
ATOM   7839 H5''   A B   3      31.406  -4.882-165.817   1.0 16.98           H
HETATM 7766 H161 G3A B   1      42.941   1.714-165.146   1.0 14.7            H

但是,我在格式中看到一个似乎违反规则的例外情况:row=0, col=2: "N" 似乎在您的示例中居中

【讨论】:

  • 我觉得它快到了。但问题是我现在不知道如何告诉制表来制作具有特定宽度的列。以某种方式传递元组的 colspec 列表并告诉 tabulate 将数据放在特定列之间是理想的......
  • 嗯,没想到!我会查看文档,但不确定是否支持...
猜你喜欢
  • 1970-01-01
  • 2013-08-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-02-18
  • 2013-09-14
  • 1970-01-01
相关资源
最近更新 更多