আমি কীভাবে কোনও পান্ডাস ডেটাফ্রেমে ব্যবহৃত মেমরি প্রকাশ করব?


111

আমার কাছে সত্যিই একটি বৃহত সিএসভি ফাইল রয়েছে যা আমি নীচে প্যান্ডাসে খুললাম ...

import pandas
df = pandas.read_csv('large_txt_file.txt')

একবার আমি এটি করলে আমার মেমরির ব্যবহার 2 জিবি দ্বারা বৃদ্ধি পায় যা প্রত্যাশিত কারণ এই ফাইলটিতে কয়েক মিলিয়ন সারি রয়েছে। আমার সমস্যাটি তখন আসে যখন আমাকে এই স্মৃতিটি প্রকাশ করতে হবে। আমি দৌড়ে গেলাম ....

del df

তবে আমার স্মৃতি ব্যবহার কমেনি usage কোনও প্যান্ডাস ডেটা ফ্রেমের দ্বারা ব্যবহৃত মেমোরিটি প্রকাশের জন্য এটি কি ভুল পদ্ধতি? যদি তা হয় তবে সঠিক উপায় কী?


3
এটি সঠিক, আবর্জনা সংগ্রাহক সরাসরি মেমরিটি মুক্তি নাও দিতে পারেন, আপনি gcgc.collect()
মডিউলটিও

del dfসরাসরি ডেফ তৈরির পরে ডাকা হয় না? আমি মনে করি আপনি df মুছতে পয়েন্টে df এর উল্লেখ রয়েছে। সুতরাং এটি মুছে ফেলা হবে পরিবর্তে এটি নাম মুছে দেয়।
মারলন অ্যাবাইকুন

4
আবর্জনা সংগ্রহকারী দ্বারা পুনরুদ্ধার করা মেমরিটি আসলে ওএসকে ফিরিয়ে দেওয়া হয় কিনা তা বাস্তবায়ন নির্ভর; আবর্জনা সংগ্রাহকের একমাত্র গ্যারান্টি হ'ল দাবি করা মেমরিটি বর্তমান পাইথন প্রক্রিয়াটি ওএস থেকে জিজ্ঞাসা বা আরও বেশি মেমরির পরিবর্তে অন্যান্য জিনিসের জন্য ব্যবহার করতে পারে ।
চিপনার

আমি সৃষ্টির ঠিক পরে ডেল ডিএফ কল করছি। আমি ডিএফ-তে অন্য কোনও উল্লেখ যুক্ত করিনি। আমি যা করেছি তা সবই আইপিথন খোলা ছিল এবং কোডের এই তিনটি লাইন চালানো হয়েছিল। যদি আমি একই কোডটি অন্য কোনও অবজেক্টে চালিত করি যা প্রচুর মেমোরি নেয়, যেমন একটি নম্র অ্যারে বলে। del nparray পুরোপুরি কাজ করে
b10hazard

@ বি 10hazard: df = ''আপনার কোড শেষে এমন কিছু সম্পর্কে কী ? ডেটাফ্রেমে ব্যবহৃত র‌্যাম সাফ করার মত মনে হচ্ছে।
jibounet

উত্তর:


119

পাইথনে মেমরির ব্যবহার হ্রাস করা কঠিন, কারণ পাইথন আসলে অপারেটিং সিস্টেমে মেমরিটি ফিরে দেয় না । যদি আপনি অবজেক্টগুলি মুছুন, তবে মেমরিটি নতুন পাইথন অবজেক্টের জন্য উপলব্ধ, তবে free()সিস্টেমে ফিরে আসবে না ( এই প্রশ্নটি দেখুন )।

যদি আপনি সংখ্যাসূচক অ্যারেগুলিতে আটকে থাকেন তবে সেগুলি মুক্ত হয় তবে বাক্সযুক্ত বস্তুগুলি তা নয়।

>>> import os, psutil, numpy as np
>>> def usage():
...     process = psutil.Process(os.getpid())
...     return process.get_memory_info()[0] / float(2 ** 20)
... 
>>> usage() # initial memory usage
27.5 

>>> arr = np.arange(10 ** 8) # create a large array without boxing
>>> usage()
790.46875
>>> del arr
>>> usage()
27.52734375 # numpy just free()'d the array

