【问题标题】:How to read only some lines from a large file in python?如何从python中的大文件中只读取一些行?
【发布时间】:2016-10-04 15:36:15
【问题描述】:

我有一个包含 7000 行的大型数据文件(虽然不是很大!),如下所示:

    # data can be obtained from pastebin
    # filename = input.csv
    # lots of comments
    #           wave           flux            err
            0.807172    7.61973e-11    1.18177e-13
            0.807375    7.58666e-11    1.18288e-13
            0.807577    7.62136e-11    1.18504e-13
             0.80778    7.64491e-11    1.19389e-13
            0.807982    7.62858e-11    1.18685e-13
            0.808185    7.63852e-11    1.19324e-13
            0.808387    7.60547e-11    1.18952e-13
             0.80859    7.52287e-11    1.18016e-13
            0.808792    7.53114e-11    1.18979e-13
            0.808995    7.58247e-11    1.20198e-13
    # lots of other lines

输入数据的链接http://pastebin.com/KCW9phzX

我想提取 0.807375 和 0.807982 之间波长的数据。
使输出看起来像这样:

#filename = output.csv
0.807375    7.58666e-11    1.18288e-13
0.807577    7.62136e-11    1.18504e-13
0.80778    7.64491e-11    1.19389e-13
0.807982    7.62858e-11    1.18685e-13     

类似链接如下:

https://stackoverflow.com/questions/8956832/python-out-of-memory-on-large-csv-file-numpy/8964779#=
efficient way to extract few lines of data from a large csv data file in python
What is the most efficient way to match list items to lines in a large file in Python?
Extract specific lines from file and create sections of data in python
how to extract elements from a list in python?
How to use numpy.genfromtxt when first column is string and the remaining columns are numbers?
genfromtxt and numpy

【问题讨论】:

  • 如果您对 numpy/pandas 感到满意,您可以看看 Dask,它是较新的 Blaze 项目的一部分 - 它专门设计用于处理不适合内存的数据集。 matthewrocklin.com/blog/work/2016/02/22/dask-distributed-part-2
  • 文件有多大?几行?您想要numpy 解决方案还是非numpy 解决方案?
  • 在使用二进制搜索查找所需行的范围时,尽可能少地解析文件的行。 Numpy 在这里帮不了你太多。
  • @wwii 现在文件是 6700 行,但是,我必须处理天文数据(我是一名天文学学生),所以欢迎 numpy 和非 numpy 的答案!跨度>

标签: python csv numpy pandas memory


【解决方案1】:

阅读@ubuntu 和@Merlin 的回答,以下也可能是一个很好的解决方案。

注意:@ubuntu 给出的答案绝对没问题。

@Merlin 给出的答案不起作用,不完整,但它是一个很好的开始模板。

注意:输入文件input.csv可以从pastebin获取:
http://pastebin.com/KCW9phzX

使用 numpy :

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# Author    : Bhishan Poudel
# Date      : May 23, 2016


# Imports
import pandas as pd
import numpy as np


# using numpy
infile = 'input.csv'
outfile = 'output.csv'
lower_value = 0.807375
upper_value = 0.807982

print('{} {} {}'.format('Reading file    :', infile, ''))
print('{} {} {}'.format('Writing to file :', outfile, ''))

with open(infile, 'rb') as fin, open(outfile, 'w+b') as fout:
    arr = np.genfromtxt(fin, usecols=(0,1,2), delimiter='', dtype=float)
    mask = (arr[:, 0] >= lower_value) & (arr[:, 0] <= upper_value )
    arr = arr[mask]
    np.savetxt(fout, arr, fmt='%g')

使用熊猫:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# Author    : Bhishan Poudel
# Date      : May 23, 2016


# Imports
import pandas as pd
import numpy as np


# extract range
infile = 'input.csv'
outfile = 'output.csv'
lower_value = 0.807375
upper_value = 0.807982


print('{} {} {}'.format('Reading file      :', infile, ''))
print('{} {} {}'.format('Writing to a file : ', outfile, ''))
df         = pd.read_csv(infile, usecols=(0,1,2), skiprows=57,sep='\s+')
df.columns = [ 'col0', 'col1' , 'col2']
df         = df[(df['col0'] >=  lower_value) & (df['col0'] <=  upper_value) ]
df.to_csv(outfile, header=None, index=None, mode='w', sep=' ')

