我正在学习Python中的类和方法。
类精度是基于shapely模块的参考多边形和一个或多个分段多边形之间的几个统计值(总共13)的一类。
from numpy import average
#some stat
def ra_or(ref, seg):
return average([(ref.intersection(s).area/ref.area) for s in seg])
def ra_os(ref, seg):
return average([(ref.intersection(s).area/s.area) for s in seg])
def sim_size(ref, seg):
return average([(min(ref.area, s.area)/max(ref.area,s.area)) for s in seg])
def AFI(ref,seg):
return (ref.area - max([s.area for s in seg]))/ref.area
其中ref.intersection(s).area
是reference
和segmented polygon-i
之间的交集区域。
我的课程设计(非常基本,而且可能需要改进)是:
class Accuracy(object):
def __init__ (self,ref,seg = None, noData = -9999):
if seg == None:
self.area = ref.area
self.perimeter = ref.length
self.centroidX = ref.centroid.x
self.centroidY = ref.centroid.y
self.data = [self.centroidX,
self.centroidY,
self.area,
self.perimeter,
noData,
noData,
noData,
noData,
noData]
else:
self.area = ref.area
self.perimeter = ref.length
self.centroidX = ref.centroid.x
self.centroidY = ref.centroid.y
self.segments = len(seg)
self.RAor = ra_or(ref,seg)
self.RAos = ra_os(ref,seg)
self.SimSize = sim_size(ref,seg)
self.AFI = AFI(ref,seg)
self.data = [self.centroidX,
self.centroidY,
self.area,
self.perimeter,
self.segments,
self.RAor,
self.RAos,
self.SimSize,
self.AFI]
from shapely.geometry import Polygon
p1 = Polygon([(2, 4), (4, 4), (4, 2), (2, 2), (2, 4)])
p2 = Polygon([(0, 3), (3, 3), (3, 0), (0, 0), (0, 3)])
accp1 = Accuracy(p1,[p2])
accp1.data
[3.0, 3.0, 4.0, 8.0, 1, 0.25, 0.1111111111111111, 0.44444444444444442, -1.25]
accp1 = Accuracy(p1)
accp1.data
[3.0, 3.0, 4.0, 8.0, -9999, -9999, -9999, -9999, -9999]
发布于 2013-03-14 11:55:24
如果计划将四个函数( ra_or
、ra_os
、sim_size
和AFI
)调用到Accuracy
之外,那么最好将它们保留为函数。如果只有通过Accuracy
才能调用它们,那么就应该使用方法。
类可以帮助组织复杂的代码,但是它们通常不会使代码更快。除非有明显的优势,否则不要使用类--通过继承或多态等等。
如果您想要使用更少内存的更快的代码,请避免在这里使用类。只需为每个属性定义函数即可。
如果您想要“豪华”语法--通过属性引用每个统计数据的能力,那么类就可以了。
如果您计划实例化Accuracy
的实例,但并不总是访问所有属性,则不需要在__init__
中计算它们。您可以使用属性延迟它们的计算。
@property
def area(self):
return self.ref.area
注意,当您编写accp1.area
时,上面的area方法将被调用。注意,在accp1.area
之后没有括号。
需要明确的是,使用属性的好处是,Accuracy
的每个实例在需要统计属性之前都不会计算它们的所有统计属性。使用属性的缺点是,每次访问属性时都会重新计算它们。如果self.ref
或self.seg
发生变化,这可能不是一个不利因素。
此外,您可以使用丹尼斯·奥特卡达的CachedAttribute装饰师.缓存结果,然后只计算属性一次,然后每次只查找一次。
不要对noData
(如noData = -9999
)使用任意的值。使用noData = np.nan
,或者直接跳过noData
并直接使用np.nan
。
import numpy as np
from shapely.geometry import Polygon
nan = np.nan
class Accuracy(object):
def __init__(self, ref, seg=None):
self.ref = ref
self.seg = seg
@property
def area(self):
return self.ref.area
@property
def perimeter(self):
return self.ref.length
@property
def centroidX(self):
return self.ref.centroid.x
@property
def centroidY(self):
return self.ref.centroid.y
@property
def data(self):
return [self.centroidX,
self.centroidY,
self.area,
self.perimeter,
self.segments,
self.RAor,
self.RAos,
self.SimSize,
self.AFI]
@property
def segments(self):
if self.seg:
return len(self.seg)
else:
return nan
@property
def RAor(self):
if self.seg:
return np.average(
[(self.ref.intersection(s).area / self.ref.area) for s in self.seg])
else:
return nan
@property
def RAos(self):
if self.seg:
return np.average(
[(self.ref.intersection(s).area / s.area) for s in self.seg])
else:
return nan
@property
def SimSize(self):
if self.seg:
return np.average(
[(min(self.ref.area, s.area) / max(self.ref.area, s.area))
for s in self.seg])
else:
return nan
@property
def AFI(self):
if self.seg:
return (self.ref.area - max([s.area for s in self.seg])) / self.ref.area
else:
return nan
p1 = Polygon([(2, 4), (4, 4), (4, 2), (2, 2), (2, 4)])
p2 = Polygon([(0, 3), (3, 3), (3, 0), (0, 0), (0, 3)])
accp1 = Accuracy(p1, [p2])
print(accp1.data)
# [3.0, 3.0, 4.0, 8.0, 1, 0.25, 0.1111111111111111, 0.44444444444444442, -1.25]
accp1 = Accuracy(p1)
print(accp1.data)
# [3.0, 3.0, 4.0, 8.0, nan, nan, nan, nan, nan]
下面是如何将数据(作为numpy数组)保存到CSV文件中:
np.savetxt('/tmp/mytest.txt', np.atleast_2d(accp1.data), delimiter=',')
下面是你怎么把它读回来的:
data = np.genfromtxt('/tmp/mytest.txt', dtype=None)
print(data)
# [ 3. 3. 4. 8. nan nan nan nan nan]
发布于 2013-03-21 16:24:04
我对待这个类的方式和unutbu一样,只是将多边形存储为类的属性,并使用属性和方法进行分析。我认为唯一不同的做法是将其实现为多边形的一个子类,因此任何给定的实例都可以根据需要将自己与任何其他多边形进行比较。我不打算勾勒出细节,但我希望它能像这样工作:
sp1 = SmartPolygon([(2, 4), (4, 4), (4, 2), (2, 2), (2, 4)])
sp2 = SmartPolygon([(0, 3), (3, 3), (3, 0), (0, 0), (0, 3)])
sp1.accuracy()
>>> (3.0, 3.0, 4.0, 8.0, nan, nan, nan, nan, nan)
sp1.accuracy(sp2)
>>> (3.0, 3.0, 4.0, 8.0, 1, 0.25, 0.1111111111111111, 0.44444444444444442, -1.25)
其他想法,没有特别的顺序:
作为它自己的类,我个人会使用不同的名称。“‘Accuracy”是你想从对象身上学到的东西的一个方面,但并不能真正代表对象是什么。我将这个类称为类似于PolygonComparison的类,或者称为描述性的,但理想情况下更简洁。我不知道这是否正式是毕达通的,但我认为类是名词,函数/方法是动词,通常这样命名。
你的风格中有一些细微的不一致之处,主要是因为有时在你不该使用的地方加上空格,反之亦然。这些通常不会影响您的代码如何运行,但更多的是可读性、可理解性和可调试性。例如,
def __init__ (self,ref,seg = None, noData = -9999):
# Note spacing: ^ ^ ^ ^
通常被写成
def __init__(self, ref, seg=None, noData=-9999):
然后,简单地看一下,该方法有三个参数,其中两个参数具有默认值。我建议看一下PEP 8风格的指南。
最后,请注意,您的__init__
方法中有一些冗余:
def __init__(self, ref, seg=None):
if seg == None:
self.area = ref.area
self.perimeter = ref.length
self.centroidX = ref.centroid.x
self.centroidY = ref.centroid.y
... # etc.
else:
self.area = ref.area
self.perimeter = ref.length
self.centroidX = ref.centroid.x
self.centroidY = ref.centroid.y
...
可以减少到
def __init__(self, ref, seg=None):
self.area = ref.area
self.perimeter = ref.length
self.centroidX = ref.centroid.x
self.centroidY = ref.centroid.y
# Typically you check if something *is* None, rather than *equals* None.
if seg is None:
...
else:
...
https://codereview.stackexchange.com/questions/23929
复制相似问题