مرحبا بالجميع!
يقترب إطلاق دورة
"Python Web Developer" ، على التوالي ، ما زلنا نشارك مقالات مثيرة للاهتمام ودعونا إلى دروسنا المفتوحة ، حيث يمكنك مشاهدة مواد مثيرة للاهتمام والتعرف على
المعلمين وطرح الأسئلة عليهم.
دعنا نذهب!
يتيح HDF5 التخزين الفعال لكميات كبيرة من البياناتعند العمل مع كميات كبيرة من البيانات ، سواء كانت تجريبية أو محاكاة ، فإن تخزينها في عدة ملفات نصية ليس فعالًا للغاية. في بعض الأحيان تحتاج إلى الوصول إلى مجموعة فرعية محددة من البيانات ، وتريد القيام بذلك بسرعة. في هذه المواقف ، يحل تنسيق HDF5 كلا المشكلتين بفضل مكتبة مدمجة محسنة للغاية. يستخدم HDF5 على نطاق واسع في البيئات العلمية ولديه تنفيذ ممتاز في Python مصمم للعمل مع NumPy مباشرة.
يدعم تنسيق HDF5 الملفات من أي حجم ، ولكل ملف بنية داخلية تسمح لك بالبحث عن مجموعة بيانات محددة. يمكن اعتبار هذا كملف منفصل لهيكله الهرمي الخاص به ، بالإضافة إلى مجموعة من المجلدات والمجلدات الفرعية. بشكل افتراضي ، يتم تخزين البيانات بتنسيق ثنائي ، والمكتبة متوافقة مع أنواع مختلفة من البيانات. أحد أهم الخيارات لتنسيق HDF5 هو أنه يسمح لك بإرفاق البيانات الوصفية بكل عنصر من عناصر الهيكل ، مما يجعله مثاليًا لإنشاء الملفات دون اتصال.

