علوم وفضاء

digitize: هل الحافة المتكررة تصنع فئة مشغولة؟

قيمة وفهرسان مع غياب الفئة الوسطى.
الفهرس 2 غائب في متجهي المثال.

في مثالنا، تغيير right نقل القيمة 2 بين فئتين وبقيت الفئة الوسطى فارغة.

حدد جهة شمول الطرف

digitize تعيد فهارس؛ للحواف المتزايدة، right=False يشمل الطرف الأيسر، وTrue يشمل الأيمن. [1]

نستعمل هنا «متزايدة» بمعنى غير متناقصة: يمكن تكرار حافة، لكن لا تنخفض القيم أثناء السير في القائمة. سؤالنا عن الفئة التي قد تبقى فارغة، لا عن تكرار عنصر في البيانات أو عدد مرات ظهوره.

في NumPy 2.3.5 على CPython 3.12.14، وضعنا B=np.array([-3,2,2,7],dtype=np.int64) وX=np.array([-4,-3,1,2,6,7,8],dtype=np.int64). شكل B هو (4,)، وشكل X هو (7,).

الحافة 2 تظهر مرتين متجاورتين. نسمي المجال بين الحافتين ذواتَي الفهرسين 1 و2 «الفئة 2» في شرحنا. نتتبع قيمًا أقل من الطرف، ومساوية له، وأكبر منه، مع تثبيت نوع المدخلين.

نقرأ نتيجة التشغيل لكل قيمة من X في الموضع نفسه. ليست قائمة النتائج قائمة أعداد أفراد الفئات: سبع قيم مدخلة أعطتنا سبعة فهارس، لا أربعة تكرارات.

فئة فارغة وقفزة حول الحافة المكررة

أعطى np.digitize(X,B,right=False) المتجه [0,1,1,3,3,4,4]، وأعطى right=True المتجه [0,0,1,1,3,3,4]. كلاهما من int64 في التشغيل، وبالشكل (7,).

عند False، مجال الفئة 1 في مثالنا هو -3<=x<2، ومجال الفئة 3 هو 2<=x<7. للقيمة 1 الفهرس 1، وللقيمة 2 الفهرس 3، وللقيمة 6 الفهرس 3 أيضًا.

تبقى الفئة 2 بين الحافتين المكررتين: 2<=x<2. لا يحقق أي عدد صحيح هذين الشرطين معًا؛ لو كان لا يقل عن 2 فلن يكون أقل من 2. لذلك لا توجد قيمة تجعل هذه الفئة مشغولة في مثالنا.

عند True يصبح مجال الفئة 1 هو -3<x<=2، ومجال الفئة 3 هو 2<x<=7. تدخل القيمة 2 الفئة 1، وتبقى القيمة 6 في الفئة 3.

ومجال الفئة 2 عند هذا الإعداد هو 2<x<=2، وهو فارغ أيضًا. نقل شمول الطرف إلى الجهة الأخرى لا يفصل الحافتين ولا يمنح المجال عرضًا موجبًا.

إذن عند القيمة 2 انتقل الناتج من 3 إلى 1 عند تغيير right. الفهرس 2 غائب من كلا متجهي النتائج. لا نقول إن الدالة حذفت موضعًا من B؛ بقيت الحواف الأربع وبايتاتها كما كانت.

يمكن رؤية الفراغ قبل استدعاء الدالة من الشرطين المتناقضين. التشغيل هنا يراجع تطبيقنا على المثال، ولا يثبت أن كل فئة غير فارغة تحتوي فعلًا قيمة من X؛ ذلك سؤال آخر يتوقف على القيم المختارة.

الطرف الأخير وموضع الإدراج

للقيمة 7، خرج الفهرس 4 عند False، والفهرس 3 عند True. في False لا تحقق 7 شرط x<7 للفئة 3؛ وفي True تحقق 2<x<=7. إذن غيّر إعداد right جهة دخول الطرف الأخير.

القيمة 8 أعطت الفهرس 4 في الحالتين، والقيمة -4 أعطت صفرًا فيهما. أما -3 فأعطت 1 عند False وصفرًا عند True، وفق اختلاف الشمول عند الطرف الأول.

طول B هو أربعة، وفهارس قراءة عناصرها من صفر إلى ثلاثة. عندما حاولنا قراءة B بمتجه نتائج False كاملًا، وقع IndexError بسبب وجود 4. الفهرس الخارج لا يتحول إلى عنصر خامس موجود.

والناتج صفر لا يكفي لتسمية مجال داخلي في هذا المثال. مثلًا القيمة -4 أقل من الحافة الأولى -3، حتى لو كانت قراءة B عند صفر ممكنة وتعطي -3. نجاح قراءة الحافة لا يجعل القيمة داخل مجال بين حافتين.

