Lỗi bộ nhớ khi sử dụng pandas read_csv


79

Tôi đang cố gắng làm một việc khá đơn giản, đọc một tệp csv lớn vào khung dữ liệu gấu trúc.

data = pandas.read_csv(filepath, header = 0, sep = DELIMITER,skiprows = 2)

Mã không thành công với một MemoryErrorhoặc không bao giờ kết thúc.

Việc sử dụng bản ghi nhớ trong trình quản lý tác vụ dừng lại ở 506 Mb và sau 5 phút không có thay đổi và không có hoạt động CPU nào trong quá trình này, tôi đã dừng nó.

Tôi đang sử dụng phiên bản gấu trúc 0.11.0.

Tôi biết rằng đã từng có sự cố bộ nhớ với trình phân tích cú pháp tệp, nhưng theo http://wesmckinney.com/blog/?p=543, điều này đã được khắc phục.

Tệp tôi đang cố đọc là 366 Mb, đoạn mã trên sẽ hoạt động nếu tôi cắt tệp xuống ngắn (25 Mb).

Nó cũng đã xảy ra rằng tôi nhận được một cửa sổ bật lên cho tôi biết rằng nó không thể viết thư đến địa chỉ 0x1e0baf93 ...

Stacktrace:

Traceback (most recent call last):
  File "F:\QA ALM\Python\new WIM data\new WIM data\new_WIM_data.py", line 25, in
 <module>
    wimdata = pandas.read_csv(filepath, header = 0, sep = DELIMITER,skiprows = 2
)
  File "C:\Program Files\Python\Anaconda\lib\site-packages\pandas\io\parsers.py"
, line 401, in parser_f
    return _read(filepath_or_buffer, kwds)
  File "C:\Program Files\Python\Anaconda\lib\site-packages\pandas\io\parsers.py"
, line 216, in _read
    return parser.read()
  File "C:\Program Files\Python\Anaconda\lib\site-packages\pandas\io\parsers.py"
, line 643, in read
    df = DataFrame(col_dict, columns=columns, index=index)
  File "C:\Program Files\Python\Anaconda\lib\site-packages\pandas\core\frame.py"
, line 394, in __init__
    mgr = self._init_dict(data, index, columns, dtype=dtype)
  File "C:\Program Files\Python\Anaconda\lib\site-packages\pandas\core\frame.py"
, line 525, in _init_dict
    dtype=dtype)
  File "C:\Program Files\Python\Anaconda\lib\site-packages\pandas\core\frame.py"
, line 5338, in _arrays_to_mgr
    return create_block_manager_from_arrays(arrays, arr_names, axes)
  File "C:\Program Files\Python\Anaconda\lib\site-packages\pandas\core\internals
.py", line 1820, in create_block_manager_from_arrays
    blocks = form_blocks(arrays, names, axes)
  File "C:\Program Files\Python\Anaconda\lib\site-packages\pandas\core\internals
.py", line 1872, in form_blocks
    float_blocks = _multi_blockify(float_items, items)
  File "C:\Program Files\Python\Anaconda\lib\site-packages\pandas\core\internals
.py", line 1930, in _multi_blockify
    block_items, values = _stack_arrays(list(tup_block), ref_items, dtype)
  File "C:\Program Files\Python\Anaconda\lib\site-packages\pandas\core\internals
.py", line 1962, in _stack_arrays
    stacked = np.empty(shape, dtype=dtype)
MemoryError
Press any key to continue . . .

Một chút thông tin cơ bản - Tôi đang cố gắng thuyết phục mọi người rằng Python có thể làm giống như R. Vì vậy, tôi đang cố gắng sao chép một tập lệnh R làm được

data <- read.table(paste(INPUTDIR,config[i,]$TOEXTRACT,sep=""), HASHEADER, DELIMITER,skip=2,fill=TRUE)

R không chỉ quản lý để đọc tốt các tệp ở trên, nó thậm chí còn đọc một số tệp này trong vòng lặp for (và sau đó thực hiện một số nội dung với dữ liệu). Nếu Python gặp sự cố với các tệp có kích thước như vậy, tôi có thể đang phải chiến đấu một trận thua ...


1
Chắc chắn gấu trúc không nên gặp vấn đề với csv có kích thước đó. Bạn có thể đăng tệp này trực tuyến không?
Andy Hayden