【讨论】:

    【解决方案2】:

    您可以在循环中调用np.genfromtxt(f, max_rows=chunksize) 以分块读取文件。这样,您可以在保持 NumPy 数组的便利性和速度的同时通过调整 chunksize 来控制所需的内存量。

    import numpy as np
    import warnings
    # genfromtxt warns if it encounters an empty file. Let's silence this warnings since 
    # the code below handles it.
    warnings.filterwarnings("ignore", message='genfromtxt', category=UserWarning)
    
    # This reads 2 lines at a time
    chunksize = 2
    with open('data', 'rb') as fin, open('out.csv', 'w+b') as fout:
        while True:
            arr = np.genfromtxt(fin, max_rows=chunksize, usecols=(0,1,2), 
                                delimiter='', dtype=float)
            if not arr.any(): break
            arr = np.atleast_2d(arr)
            mask = (arr[:, 0] >= 0.807375) & (arr[:, 0] <= 0.807982)
            arr = arr[mask]
    
            # uncomment this print statement to confirm the file is being read in chunks
            # print('{}\n{}'.format(arr, '-'*80))
            np.savetxt(fout, arr, fmt='%g')
    

    写信给out.csv

    0.807375 7.58666e-11 1.18288e-13
    0.807577 7.62136e-11 1.18504e-13
    0.80778 7.64491e-11 1.19389e-13
    0.807982 7.62858e-11 1.18685e-13
    

    对于大型数据文件,您当然希望将 chunksize 增加到比 2 大得多的某个整数。通常,您可以通过选择尽可能大的 chunksize 来获得最佳性能,同时仍在运行在适合 RAM 的阵列上。


    上面的代码适用于大文件。对于只有 7000 行的文件,

    import numpy as np
    with open('data', 'rb') as fin, open('out.csv', 'w+b') as fout:
        arr = np.genfromtxt(fin, usecols=(0,1,2), delimiter='', dtype=float)
        mask = (arr[:, 0] >= 0.807375) & (arr[:, 0] <= 0.807982)
        arr = arr[mask]
        np.savetxt(fout, arr, fmt='%g')
    

    够了。

    【讨论】:

    • @Merlin:Doh!感谢您的更正:) -- 我添加了arr = arr[mask]
    • @ubuntu,我收到此错误:回溯(最近一次调用最后一次):文件“read_large_file.py”,第 24 行,在 掩码 = ((arr[:, 0] >= 0.807375) & (arr[:, 0]
    • 如果您将unpack=True 添加到对np.genfromtxt 的调用中,您可能会收到该错误,因为在这种情况下您将获得三个一维数组,col0col1col2一个二维数组,arr。在这种情况下,请使用mask = ((col0 &gt;= 0.807375) &amp; (col0 &lt;= 0.807982))
    • @ubuntu 我用 pastebin 中的数据尝试了你的解决方案(我编辑了问题并提供了链接),但它显示错误:数组索引过多!
    • @BhishanPoudel:啊,你发现了一个错误。如果只剩下一行,则np.genfromtxt 返回一个一维数组。由于数据文件有奇数行,在最后一次迭代中,arr 被分配给一维数组,arr[:, 0] 然后引发IndexError: too many indices for array。为了解决这个问题,我添加了arr = np.atleast_2d(arr) 以确保arr 始终是二维的。
    【解决方案3】:

    试试这个:

    import pandas as pd 
    
    df         = pd.read_csv('large_data.csv', usecols=(0,1,2), skiprows=57)
    df.columns = [ 'wave', 'flux' , 'err']
    df         = df[(df['wave'] >=  0.807375) & (df['wave'] <=  0.807982) ]
    print df 
    
         wave           flux              err
    1   0.807375    7.586660e-11    1.182880e-13
    2   0.807577    7.621360e-11    1.185040e-13
    3   0.807780    7.644910e-11    1.193890e-13
    4   0.807982    7.628580e-11    1.186850e-13
    

    由于您有一些不需要的文本行,您可以在导入时使用“skiprows”标志。此外,pandas 是建立在 numpy 之上的,所以有 chunksize 标志

    【讨论】:

    • 我已经为 python2 安装了 pandas,但是我收到了这个错误,AttributeError: 'module' object has no attribute 'read'
    • 刚刚编辑了上面应该让你开始。 7000 行并不是那么大,经验法则适用于我的磁盘大小在内存中的两倍大小。而且,不要更改 chunksize ,Pandas/Python 非常有效,已经浪费了很多时间尝试,从来没有真正有成果,
    • @BhishanPoudel 请使用 pastebin 中的数据并尝试消除错误!我不是为你聘请的开发人员,只是想帮助你。
    • 你需要学习如何调试代码,在别处重用.. 浏览代码,。它非常简单.. 使用打印语句。停止使用“!”,它表明需要采取行动。
    • Pandas 方法看起来简短、简单且有趣,但它会抛出以下错误:raise ValueError("Usecols do not match names.") ValueError: Usecols do not match names.
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-06-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多