【问题标题】:Parsing tables from .txt (text) files从 .txt(文本)文件解析表
【发布时间】:2020-10-02 00:54:46
【问题描述】:

我有一些来自 python 分析器的分析结果,如下所示:

Filename: main.py

Line #    Mem usage    Increment   Line Contents
================================================
    30    121.8 MiB    121.8 MiB   @profile(stream=f)
    31                             def parse_data(data):
    32    121.8 MiB      0.0 MiB       Y=data["price"].values
    33    121.8 MiB      0.0 MiB       Y=np.log(Y)
    34    121.8 MiB      0.0 MiB       features=data.columns
    35    121.8 MiB      0.0 MiB       X1=list(set(features)-set(["price"]))
    36    126.3 MiB      4.5 MiB       X=data[X1].values
    37    126.3 MiB      0.0 MiB       ss=StandardScaler()
    38    124.6 MiB      0.0 MiB       X=ss.fit_transform(X)
    39    124.6 MiB      0.0 MiB       return X,Y


Filename: main.py

Line #    Mem usage    Increment   Line Contents
================================================
    41    127.1 MiB    127.1 MiB   @profile(stream=f)
    42                             def linearRegressionfit(Xt,Yt,Xts,Yts):
    43    127.1 MiB      0.0 MiB       lr=LinearRegression()
    44    131.2 MiB      4.1 MiB       model=lr.fit(Xt,Yt)
    45    132.0 MiB      0.8 MiB       predict=lr.predict(Xts)
    46                             

现在,我需要获取这些结果用于绘图和其他目的。但是文本不是很方便。该表显示了逐行分析结果。如何获取 pandas 数据框或表格版本可用于从该表中获取任何行或列

附:我访问过regexparsimonious,但似乎无法让它们在我的情况下使用。

【问题讨论】:

  • 你能展示一个所需输出的例子吗?你想跳过哪几行?如何处理缺失值,例如第 32 行和第 42 行中的 Mem 使用/增量?
  • 我的目标是为每个函数获取不同的数据帧。不同的功能由 @profile 装饰器区分。如果按照与此文本文件中的顺序相同的顺序,这些表格会很棒。这将允许我简单地迭代所有行并获得内存使用量的增量(总计 + 每个函数)

标签: python python-3.x text text-parsing memory-profiling


【解决方案1】:

这只是一个解析练习。通过标准的 split() 和一些小的调整,你可以在几行代码中得到一个非常干净的数据框。

txt = '''
Filename: main.py

Line #    Mem usage    Increment   Line Contents
================================================
    30    121.8 MiB    121.8 MiB   @profile(stream=f)
    31                             def parse_data(data):
    32    121.8 MiB      0.0 MiB       Y=data["price"].values
    33    121.8 MiB      0.0 MiB       Y=np.log(Y)
    34    121.8 MiB      0.0 MiB       features=data.columns
    35    121.8 MiB      0.0 MiB       X1=list(set(features)-set(["price"]))
    36    126.3 MiB      4.5 MiB       X=data[X1].values
    37    126.3 MiB      0.0 MiB       ss=StandardScaler()
    38    124.6 MiB      0.0 MiB       X=ss.fit_transform(X)
    39    124.6 MiB      0.0 MiB       return X,Y


Filename: main.py

Line #    Mem usage    Increment   Line Contents
================================================
    41    127.1 MiB    127.1 MiB   @profile(stream=f)
    42                             def linearRegressionfit(Xt,Yt,Xts,Yts):
    43    127.1 MiB      0.0 MiB       lr=LinearRegression()
    44    131.2 MiB      4.1 MiB       model=lr.fit(Xt,Yt)
    45    132.0 MiB      0.8 MiB       predict=lr.predict(Xts)
'''

import pandas as pd

lines = []
for line in txt.split('\n'):
    #print(line)
    if line.startswith('Filename'): continue
    if line.startswith('Line'): continue
    if line.startswith('='): continue
    if line == '': continue
    data = [i.strip() for i in line.split()]
    #Fix def lines
    if data[1] == 'def':
        data = [data[0],'','','','',' '.join(data[1:4])]

    data = [data[0], ' '.join(data[1:3]), ' '.join(data[3:5]), data[-1]]
    lines.append(data)

