我正在分析一些非常大的檔案(約2億行)
csv_filename=pd.read_csv('filename.txt',sep=" ", error_bad_lines=False)
程式運行了大約半小時后,我得到了這樣的錯誤資訊:
MemoryError: Unable to allocate 3.25 GiB for an array with shape (7, 62388743) and資料type object
我想知道是否有辦法繞過這個記憶體錯誤,或者是否有一個不同的函式我可以使用,不需要那么多的記憶體?我已經將檔案分成了幾塊,但問題是我需要將所有的資料放在一個資料框中,以便我可以將其作為一個整體進行分析。
uj5u.com熱心網友回復:
你可以找一臺有更多記憶體的電腦,簡化/匯總資料,或者嘗試不同的工具。
如果我在做這件事,處理一個這么大的檔案,我會切換到 Spark 并使用 PySpark API。
PySpark 將使您能夠在超過機器上的可用記憶體時使用 pandas 操作。 這對于大資料操作來說是非常好的。
http://spark.apache.org/docs/latest/api/python/
uj5u.com熱心網友回復:
在[49]。7*62388743*8/1e9。
Out[49]。3.493769608
這就是你的3.25GiB。 這僅僅是指向物件的指標。
('field1', dtype('int64')) ('field2', dtype('int64')) ('field3', dtype('O')) ('field4', dtype('O')) ('field5', dtype('O')) ('field6', dtype('O')) ('field7', dtype('O')) ('field8', dtype('O')) ('field9', dtype('O')) ('field10', dtype('int64')) ('field11', dtype('float64')) ('field12', dtype('int64')
我計算了7個dtype('O')欄位;這可能是形狀中7的原因;另一個值我認為是行。 int64和float欄位將被放在他們自己的陣列中。
在pandas中,帶有字串的列是物件dtype;也就是說,它將字串存盤為普通的Python字串,因此需要指標。
通過該欄位串列,1,10,11,12都是數字。 但是同樣的,pandas如果內容不 "正確",可能會把它們改為物件,有字串、無、NA等等。
uj5u.com熱心網友回復:
你可以用usecols限制列的數量。這將減少記憶體的占用。你在CSV檔案中似乎也有一些不好的資料,使得你認為應該是int64的列變成了object。這些可能是空單元格,或任何非數字值。這里有一個例子,它將讀取csv,然后掃描不良資料。這個例子使用逗號,而不是制表符,因為這樣更容易演示。
import pandas as pd
import numpy as np
import io
import re
test_csv = io.StringIO(""field1,field2,field3,other
1,2,3,這個
4,什么?,6,是
7,,9,額外"")
_numbers_re = re.compile(r "d $"/span>)
df = pd.read_csv(test_csv,sep=",", error_bad_lines=False,
usecols=['field1'/span>, 'field2'/span>, 'field3'/span>])
print(df)
# columns that arent int64
bad_cols = list(df.dtypes[df.dtypes!=np.dtype('int64'/span>)].index)
if bad_cols:
print("bad cols"/span>, bad_cols)
for bad_col in bad_cols:
col = df[bad_col]
bad = col[col.str.match(_numbers_re) != True]
print(bad)
exit(1)
uj5u.com熱心網友回復:
你可以逐行讀取你的csv檔案,并在消耗迭代器的同時計算指標,而不增加記憶體用量。但你不需要從頭開始做(見下文)。
看看convtools,它是一個輕量級的python庫,它允許你定義轉換,當你完成后,它寫&;在引擎蓋下編譯臨時的python代碼,所以你有函式來做你想要的事情。
我生成了一個測驗的csv檔案(81MB;2M行;3列),使用了下面的代碼
。import csv
from tqdm import tqdm
from random import random, choice
field_1_values = [
"abcde1234567890",
"cde1234567890",
"def1234567890",
"fgh1234567890",
]
with open("input_data-small.csv"/span>, "w"/span>) as f:
writer = csv.writer(f)
writer.writerow(["field_1"/span>, "field_2"/span>, "field_3"/span>] )
for index in tqdm(range(2000000))。)
writer.writerow([choice(field_1_values), random(), index])
讓我們用convtools來處理它,以找到例如:
- field_1的唯一值 欄位_2的第一個值
- 欄位_2的最大值
- 欄位_2的最大值
- 欄位_2的最大值
- 欄位2的最大值
- 欄位2的最小值
- 持有field_2的最小值的行 。
import csv
# pip install convtools
from convtools import conversion as c
# pip install tqdm (for a nice progress bar)
from tqdm import tqdm
# define optional conversions to prepare data
column_to_prepare_conversion = {
"field_2": c.this().as_type(float)。
"field_3": c.call_func(int, c.this() 。)
}
with open("input_data-small.csv"/span>, "r"/span>) as f:
# csv.DictReader很慢,所以讓我們使用原始行。
reader = csv.reader(f)
# fetch column names
column_names = next(reader)
# 添加一些免費的語法糖(在編譯代碼中沒有開銷):
# 允許通過名字來參考列,而索引則是在后臺使用的。
def column_(column_name)。
return c.item(column_names.index(column_name))
if column_to_prepare_conversion:
prepare_input = c.iter(
# creates iterable of prepared tuples.
tuple(
column_(column_name).pipe(
column_to_prepare_conversion[column_name] 。
)
if column_name in column_to_prepare_conversion
else column_(column_name)
for column_name in column_names
)
)
else:
prepare_input = c.this()
# let's aggregate something: prepare_input = c.this()
converter = prepare_input.pipe(
# 當然也有group_by: https://convtools.readthedocs.io/en/latest/cheatsheet.html#group-by-simple
c.aggregation(
{
"unique_field_1"/span>: c.ReduceFuncs.ArrayDistinct(
column_("field_1")
),
"first_field_2": c.ReduceFuncs.First(column_("field_2") ) 。
"max_field_2": c.ReduceFuncs.Max(column_("field_2") )。)
"avg_field_2": c.ReduceFuncs.Average(column_("field_2") )。)
"row_with_min_field_2": c.ReduceFuncs.MinRow(
column_("field_2")
),
}
)
).gen_converter(
# 如果安裝了黑色,將列印黑色格式的代碼。
debug=True。
)
結果 = converter(tqdm(reader))
print(results)
結果:
# 2000000it [00:04, 462371.13it/s]/span>
{
"unique_field_1": [
"cde1234567890",
"fgh1234567890",
"abcde1234567890",
"def1234567890",
],
"first_field_2": 4.149475385772927e-05,
"max_field_2": 0.9999996797416377,
"avg_field_2": 0.49995239963138766,
"row_with_min_field_2": ("fgh1234567890", 3.6033313821626223e-07, 425211) 。
}
因此,如果我的測驗檔案有200個銑削行,處理462K行/秒,將需要~433秒(7分鐘13秒)。
JFYI:在沒有任何資料準備和計算的情況下,簡單的檔案讀取需要~203秒(3分23秒):
標籤:with open("input_data-small.csv"/span>, "r"/span>) as f:
reader = csv.reader(f)
for row in tqdm(reader):
pass
# 2000001it [00:02, 983404.81it/s]/span>