>>> arr = np.arange(10 ** 8, dtype='O') # create lots of objects
>>> usage()
3135.109375
>>> del arr
>>> usage()
2372.16796875  # numpy frees the array, but python keeps the heap big

ডেটা ফ্রেমের সংখ্যা হ্রাস করা হচ্ছে

পাইথন আমাদের স্মৃতিশক্তিটিকে উচ্চ ওয়াটারমার্কে রাখে তবে আমরা তৈরি ডেটা ফ্রেমের সংখ্যাটি হ্রাস করতে পারি। আপনার ডেটাফ্রেমটি সংশোধন করার সময়, পছন্দ করুন inplace=True, যাতে আপনি অনুলিপি তৈরি করেন না।

আরেকটি সাধারণ গোচা আইপথনে পূর্বে নির্মিত ডেটাফ্রেমের অনুলিপি ধরে রেখেছে:

In [1]: import pandas as pd

In [2]: df = pd.DataFrame({'foo': [1,2,3,4]})

In [3]: df + 1
Out[3]: 
   foo
0    2
1    3
2    4
3    5

In [4]: df + 2
Out[4]: 
   foo
0    3
1    4
2    5
3    6

In [5]: Out # Still has all our temporary DataFrame objects!
Out[5]: 
{3:    foo
 0    2
 1    3
 2    4
 3    5, 4:    foo
 0    3
 1    4
 2    5
 3    6}

আপনি %reset Outআপনার ইতিহাস সাফ করতে টাইপ করে এটি ঠিক করতে পারেন । বিকল্পভাবে, আপনি আইপিথন কতটা ইতিহাস রেখেছেন তা সামঞ্জস্য করতে পারেন ipython --cache-size=5(ডিফল্টটি 1000)।

ডেটাফ্রেমের আকার হ্রাস করা হচ্ছে

যেখানেই সম্ভব, অবজেক্টের dtyype ব্যবহার এড়িয়ে চলুন।

>>> df.dtypes
foo    float64 # 8 bytes per value
bar      int64 # 8 bytes per value
baz     object # at least 48 bytes per value, often more

একটি অবজেক্ট dtype সহ মানগুলি বাক্সযুক্ত, যার অর্থ নিমপী অ্যারেটিতে কেবলমাত্র একটি পয়েন্টার থাকে এবং আপনার ডেটাফ্রেমের প্রতিটি মানের জন্য স্তূপে একটি পূর্ণ পাইথন অবজেক্ট থাকে। এটি স্ট্রিং অন্তর্ভুক্ত।

যদিও ন্যালি অ্যারেগুলিতে স্থির আকারের স্ট্রিংগুলিকে সমর্থন করে, পান্ডাসগুলি দেয় না ( এটি ব্যবহারকারীর বিভ্রান্তির কারণ )। এটি একটি উল্লেখযোগ্য পার্থক্য করতে পারে:

>>> import numpy as np
>>> arr = np.array(['foo', 'bar', 'baz'])
>>> arr.dtype
dtype('S3')
>>> arr.nbytes
9

>>> import sys; import pandas as pd
>>> s = pd.Series(['foo', 'bar', 'baz'])
dtype('O')
>>> sum(sys.getsizeof(x) for x in s)
120

আপনি স্ট্রিং কলামগুলি ব্যবহার এড়াতে বা স্ট্রিং ডেটা সংখ্যা হিসাবে উপস্থাপনের উপায় খুঁজে পেতে পারেন।

আপনার যদি এমন একটি ডেটাফ্রেম থাকে যাতে অনেকগুলি পুনরাবৃত্তি মান থাকে (NaN খুব সাধারণ) তবে আপনি মেমরির ব্যবহার হ্রাস করতে একটি স্পারস ডেটা কাঠামো ব্যবহার করতে পারেন :

>>> df1.info()
<class 'pandas.core.frame.DataFrame'>
Int64Index: 39681584 entries, 0 to 39681583
Data columns (total 1 columns):
foo    float64
dtypes: float64(1)
memory usage: 605.5 MB

>>> df1.shape
(39681584, 1)

