Python 以多次包装代替状态变化,首先考虑创建一个名为Ranked_X
的命名元组子类,包含r_x
和ranked_y
两个属性。其中ranked_y
是一个Ranked_Y
实例,Ranked_Y
包含两个属性:r_y
和raw
,虽然易于构建,但难以处理,因为r_x
和r_y
不在同一级结构中。下面介绍一个略复杂的包装过程,以得到简单的结果数据结构。
我们希望输出数据如下所示:
class Ranked_XY(NamedTuple):
r_x: float
r_y: float
raw: Pair
该命名元组包含多个对等的属性,这种结构比深层嵌套结构易于处理。在某些应用中,需要多次变换数据,这里只有两次变换:对x
和y
求等级值。整个过程分为两步:首先像前面那样简单包装,然后是更通用的“拆包-再包装”。
基于y
等级排序进行x-y
等级排序如下所示:
def rank_xy(pairs: Sequence[Pair]) -> Iterator[Ranked_XY]:
return (
Ranked_XY(
r_x=r_x, r_y=rank_y_raw[0], raw=rank_y_raw[1])
for r_x, rank_y_raw in
rank(rank_y(pairs), lambda r: r.raw.x)
)
首先通过rank_y()
函数创建Rank_Y
对象,然后对这些对象应用rank()
函数,基于原始数据中的x
属性求等级值。该函数返回一个二元组:x
等级值和Rank_Y
对象。最后基于x
等级值r_x
、y
等级值rank_y_raw[0]
和原始对象rank_y_raw[1]
创建了Ranked_XY
对象。
第二个函数展示了为元组添加数据的一种更通用的方法,Ranked_XY
对象的构建过程演示了如何从原有数据中拆包,并再次打包形成更复杂的结构,这是向元组中添加新变量的一种常用方法。
样本数据如下所示:
>>> data = (Pair(x=10.0, y=8.04), Pair(x=8.0, y=6.95),
... Pair(x=13.0, y=7.58), Pair(x=9.0, y=8.81),
etc.
... Pair(x=5.0, y=5.68))
可创建等级对象如下所示:
>>> list(rank_xy(data))
[Ranked_XY(r_x=1.0, r_y=1.0, raw=Pair(x=4.0, y=4.26)),
Ranked_XY(r_x=2.0, r_y=3.0, raw=Pair(x=5.0, y=5.68)),
Ranked_XY(r_x=3.0, r_y=5.0, raw=Pair(x=6.0, y=7.24)),
etc.
Ranked_XY(r_x=11.0, r_y=10.0, raw=Pair(x=14.0, y=9.96))]
有了x
和y
的等级值,就可以计算斯皮尔曼等级顺序相关度了,最终可以根据原始数据算出斯皮尔曼等级相关系数。
前面的多次求等级值的方法涉及拆解元组并创建新的包含附加属性的单层元组,当需要从输入数据中计算多个目标值时,这是一种常用的方法。