1
Bạn cũng có thể thử chuyển qua nrows=something smallđể read_csvđảm bảo rằng nó không phải là kích thước của tệp gây ra sự cố, như Andy đã nói, không nên như vậy.
TomAugspurger,

1
nó có thể là một cái gì đó để làm với "Visual Studio, sử dụng Anaconda và PTVS" ... có lẽ cố gắng trong python thường xuyên quá
Andy Hayden

3
Tôi đã tìm ra cách sau để giải quyết vấn đề: Đọc csv dưới dạng các đoạn csv_chunks = pandas.read_csv(filepath, sep = DELIMITER,skiprows = 1, chunksize = 10000), sau đó nối các đoạn df = pandas.concat(chunk for chunk in csv_chunks). Tôi vẫn muốn biết tại sao đọc nó một lượt không hiệu quả, đối với tôi, điều này có vẻ như là một vấn đề với trình đọc csv.
Anne

11
Nếu ai vẫn đang theo dõi điều này, tôi có một chút cập nhật. Tôi đã tin rằng trình phân tích cú pháp csv tốt (và rất nhanh), nhưng có một số vấn đề về bộ nhớ khi tạo khung dữ liệu. Lý do tôi tin vào điều này: Khi tôi sử dụng chunksize=1000hack để đọc csv, và sau đó thử nối tất cả các phần vào một khung dữ liệu lớn, thì chính tại thời điểm này, bộ nhớ sẽ tăng lên, với khoảng 3-4 lần dấu chân bộ nhớ so với kích thước của tệp gốc. Có ai có ý tưởng tại sao khung dữ liệu có thể bị nổ tung không?
Anne,

Câu trả lời:


32

Giới hạn bộ nhớ Windows

Lỗi bộ nhớ xảy ra rất nhiều với python khi sử dụng phiên bản 32bit trong Windows. Điều này là do các quy trình 32 bit chỉ có bộ nhớ 2GB để chơi theo mặc định.

Thủ thuật giảm mức sử dụng bộ nhớ

Nếu bạn không sử dụng python 32bit trong windows nhưng đang muốn cải thiện hiệu quả bộ nhớ khi đọc tệp csv, thì có một mẹo nhỏ.

Hàm pandas.read_csv nhận một tùy chọn được gọi là dtype. Điều này cho phép gấu trúc biết những loại nào tồn tại bên trong dữ liệu csv của bạn.

Cách thức hoạt động

Theo mặc định, gấu trúc sẽ cố gắng đoán định dạng tệp csv của bạn. Đây là một thao tác rất nặng vì trong khi xác định loại dữ liệu, nó phải giữ tất cả dữ liệu thô dưới dạng các đối tượng (chuỗi) trong bộ nhớ.

Thí dụ

Giả sử csv của bạn trông giống như sau:

name, age, birthday
Alice, 30, 1985-01-01
Bob, 35, 1980-01-01
Charlie, 25, 1990-01-01

Ví dụ này tất nhiên không có vấn đề gì khi đọc vào bộ nhớ, nhưng nó chỉ là một ví dụ.

Nếu gấu trúc đọc tệp csv ở trên mà không có bất kỳ tùy chọn loại nào, tuổi sẽ được lưu trữ dưới dạng chuỗi trong bộ nhớ cho đến khi gấu trúc đọc đủ số dòng của tệp csv để đưa ra phỏng đoán đủ điều kiện.

Tôi nghĩ rằng mặc định ở gấu trúc là đọc 1.000.000 hàng trước khi đoán loại dtype.

Giải pháp

Bằng cách chỉ định dtype={'age':int}như một tùy chọn cho ý .read_csv()muốn cho gấu trúc biết rằng tuổi nên được hiểu là một con số. Điều này giúp bạn tiết kiệm rất nhiều bộ nhớ.

Sự cố với dữ liệu bị hỏng

Tuy nhiên, nếu tệp csv của bạn bị hỏng, như sau:

name, age, birthday
Alice, 30, 1985-01-01
Bob, 35, 1980-01-01
Charlie, 25, 1990-01-01
Dennis, 40+, None-Ur-Bz

Sau đó, chỉ định dtype={'age':int}sẽ phá vỡ .read_csv()lệnh, vì nó không thể "40+"chuyển thành int. Vì vậy, hãy khử trùng dữ liệu của bạn một cách cẩn thận!

