微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

使用Python处理巨大的文本文件或准CSV-从文本数据创建矩阵

如何解决使用Python处理巨大的文本文件或准CSV-从文本数据创建矩阵

当我对如何解决我的问题没有一个正确的想法时,我到了一个地步。我正在处理文本文件(* .inp-abaqus作业文件),我想从中提取一些基本信息。到目前为止,我发现了两个主要问题:

  1. 这样的文件很大,即50万行。
  2. 它们的结构并不总是像csv一样

Ad.1。由于海量数据,我想包括pandas库以加快操作速度(在优化循环中将重复进行此操作)

广告2。具有其“奇怪”结构的示例* .inp文件(请注意,“ node”和“ element”是代码中使用的实际名称,每个元素都是由多个节点组成的,例如cube = element,每个立方体vertices = node]:

*NODE
     1,0.0,3.0
     2,-17.0,5.5,2.3
     3,51.0,639.8          
     5,31.0 
...
     145000,31.3,21.5,99.8
*ELEMENT,ELSET=Name1,TYPE=Type1
     1527450,265156,273237,265019,265021,275728,273221,265599,265146,273583,265020
     1527449,269279,272869,269277,269479,273130,272862,269278,269489,275729,269627
     1527448,272250,272858,275350,273327,272851,275730,275731,273346,275732,275733
...
     1126546,265180,275352,273263,275736,275737,275738,275739,275740,273246
*ELEMENT,ELSET=Name2,Type2
...
*SURFACE,NAME=Surf1
     12345,S5
     34567,S3
...
*STEP
*STATIC
1.0,1.0
*BOUNDARY
bc_1,1,3,0.0
bc_2,6,0.0
...
...

关键字“ * NODE”下列出的值具有以下顺序: node_id,coord_x,coord_y,coord_z

这是模型中最大的数据集,这就是为什么我要为此使用pandas(将其像csv一样读取)的原因。对于这一部分,我没有发现主要问题。

* ELEMENT“关键字下列出的值稍微复杂一些:

第n行:elementn_id,node1_id,node2_id,node3_id,node4_id,node5_id,node6_id,node7_id

第n + 1行:node8_id,node9_id,node10_id

在这种情况下,大熊猫将这部分代码作为两条单独的行(显然)以n + 1行的最后7列中的N / A项导入。我使用pd.read_csv。请注意,从1到10的节点ID一起构成一个元素(其ID在第n行中指定为第一件事)。

现在我说出问题了:):

  1. 当我的目标是拥有一个矩阵,其中每个元素仅使用1行且总共11列时,如何正确导入介于* ELEMENT,ELSET = name1和* ELEMENT,ELSET = name2之间的数据(第一个-element_id ,2-11-nodex_id)。
  2. 到目前为止,我已将此* .inp文件划分为多个单独的文件,以便可以在它们上工作...现在,我想在一个脚本中完成所有操作,即创建矩阵A = [(node_id,coord_x,coord_y,coord_z ),...]和矩阵B = [[element_id,node1_id,node2_id,...,node10_id),...]。如果简单的pd.read_csv在这种情况下无法执行,该怎么办?有很多严格的字符串行,不应导入或将其排除以加速脚本。

我的想法是将* .inp文件作为“打开”功能导入到python中,然后添加某种标签/触发器以匹配应进一步使用哪些代码行(并可能使用熊猫进行处理),但是在在这种情况下,我不将熊猫用作导入选项...

我相信我的问题对你们大多数人来说都是沉闷的,但我并不是严格意义上的开发人员:)我不希望得到直接,现成的解决方案,而是希望获得您在哪里寻找潜在答案或工具的建议。

提前谢谢大家,祝您有个美好的一天, prz

解决方法

有趣的挑战!

只要您需要处理的文件大致遵循该结构,类似的操作就可以为您工作。输出见下文。

  • 将文件数据内联到io.StringIO()中以使其自给自足,但也可以将其作为open("data.inp")文件流。
  • 如果您不太熟悉Python,生成器函数及其yield的魔力可能看起来有些不可思议,对此感到抱歉。 :)
  • 确实需要“重新构造”内存中的CSV文件以供熊猫读取,如果您的内存不足,可能会成为瓶颈,但是您可以通过赋予它来了解一枪...
  • 请注意如何有意跳过“ Surf1”组,因此您对如何忽略某些部分有一个了解。
