【问题标题】:Filter out non-numeric lines from multiple columns in pandas从 pandas 的多列中过滤掉非数字行
【发布时间】:2021-03-23 16:36:26
【问题描述】:

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

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

这是我目前得到的 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 是您可以使用的两个数据文件进行测试。任何帮助将不胜感激。

【问题讨论】:

    标签: python pandas numpy


    【解决方案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')
        ...
    

    【讨论】:

    • 我认为这是朝着正确方向迈出的一步,但我得到了奇怪的结果......对于第一个文件,脚本输出 K = 239 - 24043(应该都是 ~2400)对于第二个文件,脚本输出 N = 0 - 85 和 K = 0 - 7048(N 应该是 ~80 和 K ~7000)。但是可以肯定的一件事:乱码行包含的列数与其余数据不同。当该行中的一列包含 NaN 时,如何删除整行?
    • @wyphan 越早越好。恕我直言,最可靠的方法是使用正则表达式验证行。幸运的是,正则表达式可以捕获相关数据以提供数据帧。查看我的编辑。
    • 效果很好,谢谢!将您的答案标记为已接受。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-04-28
    • 1970-01-01
    • 2016-07-26
    相关资源
    最近更新 更多