تشغيل متوسط في بايثون
-
22-09-2019 - |
سؤال
هل هناك pythonic طريقة بناء قائمة تحتوي على تشغيل متوسط من بعض ؟
بعد القراءة متعة قطعة صغيرة حول المريخ الصناديق السوداء ، كوشي التوزيع, اعتقدت أنه سيكون من المرح لحساب متوسط قيد تشغيل من كوشي توزيع نفسي:
import math
import random
def cauchy(location, scale):
p = 0.0
while p == 0.0:
p = random.random()
return location + scale*math.tan(math.pi*(p - 0.5))
# is this next block of code a good way to populate running_avg?
sum = 0
count = 0
max = 10
running_avg = []
while count < max:
num = cauchy(3,1)
sum += num
count += 1
running_avg.append(sum/count)
print running_avg # or do something else with it, besides printing
أعتقد أن هذا النهج يعمل, ولكن أنا الغريب إذا قد يكون هناك أكثر أناقة نهج بناء هذا running_avg
قائمة من استخدام الحلقات عدادات (مثلا ، قائمة comprehensions).
هناك بعض الأسئلة ذات الصلة ، ولكنها تعالج مشاكل أكثر تعقيدا (نافذة صغيرة الحجم الهائل الترجيح) أو ليست محددة إلى الثعبان:
المحلول
يمكن أن تكتب مولد:
def running_average():
sum = 0
count = 0
while True:
sum += cauchy(3,1)
count += 1
yield sum/count
أو بالنظر إلى مولد كوشي الأرقام وظيفة الأداة عن مجموع تراكمي مولد, هل يمكن أن يكون أنيق مولد التعبير:
# Cauchy numbers generator
def cauchy_numbers():
while True:
yield cauchy(3,1)
# running sum utility function
def running_sum(iterable):
sum = 0
for x in iterable:
sum += x
yield sum
# Running averages generator expression (** the neat part **)
running_avgs = (sum/(i+1) for (i,sum) in enumerate(running_sum(cauchy_numbers())))
# goes on forever
for avg in running_avgs:
print avg
# alternatively, take just the first 10
import itertools
for avg in itertools.islice(running_avgs, 10):
print avg
نصائح أخرى
هل يمكن استخدام coroutines.وهي تشبه إلى مولدات, ولكن يسمح لك لإرسال القيم.Coroutines أضيف في بايثون 2.5, لذا لن ينجح في الإصدارات قبل ذلك.
def running_average():
sum = 0.0
count = 0
value = yield(float('nan'))
while True:
sum += value
count += 1
value = yield(sum/count)
ravg = running_average()
next(ravg) # advance the corutine to the first yield
for i in xrange(10):
avg = ravg.send(cauchy(3,1))
print 'Running average: %.6f' % (avg,)
باعتبارها قائمة على الفهم:
ravg = running_average()
next(ravg)
ravg_list = [ravg.send(cauchy(3,1)) for i in xrange(10)]
التعديلات:
- باستخدام
next()
وظيفة بدلا منit.next()
الأسلوب.هذا هو لذلك سوف تعمل أيضا مع بيثون 3.علىnext()
وظيفة كما تم العودة استدار إلى بيثون 2.6+.
في بايثون 2.5 يمكنك إما استبدال المكالماتit.next()
, أو تحديدnext
وظيفة نفسك.
(شكرا آدم باركين)
لقد حصلت على اثنين من الحلول الممكنة هنا بالنسبة لك.وكلاهما عامة فقط تشغيل متوسط الوظائف التي تعمل على أي قائمة من الأرقام.(يمكن أن تعمل مع أي iterable)
مولد القائم:
nums = [cauchy(3,1) for x in xrange(10)]
def running_avg(numbers):
for count in xrange(1, len(nums)+1):
yield sum(numbers[:count])/count
print list(running_avg(nums))
قائمة على أساس الفهم (في الحقيقة نفس الكود كما في وقت سابق):
nums = [cauchy(3,1) for x in xrange(10)]
print [sum(nums[:count])/count for count in xrange(1, len(nums)+1)]
مولد-compatabile مولد القائم:
تحرير:هذا واحد أنا مجرد اختبار لمعرفة ما إذا كنت يمكن أن تجعل الحل متوافق مع المولدات الكهربائية بسهولة و ما سيكون الأداء.هذا هو ما جئت حتى مع.
def running_avg(numbers):
sum = 0
for count, number in enumerate(numbers):
sum += number
yield sum/(count+1)
راجع إحصائيات الأداء أدناه ، تستحق ذلك.
خصائص الأداء:
تحرير:كما قررت لاختبار Orip مثيرة للاهتمام استخدام عدة مولدات لمعرفة تأثير على الأداء.
باستخدام مرةلا التالية (1,000,000 التكرار 3 مرات):
print "Generator based:", ', '.join(str(x) for x in Timer('list(running_avg(nums))', 'from __main__ import nums, running_avg').repeat())
print "LC based:", ', '.join(str(x) for x in Timer('[sum(nums[:count])/count for count in xrange(1, len(nums)+1)]', 'from __main__ import nums').repeat())
print "Orip's:", ', '.join(str(x) for x in Timer('list(itertools.islice(running_avgs, 10))', 'from __main__ import itertools, running_avgs').repeat())
print "Generator-compatabile Generator based:", ', '.join(str(x) for x in Timer('list(running_avg(nums))', 'from __main__ import nums, running_avg').repeat())
أنا الحصول على النتائج التالية:
Generator based: 17.653908968, 17.8027219772, 18.0342400074
LC based: 14.3925321102, 14.4613749981, 14.4277560711
Orip's: 30.8035550117, 30.3142540455, 30.5146529675
Generator-compatabile Generator based: 3.55352187157, 3.54164409637, 3.59098005295
انظر تعليقات التعليمات البرمجية:
Orip's genEx based: 4.31488609314, 4.29926609993, 4.30518198013
النتائج خلال ثوان ، LC مولد جديد متوافق مع مولد الأسلوب على نحو أسرع ، قد تختلف النتائج الخاصة بك على الرغم.أتوقع الفرق الهائل بين بلدي الأصلي مولد واحد جديد هو حقيقة أن المبلغ ليس محسوبا على الطاير.