import io
import itertools
import pandas as pd


def split_abq(inp_file):
    """
    Split an ABQ file into tuples of "group" header and lines in that group.
    """

    current_header = None
    for line in inp_file:
        line = line.strip()  # remove whitespace
        if not line:  # skip empty lines
            continue
        if line.startswith("*"):  # note headers
            current_header = line
            continue
        yield (current_header,line)  # generate lines


def group_split_abq(split_generator):
    """
    "De-repeat" the output of `split_abq` into a generator (group name,generator-of-lines)
    """
    for group,entries in itertools.groupby(split_abq(input_file),lambda pair: pair[0]):
        line_generator = (line for group,line in entries)  # A generator expression; this is evaluated lazily
        yield (group,line_generator)


def lines_to_df(line_generator,**read_csv_kwargs):
    """
    Convert an iterable of CSV-ish lines into a Pandas dataframe
    """

    # "Write" an in-memory file for Pandas to parse
    csv_io = io.StringIO()
    for line in line_generator:
        print(line,file=csv_io)
    csv_io.seek(0)  # Seek back to the start
    return pd.read_csv(csv_io,**read_csv_kwargs)


input_file = io.StringIO(
    """
*NODE
     1,0.0,3.0
     2,-17.0,5.5,2.3
     3,51.0,639.8
     5,31.0 
     145000,31.3,21.5,99.8
*ELEMENT,ELSET=Name1,TYPE=Type1
     1527450,265156,273237,265019,265021,275728,273221,265599,265146,273583,265020
     1527449,269279,272869,269277,269479,273130,272862,269278,269489,275729,269627
     1527448,272250,272858,275350,273327,272851,275730,275731,273346,275732,275733
     1126546,265180,275352,273263,275736,275737,275738,275739,275740,273246
*ELEMENT,ELSET=Name2,Type2
    1527450,265020
*SURFACE,NAME=Surf1
     12345,S5
     34567,S3
*STEP
*STATIC
1.0,1.0
*BOUNDARY
bc_1,1,3,0.0
bc_2,6,0.0
"""
)


for group,lines in group_split_abq(split_abq(input_file)):
    print("=================================")
    print("Group: ",group)
    if "Surf1" in group:  # You can use this opportunity to ignore some groups
        print("-> Skipping Surf1")
        continue
    df = lines_to_df(lines,header=None)  # `header` should probably be decided by the group type
    print(df.head())
    print("------------------------------\n")
    # You could store the various `df`s generated in a dict here

输出为

=================================
Group:  *NODE
        0     1     2      3
0       1   0.0   0.0    3.0
1       2 -17.0   5.5    2.3
2       3  51.0   0.0  639.8
3       5   0.0   5.5   31.0
4  145000  31.3  21.5   99.8
------------------------------

=================================
Group:  *ELEMENT,TYPE=Type1
        0       1       2       3       4       5       6       7       8       9       10
0  1527450  265156  273237  265019  265021  275728  273221  265599  265146  273583  265020
1  1527449  269279  272869  269277  269479  273130  272862  269278  269489  275729  269627
2  1527448  272250  272858  275350  273327  272851  275730  275731  273346  275732  275733
3  1126546  265180  275352  273263  273237  275736  275737  275738  275739  275740  273246
------------------------------

=================================
Group:  *ELEMENT,Type2
        0       1       2       3       4       5       6       7       8       9       10
0  1527450  265156  273237  265019  265021  275728  273221  265599  265146  273583  265020
------------------------------

=================================
Group:  *SURFACE,NAME=Surf1
-> Skipping Surf1
=================================
Group:  *STATIC
     0   1   2    3
0  1.0 NaN NaN  1.0
------------------------------

=================================
Group:  *BOUNDARY
      0  1  2    3
0  bc_1  1  3  0.0
1  bc_2  6  6  0.0
------------------------------
,

您可能想看看使用此解析器AbqParse,但我没有尝试过,所以我不知道它是否对您有用,代码也很旧,因此可能无法使用在最新版本的python中工作。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。