في Python ، يمكن إنشاء واجهة بتنسيق HDF5 باستخدام حزمة h5py. إحدى الميزات الأكثر إثارة للاهتمام في هذه الحزمة هي أن البيانات تُقرأ من ملف فقط عند الضرورة. تخيل أن لديك مجموعة كبيرة جدًا لا تتناسب مع ذاكرة الوصول العشوائي المتاحة لديك. على سبيل المثال ، يمكنك إنشاء مصفوفة على جهاز كمبيوتر بمواصفات مختلفة ، على عكس المواصفات التي تستخدمها لتحليل البيانات. يسمح لك تنسيق HDF5 باختيار عناصر الصفيف المطلوب قراءتها باستخدام بناء جملة يعادل NumPy. ثم يمكنك العمل مع البيانات المخزنة على محرك الأقراص الثابتة ، وليس في ذاكرة الوصول العشوائي (RAM) ، دون تغييرات كبيرة في التعليمات البرمجية الحالية.
في هذه المقالة ، سنلقي نظرة على كيفية استخدام h5py لتخزين واسترداد البيانات من محرك الأقراص الثابتة. سنناقش طرقًا مختلفة لتخزين البيانات وكيفية تحسين عملية القراءة. جميع الأمثلة التي تظهر في هذه المقالة متاحة أيضًا في
مستودع Github .
التثبيتتدعم
مجموعة HDF تنسيق HDF5 ، وهو يعتمد على معايير مفتوحة المصدر ، مما يعني أن بياناتك ستكون متاحة دائمًا ، حتى إذا اختفت المجموعة. يتم توفير دعم Python من خلال حزمة
h5py ، والتي يمكن تثبيتها عبر النقطة. تذكر أنه يجب عليك استخدام البيئة
الافتراضية للاختبار:
pip install h5py
سيقوم هذا الأمر أيضًا بتثبيت NumPy إذا لم يكن في بيئتك.
إذا كنت تبحث عن أداة رسومية لفحص محتويات ملفات HDF5 الخاصة بك ، يمكنك تثبيت
عارض HDF5 . إنه مكتوب بلغة جافا ، لذلك يجب أن يعمل على أي جهاز كمبيوتر تقريبًا.
تخزين وقراءة البيانات الأساسيةدعنا ننتقل إلى استخدام مكتبة HDF5. سنقوم بإنشاء ملف جديد وحفظ مجموعة NumPy عشوائية فيه.
import h5py import numpy as np arr = np.random.randn(1000) with h5py.File('random.hdf5', 'w') as f: dset = f.create_dataset("default", data=arr)
الأسطر القليلة الأولى بسيطة للغاية: نستورد حزمتي h5py و NumPy وننشئ مصفوفة بقيم عشوائية. نفتح ملف random.hdf5 بإذن كتابة w ، مما يعني أنه في حالة وجود ملف بنفس الاسم بالفعل ، سيتم استبداله. إذا كنت تريد حفظ الملف ولا تزال قادرًا على الكتابة إليه ، فيمكنك فتحه باستخدام السمة بدلاً من w. نقوم بإنشاء مجموعة بيانات تسمى الإعداد الافتراضي وتعيين البيانات كمصفوفة عشوائية تم إنشاؤها سابقًا. مجموعات البيانات هي حماة بياناتنا ، وهي اللبنات الأساسية لتنسيق HDF5.
ملاحظة
إذا لم تكن على دراية بالبيان ، يجب أن أشير إلى أن هذه طريقة مناسبة لفتح وإغلاق الملفات. حتى في حالة حدوث خطأ بالداخل ، سيتم إغلاق الملف. إذا كنت لا تستخدم لسبب ما ، فلا تنس أبدًا إضافة الأمر
f.close()
إلى النهاية. يعمل البيان مع أي ملفات ، وليس فقط ملفات HDF.
يمكننا قراءة البيانات بنفس الطريقة التي نقرأ بها ملف NumPy تقريبًا:
with h5py.File('random.hdf5', 'r') as f: data = f['default'] print(min(data)) print(max(data)) print(data[:15])
نفتح الملف بسمة القراءة r ونستعيد البيانات عن طريق الوصول المباشر إلى مجموعة البيانات المسماة الافتراضية. إذا فتحت الملف ولم تكن تعرف مجموعات البيانات المتاحة ، يمكنك الحصول عليها:
for key in f.keys(): print(key)
بعد قراءة مجموعة البيانات التي تريدها ، يمكنك استخدامها كما لو كنت تستخدم أي صفيف NumPy. على سبيل المثال ، يمكنك العثور على القيم القصوى والدنيا أو تحديد أول 15 قيمة للصفيف. ومع ذلك ، تخفي هذه الأمثلة البسيطة العديد من الأشياء التي تحدث تحت غطاء المحرك ، ويجب مناقشتها لفهم الإمكانات الكاملة لـ HDF5.
في المثال أعلاه ، يمكنك استخدام البيانات كمصفوفة. على سبيل المثال ، يمكنك الرجوع إلى العنصر الثالث عن طريق إدخال البيانات [2] ، أو يمكنك الحصول على نطاق من قيم البيانات [1: 3]. يرجى ملاحظة: البيانات ليست مصفوفة ، إنها مجموعة بيانات. يمكنك رؤيتها بكتابة
print(type(data))
. تعمل مجموعات البيانات بطريقة مختلفة تمامًا عن المصفوفات ، لأنه يتم تخزين معلوماتها على القرص الصلب ، ولا يتم تحميلها في ذاكرة الوصول العشوائي إذا لم نستخدمها. الكود التالي ، على سبيل المثال ، لن يعمل:
f = h5py.File('random.hdf5', 'r') data = f['default'] f.close() print(data[1])
الخطأ الذي يظهر مرهق بعض الشيء ، ولكن السطر الأخير مفيد جدًا:
ValueError: Not a dataset (not a dataset)
يعني الخطأ أننا نحاول الوصول إلى مجموعة بيانات لم يعد بإمكاننا الوصول إليها. هذا مربك قليلاً ، ولكنه يحدث لأننا أغلقنا الملف وبالتالي لم يعد مسموحًا لنا بالوصول إلى القيمة الثانية في البيانات. عندما قمنا بتعيين f ['default'] للبيانات المتغيرة ، فإننا في الواقع لا نقرأ البيانات من الملف ، بدلاً من ذلك ننشئ مؤشرًا حيث توجد البيانات على القرص الصلب. من ناحية أخرى ، سيعمل هذا الرمز:
f = h5py.File('random.hdf5', 'r') data = f['default'][:] f.close() print(data[10])
يرجى ملاحظة أن الاختلاف الوحيد هو أننا أضفنا [:] بعد قراءة مجموعة البيانات. تتناول العديد من الكتيبات الأخرى مثل هذه الأمثلة ، حتى دون إظهار الإمكانات الكاملة لتنسيق HDF5 مع حزمة h5py. بسبب الأمثلة التي قمنا بفحصها حتى الآن ، قد تتساءل: لماذا استخدام HDF5 إذا كان حفظ ملفات NumPy يمنحك نفس الوظيفة؟ دعونا نتعمق في ميزات تنسيق HDF5.
قراءة انتقائية من ملفات HDF5حتى الآن ، رأينا أنه عندما نقرأ مجموعة بيانات ، فإننا لا نقرأ البيانات من القرص بعد ، وبدلاً من ذلك ننشئ ارتباطًا بمكان معين على القرص الثابت. يمكننا أن نرى ما يحدث ، على سبيل المثال ، إذا قرأنا بشكل صريح العناصر العشرة الأولى لمجموعة البيانات:
with h5py.File('random.hdf5', 'r') as f: data_set = f['default'] data = data_set[:10] print(data[1]) print(data_set[1])
قمنا بتقسيم الشفرة إلى أسطر مختلفة لجعلها أكثر وضوحًا ، ولكن يمكنك أن تكون أكثر الاصطناعية في مشاريعك. في السطور أعلاه ، قرأنا الملف أولاً ثم قرأنا مجموعة البيانات الافتراضية. نقوم بتعيين أول 10 عناصر لمجموعة البيانات لمتغير البيانات. بعد إغلاق الملف (عند انتهائه) ، يمكننا الوصول إلى القيم المخزنة في البيانات ، لكن data_set ستلقي خطأ. لاحظ أننا نقرأ فقط من القرص عندما نصل صراحةً إلى أول 10 عناصر لمجموعة بيانات. إذا نظرت إلى أنواع البيانات ومجموعة البيانات ، فستلاحظ أنها مختلفة حقًا. الأول هو صفيف NumPy ، والثاني هو h5py DataSet.
نفس السلوك ذو صلة في سيناريوهات أكثر تعقيدًا. دعنا ننشئ ملفًا جديدًا ، هذه المرة بمجموعتي بيانات ، ودعنا نختار عناصر أحدهما استنادًا إلى عناصر الآخر. لنبدأ بإنشاء ملف جديد وتخزين البيانات ؛ هذا الجزء هو الأبسط:
import h5py import numpy as np arr1 = np.random.randn(10000) arr2 = np.random.randn(10000) with h5py.File('complex_read.hdf5', 'w') as f: f.create_dataset('array_1', data=arr1) f.create_dataset('array_2', data=arr2)
لدينا مجموعتي بيانات تسمى array_1 و array_2 ، يحتوي كل منهما على صفيف NumPy عشوائي. نريد قراءة قيم array_2 التي تتوافق مع العناصر التي تكون فيها قيم array_1 موجبة. يمكننا محاولة القيام بشيء مثل هذا:
with h5py.File('complex_read.hdf5', 'r') as f: d1 = f['array_1'] d2 = f['array_2'] data = d2[d1>0]
ولكن هذا لن يعمل. d1 هي مجموعة بيانات ولا يمكن مقارنتها بعدد صحيح. الطريقة الوحيدة هي قراءة البيانات من القرص ، ثم مقارنتها. لذلك ، نحصل على شيء مثل هذا:
with h5py.File('complex_read.hdf5', 'r') as f: d1 = f['array_1'] d2 = f['array_2'] data = d2[d1[:]>0]
يتم تحميل مجموعة البيانات الأولى d1 بالكامل في الذاكرة عندما نقوم بـ d1 [:] ، ولكن من مجموعة البيانات الثانية d2 نأخذ فقط بعض العناصر. إذا كانت مجموعة بيانات d1 كبيرة جدًا بحيث لا يمكن تحميلها في الذاكرة بالكامل ، فيمكننا العمل داخل حلقة.
with h5py.File('complex_read.hdf5', 'r') as f: d1 = f['array_1'] d2 = f['array_2'] data = [] for i in range(len(d1)): if d1[i] > 0: data.append(d2[i]) print('The length of data with a for loop: {}'.format(len(data)))
بالطبع ، هناك مشاكل في كفاءة القراءة مع العناصر وإضافة عناصر إلى القائمة ، ولكن هذا مثال جيد جدًا على واحدة من أكبر مزايا استخدام HDF5 عبر الملفات النصية أو ملفات NumPy. داخل الحلقة ، نقوم بتحميل عنصر واحد فقط في الذاكرة. في مثالنا ، كل عنصر مجرد رقم ، ولكن يمكن أن يكون أي شيء: من نص إلى صورة أو فيديو.
كما هو الحال دائمًا ، بناءً على التطبيق الخاص بك ، عليك أن تقرر ما إذا كنت تريد قراءة المصفوفة بالكامل في الذاكرة أم لا. في بعض الأحيان ، تقوم بتشغيل عمليات محاكاة على جهاز كمبيوتر معين به مساحة كبيرة من الذاكرة ، ولكن ليس لديك نفس الخصائص على الكمبيوتر المحمول ، وتضطر إلى قراءة أجزاء من بياناتك. تذكر أن القراءة من محرك الأقراص الصلبة بطيئة نسبيًا ، خاصة إذا كنت تستخدم محرك الأقراص الثابتة بدلاً من أقراص SDD أو حتى أطول إذا كنت تقرأ من محرك أقراص الشبكة.
الكتابة بشكل انتقائي إلى ملفات HDF5في الأمثلة أعلاه ، أضفنا البيانات إلى مجموعة البيانات بمجرد إنشائها. ومع ذلك ، تحتاج العديد من التطبيقات إلى حفظ البيانات أثناء الإنشاء. يسمح لك HDF5 بحفظ البيانات بنفس الطريقة التي تقرأها بها. دعنا نرى كيفية إنشاء مجموعة بيانات فارغة وإضافة بعض البيانات إليها.
arr = np.random.randn(100) with h5py.File('random.hdf5', 'w') as f: dset = f.create_dataset("default", (1000,)) dset[10:20] = arr[50:60]
create_dataset
كما كان من قبل ، باستثناء
create_dataset
. نحن لا نضيف بيانات عند إنشائها ، بل نقوم فقط بإنشاء مجموعة بيانات فارغة يمكنها استيعاب ما يصل إلى 1000 عنصر. بنفس المنطق كما كان من قبل ، عندما نقرأ عناصر معينة من مجموعة بيانات ، نكتب في الواقع إلى القرص فقط عندما نعين قيمًا لعناصر معينة من متغير dset. في المثال أعلاه ، نقوم فقط بتعيين القيم لمجموعة فرعية من الصفيف ، مع مؤشرات من 10 إلى 19.
تحذيرليس صحيحًا تمامًا ما تكتبه على القرص عند تعيين قيم لمجموعة بيانات. تعتمد اللحظة الدقيقة على عدة عوامل ، بما في ذلك حالة نظام التشغيل. إذا تم إغلاق البرنامج في وقت مبكر جدًا ، فقد يحدث أنه لن يتم تسجيل كل شيء. من المهم جدًا استخدام طريقة
close()
دائمًا ، وفي حالة الكتابة على مراحل ، يمكنك أيضًا استخدام
flush()
لفرض الإدخال. استخدام مع يمنع الكثير من مشاكل الكتابة.
إذا قرأت الملف وطبعت أول 20 قيمة لمجموعة البيانات ، فسترى أنها كلها أصفار ، باستثناء المؤشرات من 10 إلى 19. هناك خطأ شائع يمكن أن يؤدي إلى صداع ملحوظ. لن يحفظ الكود التالي أي شيء على القرص:
arr = np.random.randn(1000) with h5py.File('random.hdf5', 'w') as f: dset = f.create_dataset("default", (1000,)) dset = arr
يتسبب هذا الخطأ دائمًا في الكثير من المشاكل ، لأنك لن تفهم أنك لم تكتب أي شيء حتى تحاول قراءة النتيجة. تكمن المشكلة هنا في أنك لا تحدد المكان الذي تريد تخزين البيانات فيه ، فما عليك سوى استبدال متغير dset بمصفوفة NumPy. نظرًا لأن مجموعة البيانات والصفيف لهما نفس الطول ، يجب استخدام dset [:] = arr. يحدث هذا الخطأ في كثير من الأحيان أكثر مما تعتقد ، ولأنه ليس خطأ تقنيًا ، فلن ترى أي أخطاء معروضة على الجهاز ، وستكون بياناتك أصفارًا.
حتى الآن ، عملنا دائمًا مع مصفوفات أحادية البعد ، لكننا لا نقتصر عليها. على سبيل المثال ، لنفترض أننا نريد استخدام مصفوفة ثنائية الأبعاد ، يمكننا ببساطة القيام بما يلي:
dset = f.create_dataset('default', (500, 1024))
مما يسمح لنا بتخزين البيانات في صفيف 500x1024. لاستخدام مجموعة بيانات ، يمكننا استخدام نفس البنية كما كان من قبل ، ولكن مع مراعاة البعد الثاني:
dset[1,2] = 1 dset[200:500, 500:1024] = 123
حدد أنواع البيانات لتحسين المساحةحتى الآن ، قمنا بفحص قمة جبل الجليد فقط لما يقدمه HDF5. بالإضافة إلى طول البيانات التي تريد الاحتفاظ بها ، يمكنك تحديد نوع البيانات لتحسين المساحة. تحتوي
وثائق h5py على قائمة بجميع الأنواع المدعومة ، وهنا نعرض فقط اثنين منها. في نفس الوقت ، سنعمل مع عدة مجموعات بيانات في ملف واحد.
with h5py.File('several_datasets.hdf5', 'w') as f: dset_int_1 = f.create_dataset('integers', (10, ), dtype='i1') dset_int_8 = f.create_dataset('integers8', (10, ), dtype='i8') dset_complex = f.create_dataset('complex', (10, ), dtype='c16') dset_int_1[0] = 1200 dset_int_8[0] = 1200.1 dset_complex[0] = 3 + 4j
في المثال أعلاه ، أنشأنا ثلاث مجموعات بيانات مختلفة ، لكل منها نوع مختلف. أعداد صحيحة من 1 بايت ، والأعداد الصحيحة من 8 بايت ، والأعداد المركبة من 16 بايت. نقوم بتخزين رقم واحد فقط ، حتى لو كانت مجموعات البيانات الخاصة بنا يمكن أن تحتوي على ما يصل إلى 10 عناصر. يمكنك قراءة القيم ومعرفة ما تم حفظه بالفعل. وتجدر الإشارة هنا إلى أن العدد الصحيح من 1 بايت يجب تقريبه إلى 127 (بدلاً من 1200) ، ويجب تقريب العدد الصحيح من 8 بايت إلى 1200 (بدلاً من 1200.1).
إذا كنت قد برمجت بلغات مثل C أو Fortran ، فربما تعرف ما تعنيه أنواع البيانات المختلفة. ومع ذلك ، إذا كنت تعمل دائمًا مع Python ، فقد لا تكون واجهت أي مشاكل دون الإعلان بشكل صريح عن نوع البيانات التي تعمل معها. من المهم أن تتذكر أن عدد البايتات يخبرك بعدد الأرقام المختلفة التي يمكنك حفظها. إذا كنت تستخدم بايت واحد ، فلديك 8 بت ، وبالتالي يمكنك تخزين 2 ^ 8 أرقام مختلفة. في المثال أعلاه ، تكون الأعداد الصحيحة موجبة وسالبة و 0. عند استخدام أعداد صحيحة من 1 بايت ، يمكنك تخزين القيم من -128 إلى 127 ، في المجموع فهي 2 ^ 8 أرقام محتملة. هذا يعادل استخدام 8 بايت ، ولكن مع مجموعة واسعة من الأرقام.
سيؤثر نوع البيانات المحددة على حجمها. أولاً ، دعنا نرى كيف يعمل هذا مع مثال بسيط. دعنا ننشئ ثلاثة ملفات ، لكل منها مجموعة بيانات واحدة لكل 100000 عنصر ، ولكن مع أنواع بيانات مختلفة. سنحفظ نفس البيانات فيها ، ثم نقارن أحجامها. نقوم بإنشاء صفيف عشوائي للتعيين لكل مجموعة بيانات لملء الذاكرة. تذكر أنه سيتم تحويل البيانات إلى التنسيق المحدد في مجموعة البيانات.
arr = np.random.randn(100000) f = h5py.File('integer_1.hdf5', 'w') d = f.create_dataset('dataset', (100000,), dtype='i1') d[:] = arr f.close() f = h5py.File('integer_8.hdf5', 'w') d = f.create_dataset('dataset', (100000,), dtype='i8') d[:] = arr f.close() f = h5py.File('float.hdf5', 'w') d = f.create_dataset('dataset', (100000,), dtype='f16') d[:] = arr f.close()
عند التحقق من حجم كل ملف ، ستحصل على شيء مثل:
ملف | الحجم (ب) |
---|
عدد صحيح_1 | 102144 |
عدد صحيح 9 | 802144 |
تعويم | 1602144 |
العلاقة بين الحجم ونوع البيانات واضحة. عندما تنتقل من أعداد صحيحة من بايت واحد إلى ما يصل إلى 8 بايت ، يزداد حجم الملف بمقدار 8 مرات ، وبالمثل ، عندما تذهب إلى 16 بايت ، فإنه يأخذ مساحة أكبر بنحو 16 مرة. لكن المساحة ليست العامل الوحيد المهم الذي يجب مراعاته ؛ يجب عليك أيضًا مراعاة الوقت الذي تستغرقه كتابة البيانات على القرص. كلما كان لديك المزيد من الكتابة ، كلما استغرق الأمر وقتًا أطول. اعتمادًا على التطبيق الخاص بك ، قد يكون من الضروري تحسين قراءة وكتابة البيانات.
يرجى ملاحظة: إذا كنت تستخدم نوع بيانات غير صحيح ، فقد تفقد أيضًا المعلومات. على سبيل المثال ، إذا كان لديك أعداد صحيحة من 8 بايت ، وقمت بتخزينها كأعداد صحيحة من 1 بايت ، فسيتم اقتطاع قيمها. عند العمل في المختبر ، غالبًا ما تكون الأجهزة التي تنشئ أنواعًا مختلفة من البيانات متاحة. تحتوي بعض بطاقات DAQ على 16 بت ، وبعض الكاميرات تعمل مع 8 بت ، ولكن بعضها يمكن أن يعمل مع 24 بت. من المهم الانتباه إلى أنواع البيانات ، ولكن هذا أيضًا شيء قد لا يأخذه مطورو Python في الاعتبار ، لأنك لست بحاجة إلى يعلن نوع.
من المثير للاهتمام أيضًا أن تتذكر أن مصفوفة NumPy الافتراضية ستطفو مع 8 بايت (64 بت) لكل عنصر. يمكن أن يكون هذا مشكلة إذا قمت ، على سبيل المثال ، بتهيئة مصفوفة بأصفار لتخزين البيانات ، والتي يجب أن تكون 2 بايت فقط. لن يتغير نوع المصفوفة نفسها ، وإذا قمت بحفظ البيانات عند إنشاء مجموعة البيانات (إضافة بيانات = my_array) ، فسيكون التنسيق الافتراضي هو "f8" ، وهو مصفوفة ، ولكن ليس بيانات حقيقية ،
إن التفكير في أنواع البيانات ليس شيئًا يحدث بانتظام إذا كنت تعمل مع Python في تطبيقات بسيطة. ومع ذلك ، يجب أن تكون على دراية بأن أنواع البيانات موجودة وتأثيرها على نتائجك. قد يكون لديك محركات أقراص ثابتة كبيرة ولا تهتم حقًا بتخزين الملفات ، ولكن عندما تهتم بالسرعة التي تحفظ بها ، لا توجد طريقة أخرى سوى تحسين كل جانب من جوانب التعليمات البرمجية ، بما في ذلك أنواع البيانات.
ضغط البياناتعند حفظ البيانات ، يمكنك اختيار الضغط باستخدام خوارزميات مختلفة. تدعم حزمة h5py العديد من فلاتر الضغط ، مثل GZIP و LZF و SZIP. عند استخدام أحد مرشحات الضغط ، ستتم معالجة البيانات في طريقها إلى القرص ، وعند قراءتها سيتم فكها. لذلك ، لا توجد تغييرات خاصة في التعليمات البرمجية. يمكننا تكرار نفس التجربة ، وحفظ أنواع مختلفة من البيانات ، ولكن باستخدام مرشح ضغط. يبدو رمزنا كما يلي:
import h5py import numpy as np arr = np.random.randn(100000) with h5py.File('integer_1_compr.hdf5', 'w') as f: d = f.create_dataset('dataset', (100000,), dtype='i1', compression="gzip", compression_opts=9) d[:] = arr with h5py.File('integer_8_compr.hdf5', 'w') as f: d = f.create_dataset('dataset', (100000,), dtype='i8', compression="gzip", compression_opts=9) d[:] = arr with h5py.File('float_compr.hdf5', 'w') as f: d = f.create_dataset('dataset', (100000,), dtype='f16', compression="gzip", compression_opts=9) d[:] = arr
لقد اخترنا gzip لأنه مدعوم على جميع المنصات. تحدد خيارات compression_opts مستوى الضغط. كلما ارتفع المستوى ، قلّت مساحة البيانات ، ولكن كلما طالت فترة عمل المعالج. مستوى الضغط الافتراضي هو 4. يمكننا رؤية الاختلافات في ملفاتنا بناءً على مستوى الضغط:
اكتب | لا ضغط | ضغط 9 | ضغط 4 |
---|
عدد صحيح_1 | 102144 | 28016 | 30463 |
عدد صحيح_8 | 802144 | 43329 | 57971 |
تعويم | 1602144 | 1469580 | 1469868 |
يمكن ملاحظة تأثير الضغط على مصفوفات البيانات بالكامل أكثر بكثير من تأثيره على مجموعات بيانات الفاصلة العائمة. أترك لك معرفة سبب نجاح الضغط بشكل جيد في الحالتين الأوليين ، ولكن ليس في الحالة الأخيرة. للتلميح: يجب عليك التحقق من البيانات التي تقوم بتخزينها بالفعل.
لا تؤدي قراءة البيانات المضغوطة إلى تغيير أي من التعليمات البرمجية الموضحة أعلاه. ستهتم المكتبة الأساسية HDF5 باستخراج البيانات من مجموعات البيانات المضغوطة باستخدام الخوارزمية المناسبة. لذلك ، إذا قمت بتطبيق الضغط للحفظ ، فلن تحتاج إلى تغيير الرمز الذي تستخدمه للقراءة.
يعد ضغط البيانات أداة إضافية يجب أن تضعها في الاعتبار مع جميع الجوانب الأخرى لمعالجة البيانات. يجب مراعاة وقت المعالج الإضافي ونسبة الضغط الفعال من أجل تقييم فوائد ضغط البيانات داخل التطبيق الخاص بك. حقيقة أنه من الشفاف لشفرة المصب يجعل من السهل للغاية اختبار وإيجاد أفضل حل.
تغيير حجم مجموعات البياناتعندما تعمل على تجربة ، يكون من المستحيل أحيانًا معرفة حجم بياناتك. تخيل أنك تقوم بتسجيل فيلم ، ربما ستوقفه بعد ثانية واحدة ، ربما بعد ساعة. لحسن الحظ ، يتيح لك HDF5 تغيير حجم مجموعات البيانات بسرعة مع تكلفة حسابية قليلة. يمكن تجاوز طول مجموعة البيانات حتى الحجم الأقصى. يتم تحديد هذا الحجم الأقصى عند إنشاء مجموعة البيانات باستخدام الكلمة الرئيسية ذات الشكل الأقصى:
import h5py import numpy as np with h5py.File('resize_dataset.hdf5', 'w') as f: d = f.create_dataset('dataset', (100, ), maxshape=(500, )) d[:100] = np.random.randn(100) d.resize((200,)) d[100:200] = np.random.randn(100) with h5py.File('resize_dataset.hdf5', 'r') as f: dset = f['dataset'] print(dset[99]) print(dset[199])
أولاً ، يمكنك إنشاء مجموعة بيانات لتخزين 100 قيمة وتعيين الحد الأقصى للحجم على 500 قيمة. بعد حفظ الدفعة الأولى من القيم ، يمكنك توسيع مجموعة البيانات لحفظ الـ 100 التالية. يمكنك تكرار الإجراء حتى تحصل على مجموعة بيانات تحتوي على 500 قيمة. , N- . , , .
, , . , - ( , , ):
with h5py.File('resize_dataset.hdf5', 'a') as f: dset = f['dataset'] dset.resize((300,)) dset[:200] = 0 dset[200:300] = np.random.randn(100) with h5py.File('resize_dataset.hdf5', 'r') as f: dset = f['dataset'] print(dset[99]) print(dset[199]) print(dset[299])
, , 200 200 299. , , .
, , , . 2D-, , — , 2D-. 3- HDF-, . , :
with h5py.File('movie_dataset.hdf5', 'w') as f: d = f.create_dataset('dataset', (1024, 1024, 1), maxshape=(1024, 1024, None )) d[:,:,0] = first_frame d.resize((1024,1024,2)) d[:,:,1] = second_frame
1024x1024 , . , , . maxshape None.
(Chunks), . (chunk) , .. . , , . , :
dset = f.create_dataset("chunked", (1000, 1000), chunks=(100, 100))
, dset [0: 100,0: 100] . dset [200: 300, 200: 300], dset [100: 200, 400: 500] . . h5py, :
(Chunking) . 10 KiB 1 MiB, . , , .
(auto-chunking), . , maxshape. :
dset = f.create_dataset("autochunk", (1000, 1000), chunks=True)
(Groups). HDF5, , . (groups), , . , :
import numpy as np import h5py arr = np.random.randn(1000) with h5py.File('groups.hdf5', 'w') as f: g = f.create_group('Base_Group') gg = g.create_group('Sub_Group') d = g.create_dataset('default', data=arr) dd = gg.create_dataset('default', data=arr)
Base_Group , Sub_Group. default . , , :
with h5py.File('groups.hdf5', 'r') as f: d = f['Base_Group/default'] dd = f['Base_Group/Sub_Group/default'] print(d[1]) print(dd[1])
, : Base_Group/default Base_Group/Sub_Group/default. , , , , . — keys():
with h5py.File('groups.hdf5', 'r') as f: for k in f.keys(): print(k)
, , for-. , . visit(), :
def get_all(name): print(name) with h5py.File('groups.hdf5', 'r') as f: f.visit(get_all)
,
get_all
, , name. visit,
get_all.
visit , , None, . , , Sub_Group,
get_all
:
def get_all(name): if 'Sub_Group' in name: return name with h5py.File('groups.hdf5', 'r') as f: g = f.visit(get_all) print(g)
visit , , None, , get_all. Sub_Group, get_all , Sub_Group . , g , , :
with h5py.File('groups.hdf5', 'r') as f: g_name = f.visit(get_all) group = f[g_name]
. — , visititems, : name object. :
def get_objects(name, obj): if 'Sub_Group' in name: return obj with h5py.File('groups.hdf5', 'r') as f: group = f.visititems(get_objects) data = group['default'] print('First data element: {}'.format(data[0]))
visititems , , , . , , . . , , .
HDF5, HDF5, , . , , , , , , .. . , , 200x300x250. , , , , — , .
HDF5 -. .
import time import numpy as np import h5py import os arr = np.random.randn(1000) with h5py.File('groups.hdf5', 'w') as f: g = f.create_group('Base_Group') d = g.create_dataset('default', data=arr) g.attrs['Date'] = time.time() g.attrs['User'] = 'Me' d.attrs['OS'] = os.name for k in g.attrs.keys(): print('{} => {}'.format(k, g.attrs[k])) for j in d.attrs.keys(): print('{} => {}'.format(j, d.attrs[j]))
, attrs . , , . , . , , , update:
with h5py.File('groups.hdf5', 'w') as f: g = f.create_group('Base_Group') d = g.create_dataset('default', data=arr) metadata = {'Date': time.time(), 'User': 'Me', 'OS': os.name,} f.attrs.update(metadata) for m in f.attrs.keys(): print('{} => {}'.format(m, f.attrs[m]))
, , hdf5, . , . hdf5, . Python -. JSON, , , , pickle.
import json with h5py.File('groups_dict.hdf5', 'w') as f: g = f.create_group('Base_Group') d = g.create_dataset('default', data=arr) metadata = {'Date': time.time(), 'User': 'Me', 'OS': os.name,} m = g.create_dataset('metadata', data=json.dumps(metadata))
, . , . , json.dumps, . , HDF5. , json.loads:
بيثون
with h5py.File('groups_dict.hdf5', 'r') as f: metadata = json.loads(f['Base_Group/metadata'][()]) for k in metadata: print('{} => {}'.format(k, metadata[k]))
json , . YAML, XML .. , , , attr , , .
HDF5, . , , , . HDF , , , , , . , HDF .
HDF5 . , , . , . . SQL,
HDFql , SQL HDF5.
. , , - , , . , . , , .
HDF5 — , . , , , , . HDF5 — , , .
النهاية
,
.