在python中按顺序读取巨大的CSV文件

时间:2017-03-20 10:07:32

标签: python csv pandas

我有一个10GB的CSV文件,其中包含我需要使用的一些信息。

由于我的电脑内存有限,我无法一次性读取内存中的所有文件。相反,我想迭代地只读取该文件的某些行。

假设在第一次迭代中我想要读取前100个,第二次转到101到200,依此类推。

有没有一种有效的方法在Python中执行此任务? 五月熊猫能提供一些有用的东西吗?或者有更好的(在记忆和速度方面)方法?

4 个答案:

答案 0 :(得分:8)

这是简短的回答。

chunksize = 10 ** 6
for chunk in pd.read_csv(filename, chunksize=chunksize):
    process(chunk)

这是一个很长的答案。

要开始使用,您需要导入pandas和sqlalchemy。以下命令可以做到这一点。

import pandas as pd
from sqlalchemy import create_engine

接下来,设置一个指向csv文件的变量。这不是必要的,但它确实有助于重复使用。

file = '/path/to/csv/file'

通过这三行代码,我们可以开始分析我们的数据了。让我们看一下csv文件的“head”,看看它们的内容是什么样的。

print pd.read_csv(file, nrows=5)

此命令使用pandas的“read_csv”命令仅读取5行(nrows = 5),然后将这些行打印到屏幕上。这使您可以了解csv文件的结构,并确保以对您的工作有意义的方式格式化数据。

在我们实际使用数据之前,我们需要对它做一些事情,以便我们可以开始过滤它以使用数据的子集。这通常是我使用pandas的数据帧,但对于大数据文件,我们需要将数据存储在其他地方。在这种情况下,我们将设置一个本地sqllite数据库,以块的形式读取csv文件,然后将这些块写入sqllite。

为此,我们首先需要使用以下命令创建sqllite数据库。

csv_database = create_engine('sqlite:///csv_database.db')

接下来,我们需要以块的形式遍历CSV文件并将数据存储到sqllite中。

chunksize = 100000
i = 0
j = 1
for df in pd.read_csv(file, chunksize=chunksize, iterator=True):
      df = df.rename(columns={c: c.replace(' ', '') for c in df.columns}) 
      df.index += j
      i+=1
      df.to_sql('table', csv_database, if_exists='append')
      j = df.index[-1] + 1

使用此代码,我们将chunksize设置为100,000以保持块的大小可管理,初始化几个迭代器(i = 0,j = 0)然后运行for循环。 for循环从CSV文件中读取一块数据,从任何列名中删除空格,然后将块存储到sqllite数据库中(df.to_sql(...))。

如果您的CSV文件足够大,这可能需要一段时间,但等待的时间是值得的,因为您现在可以使用pandas的'sql'工具从数据库中提取数据而不必担心内存限制。

要立即访问数据,您可以运行如下命令:

df = pd.read_sql_query('SELECT * FROM table', csv_database)

当然,使用'select * ...'会将所有数据加载到内存中,这是我们试图摆脱的问题所以你应该从过滤器中抛出你的select语句来过滤数据。例如:

df = pd.read_sql_query('SELECT COl1, COL2 FROM table where COL1 = SOMEVALUE', csv_database)

答案 1 :(得分:6)

您可以将pandas.read_csv()chuncksize参数一起使用:

http://pandas.pydata.org/pandas-docs/stable/generated/pandas.read_csv.html#pandas.read_csv

for chunck_df in pd.read_csv('yourfile.csv', chunksize=100):
    # each chunck_df contains a part of the whole CSV

答案 2 :(得分:0)

将大量CSV传输到数据库中的方法很好,因为我们可以轻松地使用SQL查询。 我们还必须考虑两件事。

第一个要点: SQL也不是橡皮筋,它将无法扩展内存。

例如转换为bd file

https://nycopendata.socrata.com/Social-Services/311-Service-Requests- 从2010年到现在/ erm2-nwe9

对于此数据库文件SQL语言:

pd.read_sql_query("SELECT * FROM 'table'LIMIT 600000", Mydatabase)

使用16 GB的PC RAM内存(操作时间15.8秒),最多可以读取约0.6百万条记录。 补充一下,直接从csv文件下载效率更高一点可能是恶意的:

giga_plik = 'c:/1/311_Service_Requests_from_2010_to_Present.csv'
Abdul = pd.read_csv(giga_plik, nrows=1100000)

(操作时间16.5秒)

第二点::要有效地使用从CSV转换的SQL数据系列,我们应该将适当的日期格式存储到内存中。所以我提议者将以下内容添加到ryguy72的代码中:

df['ColumnWithQuasiDate'] = pd.to_datetime(df['Date'])

文件311中关于我指出的所有代码:

start_time = time.time()
### sqlalchemy create_engine
plikcsv = 'c:/1/311_Service_Requests_from_2010_to_Present.csv'
WM_csv_datab7 = create_engine('sqlite:///C:/1/WM_csv_db77.db')
#----------------------------------------------------------------------
chunksize = 100000 
i = 0
j = 1
## --------------------------------------------------------------------
for df in pd.read_csv(plikcsv, chunksize=chunksize, iterator=True, encoding='utf-8', low_memory=False):
      df = df.rename(columns={c: c.replace(' ', '') for c in df.columns}) 
## -----------------------------------------------------------------------
      df['CreatedDate'] = pd.to_datetime(df['CreatedDate'])  # to datetimes
      df['ClosedDate'] = pd.to_datetime(df['ClosedDate'])
## --------------------------------------------------------------------------
      df.index += j
      i+=1
      df.to_sql('table', WM_csv_datab7, if_exists='append')
      j = df.index[-1] + 1
print(time.time() - start_time)

最后,我想补充一点:将csv文件直接从Internet转换为db在我看来是个坏主意。我建议下载基准并在本地转换。

答案 3 :(得分:0)

此代码可以帮助您完成此任务。它可浏览大型.csv文件,并且不会占用大量内存,因此您可以在标准笔记本电脑中执行此操作。

import pandas as pd
import os

此处的块大小对要稍后读取的csv文件中的行数进行排序

chunksize2 = 2000

path = './'
data2 = pd.read_csv('ukb35190.csv',
                chunksize=chunksize2,
                encoding = "ISO-8859-1")
df2 = data2.get_chunk(chunksize2)
headers = list(df2.keys())
del data2

start_chunk = 0
data2 = pd.read_csv('ukb35190.csv',
                chunksize=chunksize2,
                encoding = "ISO-8859-1",
                skiprows=chunksize2*start_chunk)

标题= []

for i, df2 in enumerate(data2):
try:

    print('reading cvs....')
    print(df2)
    print('header: ', list(df2.keys()))
    print('our header: ', headers)

    # Access chunks within data

    # for chunk in data:

    # You can now export all outcomes in new csv files
    file_name = 'export_csv_' + str(start_chunk+i) + '.csv'
    save_path = os.path.abspath(
        os.path.join(
            path, file_name
        )
    )
    print('saving ...')

except Exception:
    print('reach the end')
    break