Ở đây, bạn có thể thấy mức độ sử dụng bộ nhớ của khung dữ liệu gấu trúc cao hơn rất nhiều khi các phao được giữ dưới dạng chuỗi:

Hãy thử nó cho mình

df = pd.DataFrame(pd.np.random.choice(['1.0', '0.6666667', '150000.1'],(100000, 10)))
resource.getrusage(resource.RUSAGE_SELF).ru_maxrss
# 224544 (~224 MB)

df = pd.DataFrame(pd.np.random.choice([1.0, 0.6666667, 150000.1],(100000, 10)))
resource.getrusage(resource.RUSAGE_SELF).ru_maxrss
# 79560 (~79 MB)

Tôi có thể thấy cách này có thể tăng tốc độ đọc dữ liệu, nhưng làm giảm bộ nhớ? Chắc chắn nó không cần phải lưu trữ nhiều hơn một vài chuỗi giá trị trên mỗi cột để đoán kiểu dữ liệu? Tức là, trừ khi bạn có một bazillion cột, hoặc read_csvhàm đang làm điều gì đó cực kỳ thú vị, tôi sẽ rất ngạc nhiên nếu mức sử dụng bộ nhớ cao hơn đáng kể.
Hannes Ovrén

2
@ HannesOvrén Không thể đoán được kiểu dữ liệu trước khi bạn đọc một phần quan trọng của dữ liệu, nếu không, bạn có nguy cơ phải thay đổi nó nhiều lần, điều này làm tăng chi phí. Tôi nghĩ rằng gấu trúc theo mặc định đọc hàng triệu hàng đầu tiên trước khi đưa ra phỏng đoán. Tôi đã giảm hồ sơ bộ nhớ của sản phẩm dựa trên gấu trúc của chúng tôi xuống gấp 50 lần bằng cách thêm các loại vào tải csv.
firelynx,

1
Hmm, suy nghĩ về nó, tôi đoán có thể có vấn đề khi quyết định xem "3" sẽ là float hay int trừ khi bạn cũng nhìn thấy "2,5" ở đâu đó. Cảm ơn vì lời giải thích. Tôi không biết về điều này.
Hannes Ovrén

Đây không phải là sự thật. Với dtype là và trong bộ nhớ đắt hơn và trong thời gian chậm hơn. Đã kiểm tra 6 lần với dtype trong read_csv. Trung bình là: ... memory no dtype: 12,121,429.333333334 | bộ nhớ với loại: 12,124,160.0 ... Trong thời gian được kiểm tra 13 lần, Trung bình là: ... thời gian không có loại: 2.0494697460761437 | time with dtypes: 2.100334332539485 ... Đã sử dụng: import os import psutil process = psutil.Process (os.getpid ()) print (process.memory_info (). rss) ___ Hàng dữ liệu: 1,5 triệu từ ba tập dữ liệu riêng biệt, cols 90% là loại Đối tượng. * Rõ ràng phao còn ít kích thước so với kiểu chuỗi
nikolaosmparoutis

@nikolaos_mparoutis Không chắc bạn đã xem những kết quả này như thế nào. Có thể bạn muốn viết câu trả lời của riêng mình vì rất khó để theo dõi đâu là mã và đâu là chú thích trong bình luận của bạn. Câu trả lời của tôi là khá cũ, có lẽ một cái gì đó đã thay đổi.
firelynx

6

Tôi đã gặp phải vấn đề bộ nhớ tương tự với một lần đọc đơn giản tệp văn bản được phân cách bằng tab có kích thước khoảng 1 GB (hơn 5,5 triệu bản ghi) và điều này đã giải quyết được sự cố bộ nhớ :

df = pd.read_csv(myfile,sep='\t') # didn't work, memory error
df = pd.read_csv(myfile,sep='\t',low_memory=False) # worked fine and in less than 30 seconds

Spyder 3.2.3 Python 2.7.13 64bits


7
Nó là phản trực giác low_memory=Falsenên sử dụng ít bộ nhớ hơn ..
guildlefix

2

Tôi sử dụng Pandas trên hộp Linux của mình và phải đối mặt với nhiều lỗi rò rỉ bộ nhớ chỉ được giải quyết sau khi nâng cấp Pandas lên phiên bản mới nhất sau khi sao chép nó từ github.


1

