Movatterモバイル変換


[0]ホーム

URL:


Welcome, guest|Sign In|My Account|Store|Cart
ActiveState Code »Recipes
LanguagesTagsAuthorsSets

Equally-spaced numbers (linspace)(Python recipe)by Andrew Barnert
ActiveState Code (http://code.activestate.com/recipes/579000/)

An equivalent ofnumpy.linspace, but as a pure-Python lazy sequence.

Like NumPy'slinspace, but unlike thespread andfrange recipes listed here, thenum argument specifies the number of values, not the number of intervals, and the range is closed, not half-open.

Although this is primarily designed for floats, it will work forFraction,Decimal, NumPy arrays (although this would be silly) and evendatetime values.

This recipe can also serve as an example for creating lazy sequences.

See the discussion below for caveats.

Python, 37 lines
Copy to clipboard
 1 2 3 4 5 6 7 8 910111213141516171819202122232425262728293031323334353637
classlinspace(collections.abc.Sequence):"""linspace(start, stop, num) -> linspace object    Return a virtual sequence of num numbers from start to stop (inclusive).    If you need a half-open range, use linspace(start, stop, num+1)[:-1].    """def__init__(self,start,stop,num):ifnotisinstance(num,numbers.Integral)ornum<=1:raiseValueError('num must be an integer > 1')self.start,self.stop,self.num=start,stop,numself.step=(stop-start)/(num-1)def__len__(self):returnself.numdef__getitem__(self,i):ifisinstance(i,slice):return[self[x]forxinrange(*i.indices(len(self)))]ifi<0:i=self.num+iifi>=self.num:raiseIndexError('linspace object index out of range')ifi==self.num-1:returnself.stopreturnself.start+i*self.stepdef__repr__(self):return'{}({}, {}, {})'.format(type(self).__name__,self.start,self.stop,self.num)def__eq__(self,other):ifnotisinstance(other,linspace):returnFalsereturn((self.start,self.stop,self.num)==(other.start,other.stop,other.num))def__ne__(self,other):returnnotself==otherdef__hash__(self):returnhash((type(self),self.start,self.stop,self.num))

For Python 3.3+ code, usecollections.abc.Sequence instead ofcollections.Sequence.


There are two obvious simple algorithms forlinspace (plus some more advanced ones):

  • division first:start + i*(stop-start)/(num-1)
  • multiplication first:(stop*i + start*(num-i-1))/(num-1)

This recipe uses the former, primarily because it's the oneused by NumPy.

Both are simple and fast; neither accumulates errors (both will close to the minimum possible number of 1 ulp errors distributed evenly throughout the range, which is as good as you can hope for with floats); but neither is perfect:

  • Division first underflows denormal numbers to0. (SeeNumPy bug #5437)
  • Multiplication first overflows very large numbers toinf.
  • Multiplication first doesn't match NumPy's results.
  • Division first errors show up worse in a few highly visible cases (e.g.,linspace(0, 1, 11)[3] == 0.30000000000000004).
  • Multiplication first requires types that can be multiplied and divided by integers, so it will not work with, e.g.,datetime. (Note that division first only multiplies and divides _differences_ between values—so, withdatetime,timedeltas.)

For many lazy sequences, a slice should return an instance of the same sequence. This is how the builtinrange works, for instance. However, floating point rounding makes that impossible forlinspace; a slice could at best guarantee a sequence whose values are within 2 ulp of the original values. So, a slice instead returns a list.


Inheriting fromSequence means thatlinspace provides__contains__,index, andcount methods, using the default (linear-search) implementation. It's generally a bad idea to use these (for the same reason it's a bad idea to compare floats with==), but not providing them would meanlinspace is no longer aSequence. Of course anO(1) implementation could be provided pretty easily, but that would just encourage (mis)use.

2 comments

Steven D'Aprano9 years, 2 months ago # |flag

Thanks for linking to my recipes, but you linked to the same one twice :-(

I think you meantspread. (Hope I got the markdown syntax right...)

Steven D'Aprano9 years, 2 months ago # |flag

Ah drat. Let's try that link again:spread

Created byAndrew BarnertonMon, 12 Jan 2015(MIT)
Python recipes (4591)
Andrew Barnert's recipes (2)

Required Modules

Other Information and Tasks

 

Accounts

Code Recipes

Feedback & Information

ActiveState

Privacy Policy |Contact Us |Support

© 2024 ActiveState Software Inc. All rights reserved. ActiveState®, Komodo®, ActiveState Perl Dev Kit®, ActiveState Tcl Dev Kit®, ActivePerl®, ActivePython®, and ActiveTcl® are registered trademarks of ActiveState. All other marks are property of their respective owners.

 x  

[8]ページ先頭

©2009-2026 Movatter.jp