df = pd.DataFrame(lines, columns=['Line #', 'Mem usage', 'Increment','Line Contents'])

print(df)

   Line #  Mem usage  Increment                            Line Contents
0      30  121.8 MiB  121.8 MiB                       @profile(stream=f)
1      31                                          def parse_data(data):
2      32  121.8 MiB    0.0 MiB                   Y=data["price"].values
3      33  121.8 MiB    0.0 MiB                              Y=np.log(Y)
4      34  121.8 MiB    0.0 MiB                    features=data.columns
5      35  121.8 MiB    0.0 MiB    X1=list(set(features)-set(["price"]))
6      36  126.3 MiB    4.5 MiB                        X=data[X1].values
7      37  126.3 MiB    0.0 MiB                      ss=StandardScaler()
8      38  124.6 MiB    0.0 MiB                    X=ss.fit_transform(X)
9      39  124.6 MiB    0.0 MiB                                      X,Y
10     41  127.1 MiB  127.1 MiB                       @profile(stream=f)
11     42                        def linearRegressionfit(Xt,Yt,Xts,Yts):
12     43  127.1 MiB    0.0 MiB                    lr=LinearRegression()
13     44  131.2 MiB    4.1 MiB                      model=lr.fit(Xt,Yt)
14     45  132.0 MiB    0.8 MiB                  predict=lr.predict(Xts)

然后当'@profile''Line Contents' 中时,您可以拆分数据框。

例如:

split_idx = df[df['Line Contents'].str.startswith('@profile')].index
dataframes = []
for i, idx in enumerate(split_idx):
    try:
        dataframes.append(df.iloc[idx, split_idx[i+1]])
    except IndexError:
        dataframes.append(df.iloc[idx:])


print(dataframes[0])
print('======')
print(dataframes[1])

   Line #  Mem usage  Increment                            Line Contents
0      30  121.8 MiB  121.8 MiB                       @profile(stream=f)
1      31                                          def parse_data(data):
2      32  121.8 MiB    0.0 MiB                   Y=data["price"].values
3      33  121.8 MiB    0.0 MiB                              Y=np.log(Y)
4      34  121.8 MiB    0.0 MiB                    features=data.columns
5      35  121.8 MiB    0.0 MiB    X1=list(set(features)-set(["price"]))
6      36  126.3 MiB    4.5 MiB                        X=data[X1].values
7      37  126.3 MiB    0.0 MiB                      ss=StandardScaler()
8      38  124.6 MiB    0.0 MiB                    X=ss.fit_transform(X)
9      39  124.6 MiB    0.0 MiB                                      X,Y
10     41  127.1 MiB  127.1 MiB                       @profile(stream=f)
11     42                        def linearRegressionfit(Xt,Yt,Xts,Yts):
12     43  127.1 MiB    0.0 MiB                    lr=LinearRegression()
13     44  131.2 MiB    4.1 MiB                      model=lr.fit(Xt,Yt)
14     45  132.0 MiB    0.8 MiB                  predict=lr.predict(Xts)
======
   Line #  Mem usage  Increment                            Line Contents
10     41  127.1 MiB  127.1 MiB                       @profile(stream=f)
11     42                        def linearRegressionfit(Xt,Yt,Xts,Yts):
12     43  127.1 MiB    0.0 MiB                    lr=LinearRegression()
13     44  131.2 MiB    4.1 MiB                      model=lr.fit(Xt,Yt)
14     45  132.0 MiB    0.8 MiB                  predict=lr.predict(Xts)

【讨论】:

  • 这太完美了!非常感谢 :) 我对代码进行了一些更正,以包含其他一些幼稚的案例。我想我会用正则表达式来矫枉过正
  • @PeDro 您的编辑过多地更改了代码。我拒绝了他们。以我写的代码为例,按照你认为最好的方式修改你自己的实现。
【解决方案2】:

