使用to_csv时如何处理pandas内存错误?

Posted

技术标签:

【中文标题】使用to_csv时如何处理pandas内存错误?【英文标题】:How to deal with pandas memory error when using to_csv? 【发布时间】:2019-11-11 05:18:49 【问题描述】:

我目前正在 linux 系统中运行一个脚本。该脚本读取大约 6000 行的 csv 作为数据帧。脚本的工作是转换一个数据框,例如:

name       children
Bob        [Jeremy, Nancy, Laura]
Jennifer   [Kevin, Aaron]

到:

name       children                 childName
Bob        [Jeremy, Nancy, Laura]   Jeremy
Bob        [Jeremy, Nancy, Laura]   Nancy
Bob        [Jeremy, Nancy, Laura]   Laura
Jennifer   [Kevin, Aaron]           Kevin
Jennifer   [Kevin, Aaron]           Aaron

并将其写入另一个文件(原始 csv 保持不变)。

基本上添加一个新列并为列表中的每个项目创建一行。 请注意,我正在处理一个包含 7 列的数据框,但出于演示目的,我使用了一个较小的示例。我的实际 csv 中的列都是字符串,除了两个是列表。

这是我的代码:


import ast
import os
import pandas as pd

cwd = os.path.abspath(__file__+"/..")
data= pd.read_csv(cwd+"/folded_data.csv", sep='\t', encoding="latin1")
output_path = cwd+"/unfolded_data.csv"

out_header = ["name", "children", "childName"]
count = len(data)
for idx, e in data.iterrows():
    print("Row ",idx," out of ",count)
    entry = e.values.tolist()
    c_lst = ast.literal_eval(entry[1])

    for c in c_lst :
        n_entry = entry + [c]
        if os.path.exists(output_path):
            output = pd.read_csv(output_path, sep='\t', encoding="latin1")
        else:
            output = pd.DataFrame(columns=out_header)

        output.loc[len(output)] = n_entry
        output.to_csv(output_path, sep='\t', index=False)

但我收到以下错误:

Traceback (most recent call last):
  File "fileUnfold.py", line 31, in <module>
    output.to_csv(output_path, sep='\t', index=False)
  File "/usr/local/lib/python3.5/dist-packages/pandas/core/generic.py", line 3020, in to_csv
    formatter.save()
  File "/usr/local/lib/python3.5/dist-packages/pandas/io/formats/csvs.py", line 172, in save
    self._save()
  File "/usr/local/lib/python3.5/dist-packages/pandas/io/formats/csvs.py", line 288, in _save
    self._save_chunk(start_i, end_i)
  File "/usr/local/lib/python3.5/dist-packages/pandas/io/formats/csvs.py", line 315, in _save_chunk
    self.cols, self.writer)
  File "pandas/_libs/writers.pyx", line 75, in pandas._libs.writers.write_csv_rows
MemoryError

还有其他方法可以在不出现此错误的情况下做我想做的事情吗?

编辑:如果你想看一下 csv 文件https://media.githubusercontent.com/media/lucas0/Annotator/master/annotator/data/folded_snopes.csv

EDIT2:我目前正在使用

with open(output_path, 'w+') as f:
            output.to_csv(f, index=False, header=True, sep='\t')

在第 98 行左右,程序开始显着减速。我很确定这是因为随着文件变大,我会一遍又一遍地阅读文件。我怎样才能在文件中追加一行而不读取它?

EDIT3:这是我用来处理第一次编辑中链接的数据的实际代码。这可能会更容易回答。

import ast
import os
import pandas as pd

cwd = os.path.abspath(__file__+"/..")
snopes = pd.read_csv(cwd+"/folded_snopes.csv", sep='\t', encoding="latin1")
output_path = cwd+"/samples.csv"

out_header = ["page", "claim", "verdict", "tags", "date", "author","source_list","source_url"]
count = len(snopes)
for idx, e in snopes.iterrows():
    print("Row ",idx," out of ",count)
    entry = e.values.tolist()
    src_lst = ast.literal_eval(entry[6])

    for src in src_lst:
        n_entry = entry + [src]
        if os.path.exists(output_path):
            output = pd.read_csv(output_path, sep='\t', encoding="latin1")
        else:
            output = pd.DataFrame(columns=out_header)

        output.loc[len(output)] = n_entry
        with open(output_path, 'w+') as f:
            output.to_csv(f, index=False, header=True, sep='\t')

【问题讨论】:

7 列和 6000 行现在应该不会在任何合理的 PC 上引起内存问题。你没有给出一个容易测试的例子,但如果它像 n_entry = entry + [c] 这样的东西在列表中的列表结束时会炸毁内存,我不会感到惊讶 @roganjosh 我添加了一个指向数据的链接,如果你想看看 这里有什么真正的理由使用熊猫吗?您可以使用标准库 csv 模块非常有效地完成此任务。 @juanpa.arrivillaga 一些数据本身有标签。我是一名实习生,我的主管(谁给了我这些数据)告诉我只使用 pandas,因为它可以处理这些问题。我使用的是正常的打开和写入,但由于第 1000 行周围的数据格式不正确,因此无法正常工作。 @MohamadMoustafa 您能否在 df = df[:-1] 的帮助下将最后一行作为临时解决方案删除并检查我的答案? 【参考方案1】:

我停止读取输出文件,并停止为每个源写入。相反,我为输入数据的每一行创建了一个包含新行的数据框,然后将其附加到 samples.csv。

代码:

import ast
import os
import pandas as pd

cwd = os.path.abspath(__file__+"/..")
snopes = pd.read_csv(cwd+"/folded_snopes.csv", sep='\t', encoding="latin1")
output_path = cwd+"/samples.csv"

out_header = ["page", "claim", "verdict", "tags", "date", "author","source_list","source_url"]
count = len(snopes)
is_first = True

for idx, e in snopes.iterrows():
    print("Row ",idx," out of ",count)
    entry = e.values.tolist()
    src_lst = ast.literal_eval(entry[6])
    output = pd.DataFrame(columns=out_header)
    for src in src_lst:
        n_entry = entry + [src]
        output.loc[len(output)] = n_entry

    output.to_csv(output_path, sep='\t', header=is_first, index=False, mode='a')
    is_first = False

【讨论】:

【参考方案2】:

尝试打开以便记忆,也许可以解决它。

我怎样才能在文件中追加一行而不读取它?

from pathlib import Path

output_path= Path("/yourfolder/path")
with open(path1, 'w',  newline='') as f1, open(path2, 'r') as f2:
    file1= csv.writer(f1)
    #output.to_csv(f, header=False, sep=';') 
    file2 = csv.reader(f4)
    i = 0
    for row in file2:
        row.insert(1,output[i])
        file1.writerow(row)
        i += 1

【讨论】:

什么是df?和test.csv?请编辑您对此方案的答案(使用适当的名称) 当然,df 是你的数据框,test.csv 是你的 output_path。 在这里使用 a+ 是不正确的,因为我们正在读取、添加然后覆盖 csv 文件。不附加。

以上是关于使用to_csv时如何处理pandas内存错误?的主要内容,如果未能解决你的问题,请参考以下文章

由于内存导致重新分配失败时如何处理?

合并发布者时如何处理错误?

使用app.get调用错误端点时如何处理?

使用 Kafka Streams DSL 时如何处理错误和不提交

执行 Flux.map() 时如何处理错误

使用 DataGridView 控件和 Access 数据库查询时如何处理错误?