【问题标题】:How can I filter lines on load in Pandas read_csv function?如何在 Pandas read_csv 函数中过滤加载行?
【发布时间】:2012-11-19 00:31:45
【问题描述】:

如何使用 pandas 筛选要加载到内存中的 CSV 行?这似乎是一个应该在read_csv 中找到的选项。我错过了什么吗?

示例:我们有一个带有时间戳列的 CSV,我们希望只加载时间戳大于给定常量的行。

【问题讨论】:

    标签: python pandas


    【解决方案1】:

    在将 CSV 文件加载到 pandas 对象之前,没有过​​滤行的选项。

    您可以加载文件,然后使用df[df['field'] > constant] 进行过滤,或者如果您有一个非常大的文件并且您担心内存耗尽,则使用迭代器并在连接文件块时应用过滤器,例如:

    import pandas as pd
    iter_csv = pd.read_csv('file.csv', iterator=True, chunksize=1000)
    df = pd.concat([chunk[chunk['field'] > constant] for chunk in iter_csv])
    

    您可以改变chunksize 以适应您的可用内存。详情请见here

    【讨论】:

    • for chunk['filed']>constant 我可以把它夹在两个常数值之间吗?例如:常量 1 > 块 ['字段'] > 常量 2。或者我可以使用“范围内”吗?
    • 试试:chunk[(chunk['field'] > constant2)&(chunk['field']<constant1)]
    • 这是否缺少.locchunk.loc[chunk['field'] > constant]
    • 您可以使用带或不带.loc 的布尔掩码。我不认为 .loc 早在 2012 年就存在,但我想这些天使用 .loc 更加明确。
    【解决方案2】:

    read_csv 的上下文中,我没有找到直接的方法来执行此操作。但是read_csv返回一个DataFrame,可以通过布尔向量df[bool_vec]选择行来过滤:

    filtered = df[(df['timestamp'] > targettime)]
    

    这是选择 df 中的所有行(假设 df 是任何 DataFrame,例如 read_csv 调用的结果,至少包含一个日期时间列 timestamp),其中 timestamp 列中的值是大于目标时间的值。 Similar question.

    【讨论】:

    • 我不确定这一点,但我感觉这会占用大量内存。
    【解决方案3】:

    如果过滤的范围是连续的(通常是使用时间(戳)过滤器),那么最快的解决方案是对行范围进行硬编码。只需将skiprows=range(1, start_row)nrows=end_row 参数结合起来。然后导入需要几秒钟,而接受的解决方案需要几分钟。考虑到导入时间的节省,对初始 start_row 的一些实验并不是一笔巨大的成本。请注意,我们使用 range(1,..) 保留了标题行。

    【讨论】:

      【解决方案4】:

      已接受答案的替代方法是将 read_csv() 应用于通过过滤输入文件获得的 StringIO。

      with open(<file>) as f:
          text = "\n".join([line for line in f if <condition>])
      
      df = pd.read_csv(StringIO(text))
      

      当过滤条件仅保留一小部分行时,此解决方案通常比接受的答案更快

      【讨论】:

      • &lt;condition&gt; 在这里如何工作? text = "\n".join([line for line in f if df['column']=='Hello']) 喜欢吗?编辑:不,它不起作用。 TypeError: string indices must be integers
      • 没有。假设 'column' 是 CSV 文件中的第三列,假设 ',' 是字段分隔符,请写:with open(&lt;file&gt;) as f: text = "\n".join([line for line in f if line.split(',')[2] == "Hello"])
      【解决方案5】:

      假设您有以下数据框

      +----+--------+
      | Id | Name   |
      +----+--------+
      |  1 | Sarath |
      |  2 | Peter  |
      |  3 | James  |
      +----+--------+
      

      如果您需要过滤Id = 1 的记录,则可以使用以下代码。

      df = pd.read_csv('Filename.csv', sep = '|')
      df = df [(df ["Id"] == 1)]
      

      这将产生以下输出。

      +----+--------+
      | Id | Name   |
      +----+--------+
      |  1 | Sarath |
      +----+--------+
      

      【讨论】:

        【解决方案6】:

        如果你在 linux 上,你可以使用 grep。

        # to import either on Python2 or Python3
        import pandas as pd
        from time import time # not needed just for timing
        try:
            from StringIO import StringIO
        except ImportError:
            from io import StringIO
        
        
        def zgrep_data(f, string):
            '''grep multiple items f is filepath, string is what you are filtering for'''
        
            grep = 'grep' # change to zgrep for gzipped files
            print('{} for {} from {}'.format(grep,string,f))
            start_time = time()
            if string == '':
                out = subprocess.check_output([grep, string, f])
                grep_data = StringIO(out)
                data = pd.read_csv(grep_data, sep=',', header=0)
        
            else:
                # read only the first row to get the columns. May need to change depending on 
                # how the data is stored
                columns = pd.read_csv(f, sep=',', nrows=1, header=None).values.tolist()[0]    
        
                out = subprocess.check_output([grep, string, f])
                grep_data = StringIO(out)
        
                data = pd.read_csv(grep_data, sep=',', names=columns, header=None)
        
            print('{} finished for {} - {} seconds'.format(grep,f,time()-start_time))
            return data
        

        【讨论】:

        • 使用 grep 是非常糟糕的选择,原因有几个。 1)它很慢 2)它不便携 3)它不是 pandas 或 python(你可以在 python 中使用正则表达式)这就是为什么我不赞成你的答案
        • 您的解决方案并非适用于所有平台,而且它还包括 Grep。这就是投反对票的原因。
        【解决方案7】:

        您可以指定nrows参数。

        import pandas as pd df = pd.read_csv('file.csv', nrows=100)

        此代码在 0.20.3 版本中运行良好。

        【讨论】:

        • OP 询问如何过滤而不限制读取的行数。这就是为什么我不赞成你的回答。
        猜你喜欢
        • 2013-02-07
        • 2020-07-24
        • 2013-06-20
        • 2022-10-13
        • 1970-01-01
        • 2023-03-29
        相关资源
        最近更新 更多