>>> df1.foo.isnull().sum() * 100. / len(df1)
20.628483479893344 # so 20% of values are NaN

>>> df1.to_sparse().info()
<class 'pandas.sparse.frame.SparseDataFrame'>
Int64Index: 39681584 entries, 0 to 39681583
Data columns (total 1 columns):
foo    float64
dtypes: float64(1)
memory usage: 543.0 MB

মেমোরি ব্যবহার দেখুন

আপনি মেমোরি ব্যবহার ( ডক্স ) দেখতে পারেন :

>>> df.info()
<class 'pandas.core.frame.DataFrame'>
Int64Index: 39681584 entries, 0 to 39681583
Data columns (total 14 columns):
...
dtypes: datetime64[ns](1), float64(8), int64(1), object(4)
memory usage: 4.4+ GB

পান্ডাস 0.17.1 হিসাবে, আপনি df.info(memory_usage='deep')অবজেক্টস সহ মেমরির ব্যবহার দেখতেও করতে পারেন।


2
এটি 'স্বীকৃত উত্তর' চিহ্নিত করতে হবে। এটি সংক্ষেপে কিন্তু স্পষ্টভাবে ব্যাখ্যা করে যে কীভাবে পাইথন মেমরিটিকে ধরে রাখে এমনকি এমনকি এটির প্রয়োজন হয় না তখনও। মেমরি সংরক্ষণের টিপস সমস্ত বুদ্ধিমান এবং দরকারী। অন্য টিপ হিসাবে আমি কেবল 'মাল্টিপ্রসেসিং' ব্যবহার করে যুক্ত করব (@
অ্যামির

46

মন্তব্যে উল্লিখিত হিসাবে, চেষ্টা করার মতো কিছু জিনিস রয়েছে: gc.collect(@ অ্যাডচাম) উদাহরণস্বরূপ জিনিসগুলি সাফ করতে পারে। অন্তত আমার অভিজ্ঞতা থেকে, এই জিনিসগুলি কখনও কখনও কাজ করে এবং প্রায়শই হয় না।

একটি জিনিস রয়েছে যা সর্বদা কার্যকর হয় তবে এটি ভাষা, স্তরে নয় ওএস এ করা হয়।

ধরুন আপনার একটি ফাংশন রয়েছে যা একটি মধ্যবর্তী বিশাল ডেটাফ্রেম তৈরি করে এবং একটি ছোট ফলাফল প্রদান করে (এটি ডেটাফ্রেমও হতে পারে):

def huge_intermediate_calc(something):
    ...
    huge_df = pd.DataFrame(...)
    ...
    return some_aggregate

তারপরে যদি এমন কিছু করেন

import multiprocessing

result = multiprocessing.Pool(1).map(huge_intermediate_calc, [something_])[0]

তারপরে ফাংশনটি একটি ভিন্ন প্রক্রিয়াতে কার্যকর করা হয় । যখন এই প্রক্রিয়াটি সম্পূর্ণ হয়, ওএস ব্যবহৃত সমস্ত সংস্থান পুনরায় গ্রহণ করে। পাইথন, পান্ডাস, আবর্জনা সংগ্রহকারী, এটি থামাতে আসলে কিছুই করতে পারেনি।


1
@ b10hazard এমনকি পান্ডাস ব্যতীত পাইথন স্মৃতি বাস্তবে কীভাবে কাজ করে তা আমি কখনই সম্পূর্ণ বুঝতে পারি নি। এই অপরিশোধিত কৌশলটিই কেবলমাত্র আমি নির্ভর করি।
অমি ট্যাভোরি

9
সত্যিই ভাল কাজ করে। তবে একটি আইপথন পরিবেশে (বৃহস্পতি নোটবুকের মতো) আমি দেখতে পেয়েছি যে উদ্দীপনা প্রক্রিয়া থেকে মুক্তি পেতে আপনার পুলটি বন্ধ করুন () এবং .জয়েন () বা .মারমিট () স্থাপন করতে হবে। পাইথন ৩.৩ যেহেতু এটি করার সহজতম উপায় হ'ল কনটেক্সট ম্যানেজমেন্ট প্রোটোকলটি ব্যবহার করা: with multiprocessing.Pool(1) as pool: result = pool.map(huge_intermediate_calc, [something])যা লাগে একবার পুল শেষ করে বন্ধ করে দেওয়া।
জের্টিন

2
এটি ভাল কাজ করে, টাস্ক শেষ হওয়ার পরে কেবল সমাপ্তি এবং পুলটিতে যোগদান করতে ভুলবেন না।
আন্দ্রে নিকিশাভ

1
অজগর বস্তু থেকে কীভাবে স্মৃতি ফিরে পাওয়ার দাবি করতে হবে তা বেশ কয়েকবার পড়ার পরে, এটি এটি করার সর্বোত্তম উপায় বলে মনে হয়। একটি প্রক্রিয়া তৈরি করুন, এবং যখন সেই প্রক্রিয়াটি মারা যায় তখন ওএস মেমরিটি প্রকাশ করে।
muammar

1
সম্ভবত এটি কাউকে সহায়তা করে, পুল তৈরি করার সময় প্রক্রিয়াটি প্রকাশের জন্য ম্যাক্সটাস্কস্পারচাইল্ড = 1 ব্যবহার করার চেষ্টা করুন এবং কাজ শেষ হওয়ার পরে একটি নতুন তৈরি করুন।
giwiro

22

এটি আমার জন্য স্মৃতি প্রকাশের সমস্যাটি সমাধান করে !!!

del [[df_1,df_2]]
gc.collect()
df_1=pd.DataFrame()
df_2=pd.DataFrame()

ডেটা-ফ্রেম স্পষ্টভাবে নালিতে সেট করা হবে


1
উপ-তালিকায় ডেটাফ্রেমগুলি কেন যুক্ত করা হয়েছে [[df_1, df_2]]? কোন নির্দিষ্ট কারণ? দয়া করে ব্যাখ্যা করুন.
goks

5
আপনি শুধু শেষ দুটি বিবৃতি ব্যবহার করবেন না কেন? আমি মনে করি না আপনার প্রথম দুটি বিবৃতি দরকার।
স্পেসডাস্টপি

3

del dfdfমোছার সময় কোনও রেফারেন্স থাকলে মুছে ফেলা হবে না । সুতরাং del dfমেমরিটি প্রকাশের জন্য আপনাকে এর সাথে সম্পর্কিত সমস্ত তথ্য মুছে ফেলতে হবে ।

সুতরাং আবর্জনা সংগ্রহে ট্রিগার করতে df এ আবদ্ধ সমস্ত দৃষ্টান্ত মুছে ফেলা উচিত।

কোনটি বস্তুগুলিকে ধরে রেখেছে তা পরীক্ষা করতে অবজাগ্র্যাগ ব্যবহার করুন ।


লিঙ্কটি অজিগ্রাফের (এমজি.পোভ.ল্ট / ওবজগ্রাফ ) নির্দেশ করে, এটি যদি আপনার কোনও উত্তর না থাকে তবে এটি আপনার উত্তরের একটি টাইপো
SatZ

1

পান্ডসে মেমরি বরাদ্দকে প্রভাবিত করে এমন একটি সমস্যা রয়েছে যা দেখে মনে হচ্ছে: https://github.com/pandas-dev/pandas/issues/2659

বানর প্যাচ এই বিষয়ে বিস্তারিত আমার জন্য সমস্যা সমাধান করেছেন:

# monkeypatches.py

# Solving memory leak problem in pandas
# https://github.com/pandas-dev/pandas/issues/2659#issuecomment-12021083
import pandas as pd
from ctypes import cdll, CDLL
try:
    cdll.LoadLibrary("libc.so.6")
    libc = CDLL("libc.so.6")
    libc.malloc_trim(0)
except (OSError, AttributeError):
    libc = None

__old_del = getattr(pd.DataFrame, '__del__', None)

def __new_del(self):
    if __old_del:
        __old_del(self)
    libc.malloc_trim(0)

if libc:
    print('Applying monkeypatch for pd.DataFrame.__del__', file=sys.stderr)
    pd.DataFrame.__del__ = __new_del
else:
    print('Skipping monkeypatch for pd.DataFrame.__del__: libc or malloc_trim() not found', file=sys.stderr)
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.