从熊猫的多列中过滤掉非数字行

时间:2021-03-23 16:36:26

标签: python pandas numpy

我有相当大的 LZMA 压缩数据文件,我想使用 Pandas 读取这些文件以提取某些列的最小值和最大值。该文件是使用 grep -n 从在 MPI 下运行的程序的日志文件中生成的,因此包含多个 MPI 等级同时写入 stdout 的乱码行。

这个问题与 this one 非常相似,但我需要对每一列做同样的事情 3 次。我尝试了那里提供的各种答案都无济于事。

这是我目前得到的 Python 脚本:

import os # to check file existence
import sys # for argc, argv
import re # regex
import lzma as xz
import numpy as np
import pandas as pd

# Quick exit if file does not exist
if not os.path.exists(argv[1]):
    help();    sys.exit( 'Error: cannot read file', argv[1] );
else:
    
    # Define column names and columns to take
    cols     = [ 4,   7,   10  ];
    colnames = [ 'm', 'n', 'k' ];

    # Read file through LZMA decompressor
    ifname = argv[1];
    ifile = xz.open( ifname, 'rt' );
    data = pd.read_csv( ifile, delim_whitespace=True, \
                        usecols=cols, names=colnames, \
                        error_bad_lines=False );
    ifile.close();

    ### Insert filtering method here to transform data to data_clean
    
    mdims = data_clean['m'].to_numpy();
    mmin = np.amin(mdims);
    mmax = np.amax(mdims);
    ndims = data_clean['n'].to_numpy();
    nmin = np.amin(ndims);
    nmax = np.amax(ndims);
    kdims = data_clean['k'].to_numpy();
    kmin = np.amin(kdims);
    kmax = np.amax(kdims);

    # Display output
    print( re.sub( ifname, '.xz', '' ), ':' );
    print( 'M =', mmin, '-', mmax );
    print( 'N =', nmin, '-', nmax );
    print( 'K =', kmin, '-', kmax );

    sys.exit(0);

Here 是您可以测试的两个数据文件。任何帮助将不胜感激。

1 个答案:

答案 0 :(得分:1)

说到数据过滤,越早越好...

在这里,我将在加载时使用转换器将有问题的值替换为 NaN 。这样,过滤就只需要 dropna:

def convert(x):
    try:
        return np.int64(x)
    except ValueError:
        return np.nan
...
data = pd.read_csv( ifile, delim_whitespace=True, \
                    usecols=cols, names=colnames, \
                    error_bad_lines=False, \
                    converters= {k: convert for k in colnames})
data_clean = data.dropna().astype('int64')

但实际上,尝试使用 csv 阅读器只是为时已晚。因为它不是真正的 csv 文件,而是包含如下行:

793883: zgemm: m =           51  n =           449 k =          2408
793884: zgemm: m =           51  n =           449 k =          2408
793885: zgemm: m =           51  n =           449 k =          2408
793886: zgemm: m =           51  n =           449 k =          2408
793887: zgemm: m =           51  n =           449 k =          2408
793888: zgemm: m =           51  n =           449 k =          2408

到目前为止一切顺利,问题是还包含像

这样的乱码
3251002: ) into (     zgemm: m =           51  n =           449 k =          2391
1735619: zgemm: m =           51  n =           449 k =          24043 x          243 
1747325: zgemm: m =           51  n =           449 k =          239          3 packing gntuju (          243 x          243

最后两行表明,试图挽救错误的行可能会导致错误的数据,因为某些值可能会被截断或与其他数字连接

但是正则表达式应该足以识别有效行。所以我会这样做:

...
import re
...

    ...
    pattern = r'\d+:\s\w+:\s+m\s+=\s+(\d+)\s+n\s+=\s+(\d+)\s+k\s+=\s+(\d+)\s*$'
    rx = re.compile(pattern)
    data = pd.DataFrame((m.groups() for line in ifile
                       for m in (rx.match(line),) if m),
                      columns=colnames).astype('int64')
    ...