不完全清楚是要解析整个文本,还是每个表都有一个文本文件并要解析该表。

如果你想从每个表中创建一个 pandas 数据框,使用 skiprows 参数到 read_fwf 应该可以工作(这会跳过文件中的非标准行,但会解析其余部分)。这里我将第一个表的内容存储到一个文件sample-1.txt 并使用read_fwf 读取它。

import pandas

df = pandas.read_fwf('sample-1.txt', skiprows=[1])

这给出了以下数据框。

>>> df.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 10 entries, 0 to 9
Data columns (total 4 columns):
Line #           10 non-null int64
Mem usage        9 non-null object
Increment        9 non-null object
Line Contents    10 non-null object
dtypes: int64(1), object(3)
memory usage: 392.0+ bytes

如果要将其拆分为单独的表,则必须在每次提及 Filename: main.py 时破坏文件。

【讨论】:

    【解决方案3】:

    另一种解决方案。

    可以使用TTP从文本中生成时间序列数据。

    示例代码:

    from ttp import ttp
    import pprint
    
    data_1 = """
    Line #    Mem usage    Increment   Line Contents
    ================================================
        30    121.8 MiB    121.8 MiB   @profile(stream=f)
        31                             def parse_data(data):
        32    121.8 MiB      0.0 MiB       Y=data["price"].values
        33    121.8 MiB      0.0 MiB       Y=np.log(Y)
        34    121.8 MiB      0.0 MiB       features=data.columns
        35    121.8 MiB      0.0 MiB       X1=list(set(features)-set(["price"]))
        36    126.3 MiB      4.5 MiB       X=data[X1].values
        37    126.3 MiB      0.0 MiB       ss=StandardScaler()
        38    124.6 MiB      0.0 MiB       X=ss.fit_transform(X)
        39    124.6 MiB      0.0 MiB       return X,Y
    """
    
    data_2 = """
    Line #    Mem usage    Increment   Line Contents
    ================================================
        41    127.1 MiB    127.1 MiB   @profile(stream=f)
        42                             def linearRegressionfit(Xt,Yt,Xts,Yts):
        43    127.1 MiB      0.0 MiB       lr=LinearRegression()
        44    131.2 MiB      4.1 MiB       model=lr.fit(Xt,Yt)
        45    132.0 MiB      0.8 MiB       predict=lr.predict(Xts)
        46    
    """
    
    template = """
    <vars>
    timestamp = "get_timestamp_iso"
    </vars>
    
    <group macro="process">
    Line_N    Mem_usage    Increment   Line_Contents {{ _headers_ }}
    {{ @timestamp | set(timestamp) }}
    </group>
    
    <macro>
    def process(data):
        # remove ===== matches
        if "====" in data["Line_N"]:
            return False
            
        # convert Increment to integer    
        incr = data.pop("Increment").split(" ")[0]
        data["Increment_MiB"] = float(incr) if incr else 0.0
        
        # convert Mem usage to integer 
        memuse = data.pop("Mem_usage").split(" ")[0]
        data["Mem_usage_MiB"] = float(memuse) if memuse else 0.0
        
        return data
    </macro>
    """
    
    parser = ttp(template=template)
    parser.add_input(data_1)
    parser.add_input(data_2)
    parser.parse()
    res = parser.result(structure="flat_list")
    pprint.pprint(res)
    
    # will print:
    # [{'@timestamp': '2020-08-01T21:57:51.734448+00:00',
    #   'Increment_MiB': 121.8,
    #   'Line_Contents': '@profile(stream=f)',
    #   'Line_N': '30',
    #   'Mem_usage_MiB': 121.8},
    #  {'@timestamp': '2020-08-01T21:57:51.734448+00:00',
    #   'Increment_MiB': 0.0,
    #   'Line_Contents': 'def parse_data(data):',
    #   'Line_N': '31',
    #   'Mem_usage_MiB': 0.0},
    #  {'@timestamp': '2020-08-01T21:57:51.734448+00:00',
    #   'Increment_MiB': 0.0,
    #   'Line_Contents': 'Y=data["price"].values',
    #   'Line_N': '32',
    #   'Mem_usage_MiB': 121.8},
    #  {'@timestamp': '2020-08-01T21:57:51.734448+00:00',
    #   'Increment_MiB': 0.0,
    #   'Line_Contents': 'Y=np.log(Y)',
    #   'Line_N': '33',
    #   'Mem_usage_MiB': 121.8},
    #  {'@timestamp': '2020-08-01T21:57:51.734448+00:00',
    #   'Increment_MiB': 0.0,
    #   'Line_Contents': 'features=data.columns',
    #   'Line_N': '34',
    #   'Mem_usage_MiB': 121.8},
    #  {'@timestamp': '2020-08-01T21:57:51.734448+00:00',
    #   'Increment_MiB': 0.0,
    #   'Line_Contents': 'X1=list(set(features)-set(["price"]))',
    #   'Line_N': '35',
    #   'Mem_usage_MiB': 121.8},
    #  {'@timestamp': '2020-08-01T21:57:51.734448+00:00',
    #   'Increment_MiB': 4.5,
    #   'Line_Contents': 'X=data[X1].values',
    #   'Line_N': '36',
    #   'Mem_usage_MiB': 126.3},
    #  {'@timestamp': '2020-08-01T21:57:51.734448+00:00',
    #   'Increment_MiB': 0.0,
    #   'Line_Contents': 'ss=StandardScaler()',
    #   'Line_N': '37',
    #   'Mem_usage_MiB': 126.3},
    #  {'@timestamp': '2020-08-01T21:57:51.734448+00:00',
    #   'Increment_MiB': 0.0,
    #   'Line_Contents': 'X=ss.fit_transform(X)',
    #   'Line_N': '38',
    #   'Mem_usage_MiB': 124.6},
    #  {'@timestamp': '2020-08-01T21:57:51.734448+00:00',
    #   'Increment_MiB': 0.0,
    #   'Line_Contents': 'return X,Y',
    #   'Line_N': '39',
    #   'Mem_usage_MiB': 124.6},
    #  {'@timestamp': '2020-08-01T21:57:51.738444+00:00',
    #   'Increment_MiB': 127.1,
    #   'Line_Contents': '@profile(stream=f)',
    #   'Line_N': '41',
    #   'Mem_usage_MiB': 127.1},
    #  {'@timestamp': '2020-08-01T21:57:51.738444+00:00',
    #   'Increment_MiB': 0.0,
    #   'Line_Contents': 'def linearRegressionfit(Xt,Yt,Xts,Yts):',
    #   'Line_N': '42',
    #   'Mem_usage_MiB': 0.0},
    #  {'@timestamp': '2020-08-01T21:57:51.738444+00:00',
    #   'Increment_MiB': 0.0,
    #   'Line_Contents': 'lr=LinearRegression()',
    #   'Line_N': '43',
    #   'Mem_usage_MiB': 127.1},
    #  {'@timestamp': '2020-08-01T21:57:51.738444+00:00',
    #   'Increment_MiB': 4.1,
    #   'Line_Contents': 'model=lr.fit(Xt,Yt)',
    #   'Line_N': '44',
    #   'Mem_usage_MiB': 131.2},
    #  {'@timestamp': '2020-08-01T21:57:51.738444+00:00',
    #   'Increment_MiB': 0.8,
    #   'Line_Contents': 'predict=lr.predict(Xts)',
    #   'Line_N': '45',
    #   'Mem_usage_MiB': 132.0}]
    

    如果您将上述数据推送到 Elasticsearch 进行索引,则可以使用 Grafana 相当容易地对其进行可视化,您可以构造查询以引用 Line_N 或 Line_Contents 变量以每行显示计数器。

    但要使上述模板正常工作,需要从 github repo 安装 TTP - PyPI 上可用的 0.3.0 版本没有必需的功能。不过新版本即将推出。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-10-09
      • 1970-01-01
      • 2017-02-06
      • 1970-01-01
      • 1970-01-01
      • 2017-10-08
      • 1970-01-01
      • 2016-04-07
      相关资源
      最近更新 更多