searchsorted تعطي مواضع إدراج تحفظ الترتيب؛ side يختار أول موضع مناسب أو آخره. [2]

نفذنا np.searchsorted(B,X,side="right") فحصلنا على متجه False نفسه، ونفذنا side="left" فحصلنا على متجه True نفسه. نقارن قوائم الفهارس كاملة، لا مجرد فهرس واحد عند الحافة المكررة.

في مرجعنا للقيمة 2، توجد ثلاث حواف لا تزيد عليها، وحافة واحدة تقل عنها. هذان العددان هما 3 و1 في متجهي الإعدادين. لم نستعمل هذه المقارنة لاختبار عضوية 2 في B أو اختيار أقرب حافة.

نحتفظ باسم الدالة وخيارها مع النتيجة. الأسماء right وside="right" تتفق في هذا التشغيل عندما right=False؛ لا ننقل كلمة right وحدها بين الواجهتين ثم نفترض أن موضع شمول الطرف بقي نفسه.

شروط الفئة الفارغة والطرف الأخير.
عند 7: الفهرس 4 أو 3 حسب الإعداد.

مرجع العد ونطاق الشبكة

لكل قيمة x، عد مرجع Python الحواف التي تحقق b<=x لتوقع False، والحواف التي تحقق b<x لتوقع True. استعمل sum على مقارنات الأعداد في القوائم، ولم يستدع digitize أو searchsorted لبناء التوقع.

للشبكة، أخذنا جميع قوائم الحواف غير المتناقصة بأطوال 2 و3 و4 و5 من الأعداد الصحيحة -4 إلى 4. استبعدنا القائمة التي تتساوى حوافها جميعًا؛ بقيت 1956 قائمة، تتضمن تكرارات داخلية وطرفية.

لأطوال 2 و3 و4 و5، كانت الأعداد بعد هذا الاستبعاد 36 و156 و486 و1278 على الترتيب. جمعها يعطي 1956. هذه قوائم حواف مختلفة؛ لا نعد جميع تبديلات ترتيبها لأننا ثبتنا اتجاه الترتيب.

مع كل قائمة استعملنا القيم [-5,-4,-2,0,2,4,5,6] بالشكل (2,4). لا تغير إعادة تشكيل قيم الفحص ترتيبها في العد؛ قارننا النتائج في المواضع نفسها، وحفظنا شكل المصفوفة.

لكل حالة ستة فحوص: خرج False وشكله ونوعه مقابل المرجع؛ وخرج True كذلك؛ واتفاق كل منهما مع خيار searchsorted المقابل بفحصين؛ وشروط الفئات أو الطرفين الخارجيين؛ وثبات بايتات B وX وشكليهما.

أضفنا مثال الحواف الأربع والقيم السبع حالةً أخرى بهذه الفحوص الستة. ثم راجعنا خمسة أمور إضافية: المتجهين المعلنين، وغياب الفهرس 2، والفرق عند 2، والفرق عند 7، وفشل قراءة الحواف بالمتجه المحتوي على 4.

الحساب (1956+1)×6+5=11747، ومرت الفحوص جميعًا. لا نجعل searchsorted مرجع التوقع المستقل؛ دورها هنا مقارنة إضافية، بينما التوقع يأتي من العد وشروط المجالات.

النطاق حواف int64 غير متناقصة ذات قيمتين مختلفتين على الأقل، وقيم int64 منتهية، بمدخل متجه أو مصفوفة ذات أبعاد موجبة. لم نفحص حواف متناقصة أو متساوية كلها أو فارغة، ولا NaN أو اللانهاية أو الأعداد المركبة أو التقريب العشري.

لم نفحص sorter أو الأداء أو ملكية الذاكرة أو حساب مدرج تكراري. ثبات بايتات المدخلين في التجربة لا يحدد ما إذا كان ناتج آخر يشاركهما التخزين.

القضية التي نراجعها هي الفئة الخالية بين حافتين متساويتين. يمكن تغيير جهة شمول الطرف والانتقال إلى فئة مجاورة، بينما يظل المجال بين الحافتين فارغًا.

قيمة المثالright=Falseright=True
-400
-310
111
231
633
743
844

للتوسع: حدود واجهة المدرج.

المراجع

  1. NumPy 2.3 — digitize
  2. NumPy 2.3 — searchsorted

أُعدّ هذا المقال بمساعدة الذكاء الاصطناعي، وخضع لمراجعة ذاتية بالأداة نفسها. لا يُنسب إلى مراجع بشري أو خبير مستقل. منهجية المحتوى.