Tôi cũng gặp phải sự cố này khi tôi đang chạy trong một máy ảo hoặc máy ảo nào đó khác, nơi bộ nhớ bị giới hạn rõ rệt. Nó không liên quan gì đến gấu trúc hoặc numpy hoặc csv, nhưng sẽ luôn xảy ra nếu bạn cố gắng sử dụng nhiều bộ nhớ hơn vì bạn được phép sử dụng, thậm chí không chỉ trong python.

Cơ hội duy nhất bạn có là những gì bạn đã cố gắng, hãy cố gắng chia nhỏ thứ lớn thành những phần nhỏ vừa với trí nhớ.

Nếu bạn từng hỏi bản thân MapReduce là gì, bạn đã tự tìm hiểu ... MapReduce sẽ cố gắng phân phối các phần trên nhiều máy, bạn sẽ cố gắng xử lý lần lượt các phần trên máy này.

Những gì bạn phát hiện ra với việc nối các tệp chunk thực sự có thể là một vấn đề, có thể cần một số bản sao trong thao tác này ... nhưng cuối cùng, điều này có thể giúp bạn tiết kiệm trong tình huống hiện tại nhưng nếu csv của bạn lớn hơn một chút bạn có thể lại chạy vào bức tường đó ...

Nó cũng có thể là, con gấu trúc rất thông minh, nó thực sự chỉ tải các khối dữ liệu riêng lẻ vào bộ nhớ nếu bạn làm gì đó với nó, chẳng hạn như nối với một df lớn?

Một số điều bạn có thể thử:

  • Không tải tất cả dữ liệu cùng một lúc mà hãy chia thành nhiều phần
  • Theo như tôi biết, hdf5 có thể tự động thực hiện các phần này và chỉ tải phần chương trình của bạn hiện đang hoạt động
  • Xem các loại có ổn không, một chuỗi '0.111111' cần nhiều bộ nhớ hơn một float
  • Thực ra bạn cần gì, nếu có địa chỉ là một chuỗi, bạn có thể không cần nó để phân tích số ...
  • Cơ sở dữ liệu có thể giúp đánh giá và chỉ tải những phần bạn thực sự cần (ví dụ: chỉ 1% người dùng đang hoạt động)

1

Không có lỗi cho Pandas 0.12.0 và NumPy 1.8.0.

Tôi đã quản lý để tạo một DataFrame lớn và lưu nó vào tệp csv và sau đó đọc thành công. Vui lòng xem ví dụ ở đây . Kích thước của tệp là 554 Mb (Nó thậm chí hoạt động với tệp 1,1 Gb, mất nhiều thời gian hơn, để tạo ra tần suất sử dụng tệp 1,1Gb là 30 giây). Mặc dù tôi có sẵn 4Gb RAM.

Đề xuất của tôi là thử cập nhật Pandas. Một điều khác có thể hữu ích là hãy thử chạy tập lệnh của bạn từ dòng lệnh, vì đối với R bạn không sử dụng Visual Studio (điều này đã được đề xuất trong phần nhận xét cho câu hỏi của bạn), do đó nó có sẵn nhiều tài nguyên hơn.


1

Tôi đã thử chunksizekhi đọc tệp CSV lớn

reader = pd.read_csv(filePath,chunksize=1000000,low_memory=False,header=0)

Đọc bây giờ là danh sách. Chúng tôi có thể lặp lại readervà ghi / nối vào csv mới hoặc có thể thực hiện bất kỳ hoạt động nào

for chunk in reader:
    print(newChunk.columns)
    print("Chunk -> File process")
    with open(destination, 'a') as f:
        newChunk.to_csv(f, header=False,sep='\t',index=False)
        print("Chunk appended to the file")

0

Thêm những thứ này: xếp hạng = pd.read_csv (..., low_memory = False, memory_map = True )

Bộ nhớ của tôi với hai cái này: # 319.082.496 Không có hai cái này: # 349.110.272


-1

Mặc dù đây là một giải pháp thay thế không phải là một giải pháp khắc phục, nhưng tôi sẽ thử chuyển đổi CSV đó sang JSON (phải là tầm thường) và sử dụng read_jsonphương pháp thay thế - Tôi đã viết và đọc JSON / dataframe khá lớn (100 MB) trong Pandas this cách mà không có bất kỳ vấn đề ở tất cả.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.