أفضل طريقة لإنشاء مجموعة NumPy من القاموس؟

StackOverflow https://stackoverflow.com/questions/601477

  •  03-07-2019
  •  | 
  •  

سؤال

لقد بدأت للتو في استخدام NumPy لذا ربما أفتقد بعض المفاهيم الأساسية...

ما هي أفضل طريقة لإنشاء مصفوفة NumPy من قاموس تكون قيمه عبارة عن قوائم؟

شيء من هذا القبيل:

d = { 1: [10,20,30] , 2: [50,60], 3: [100,200,300,400,500] }

يجب أن يتحول إلى شيء مثل:

data = [
  [10,20,30,?,?],
  [50,60,?,?,?],
  [100,200,300,400,500]
]

سأقوم ببعض الإحصائيات الأساسية في كل صف، على سبيل المثال:

deviations = numpy.std(data, axis=1)

أسئلة:

  • ما هي الطريقة الأفضل/الأكثر فاعلية لإنشاء numpy.array من القاموس؟القاموس كبير؛بضعة ملايين من المفاتيح، يحتوي كل منها على 20 عنصرًا تقريبًا.

  • يختلف عدد القيم لكل "صف".إذا فهمت بشكل صحيح أن numpy يريد حجمًا موحدًا، فماذا أقوم بملء العناصر المفقودة لجعل std() سعيدًا؟

تحديث:شيء واحد نسيت أن أذكره - على الرغم من أن تقنيات بايثون معقولة (على سبيل المثال.يعد التكرار على بضعة ملايين من العناصر أمرًا سريعًا)، فهو مقيد بوحدة معالجة مركزية واحدة.تتكيف عمليات Numpy بشكل جيد مع الأجهزة وتضرب جميع وحدات المعالجة المركزية (CPUs)، لذا فهي جذابة.

هل كانت مفيدة؟

المحلول

لا تحتاج إلى إنشاء صفائف numpy للاتصال بـ numpy.std().يمكنك استدعاء numpy.std()‎ في حلقة فوق كافة قيم القاموس الخاص بك.سيتم تحويل القائمة إلى مصفوفة numpy بسرعة لحساب التباين القياسي.

الجانب السلبي لهذه الطريقة هو أن الحلقة الرئيسية ستكون في بايثون وليس في C.لكن أعتقد أن هذا يجب أن يكون سريعًا بدرجة كافية:ستظل تحسب std بسرعة C، وستوفر الكثير من الذاكرة حيث لن تضطر إلى تخزين 0 قيم حيث يكون لديك صفائف متغيرة الحجم.

  • إذا كنت ترغب في تحسين ذلك بشكل أكبر، فيمكنك تخزين قيمك في قائمة من المصفوفات numpy، بحيث يمكنك إجراء قائمة python -> تحويل المصفوفات numpy مرة واحدة فقط.
  • إذا وجدت أن هذا لا يزال بطيئًا جدًا، فحاول استخدام psycho لتحسين حلقة بايثون.
  • إذا كان هذا لا يزال بطيئًا جدًا، فحاول استخدامه سايثون جنبا إلى جنب مع الوحدة النمطية numpy.هذا درس تعليمي يدعي تحسينات مذهلة في سرعة معالجة الصور.أو ببساطة قم ببرمجة الوظيفة std بأكملها في Cython (انظر هذا للحصول على المعايير والأمثلة مع وظيفة المبلغ)
  • سيكون البديل لـ Cython هو الاستخدام جرعة كبيرة مع numpy.i.
  • إذا كنت تريد استخدام numpy فقط وحساب كل شيء على المستوى C، فحاول تجميع كافة السجلات ذات الحجم نفسه معًا في مصفوفات مختلفة واستدعاء numpy.std() على كل منها.يجب أن يبدو مثل المثال التالي.

مثال مع تعقيد O(N):

import numpy
list_size_1 = []
list_size_2 = []
for row in data.itervalues():
    if len(row) == 1:
      list_size_1.append(row)
    elif len(row) == 2:
      list_size_2.append(row)
list_size_1 = numpy.array(list_size_1)
list_size_2 = numpy.array(list_size_2)
std_1 = numpy.std(list_size_1, axis = 1)
std_2 = numpy.std(list_size_2, axis = 1)

نصائح أخرى

على الرغم من وجود بعض الأفكار المعقولة هنا بالفعل، إلا أنني أعتقد أن ما يلي جدير بالذكر.

قد يؤدي ملء البيانات المفقودة بأي قيمة افتراضية إلى إفساد الخصائص الإحصائية (الأمراض المنقولة جنسيًا، وما إلى ذلك).من الواضح أن هذا هو السبب وراء اقتراح Mapad الحيلة الرائعة من خلال تجميع السجلات بنفس الحجم.المشكلة في ذلك (بافتراض عدم وجود أي بيانات مسبقة عن أطوال السجلات في متناول اليد) هي أنها تتضمن حسابات أكثر من الحل المباشر:

  1. على الأقل يا(ن*سجلN) مكالمات "len" ومقارنات للفرز باستخدام خوارزمية فعالة
  2. على) يتم التحقق في الطريقة الثانية من خلال القائمة للحصول على المجموعات (فهرس البداية والنهاية على المحور "العمودي")

يعد استخدام Psyco فكرة جيدة (إنه سهل الاستخدام بشكل لافت للنظر، لذا تأكد من تجربته).

يبدو أن الطريقة المثلى هي اتباع الإستراتيجية التي وصفها Mapad في النقطة رقم 1، ولكن مع تعديل - ليس لإنشاء القائمة بأكملها، ولكن للتكرار من خلال القاموس لتحويل كل صف إلى numpy.array وإجراء الحسابات المطلوبة.مثله:

for row in data.itervalues():
    np_row = numpy.array(row)    
    this_row_std = numpy.std(np_row)
    # compute any other statistic descriptors needed and then save to some list

على أية حال، فإن بضعة ملايين من الحلقات في لغة بايثون لن تستغرق وقتًا طويلاً كما هو متوقع.بالإضافة إلى ذلك، لا يبدو هذا بمثابة حساب روتيني، لذا من يهتم إذا استغرق الأمر ثانية/دقيقة إضافية إذا تم تشغيله مرة واحدة كل فترة أو حتى مرة واحدة فقط.


صيغة عامة لما اقترحه Mapad:

from numpy import array, mean, std

def get_statistical_descriptors(a):
    if ax = len(shape(a))-1
    functions = [mean, std]
    return f(a, axis = ax) for f in functions


def process_long_list_stats(data):
    import numpy

    groups = {}

    for key, row in data.iteritems():
        size = len(row)
        try:
            groups[size].append(key)
        except KeyError:
            groups[size] = ([key])

    results = []

    for gr_keys in groups.itervalues():             
        gr_rows = numpy.array([data[k] for k in gr_keys])       
        stats = get_statistical_descriptors(gr_rows)                
        results.extend( zip(gr_keys, zip(*stats)) )

    return dict(results)

قاموس numpy

يمكنك استخدام مصفوفة منظمة للحفاظ على القدرة على معالجة كائن numpy بواسطة مفتاح، مثل القاموس.

import numpy as np


dd = {'a':1,'b':2,'c':3}
dtype = eval('[' + ','.join(["('%s', float)" % key for key in dd.keys()]) + ']')
values = [tuple(dd.values())]
numpy_dict = np.array(values, dtype=dtype)

numpy_dict['c']

سوف يخرج الآن

array([ 3.])
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top