NumPy之order玄学

#order探究
a = numpy.arange(12).reshape(3, 4,order='F')
b=a.flat
print(type(b))  #<class 'numpy.flatiter'>
print(b[...])  #[ 0  3  6  9  1  4  7 10  2  5  8 11]
b[0]=100
print(a)
'''
[[100   3   6   9]
 [  1   4   7  10]
 [  2   5   8  11]]
'''
print(b[...])  #[100   3   6   9   1   4   7  10   2   5   8  11]
'''
对比flat,那就很有意思了,不管原数组是啥order模式,flat后的一维数组都能与原数组相互影响,从这点看貌似flat比ravel()更满足''视图''的定义。但同时仍有很多值得注意的地方。
1、ravel()后仍为ndarray对象,而flat后为flatiter对象,但对于flatiter对象,同样可以a.flat[0]、a.flat[1]、a.flat[...]来访问各个元素。
2、不管原数组order是何模式,flat都是按C扁平化的,而不是按A/K。对于ndarray对象而言,一般是变化前后order不同,就会深拷贝一份。
可为什么flat后order不一致,仍然是浅拷贝呢?可能这就是它返回值身为flatiter对象的特殊之处吧。
'''
'''
到目前为止,其实有一个猜想,它与事实是有冲突的,那就是变化前后order不同,就会深拷贝一份。这句话是不准确的。
冲突点就在之前学的a.T
我们知道a与a.T相互影响,浅拷贝,但a与a.T,它们flags属性中关于存储模式的相反的,一个是C的话,另一个肯定是F,也就是说转置前后,存储的order是不同的,可为什么还是浅拷贝呢?浅拷贝的要求,实质是要求的是元素存储序列不发生改变,从a到a.T,虽然order变了,但只要存储序列不变,那就是浅拷贝。
'''
'''
这时,会自然而然地反问道:“那你怎么确定学到的其他函数,order改变后,存储序列就发生改变了呢?”
这你要搞清楚,a.T与其他如copy()、ravel()、array()、asarray()等创建类方法、函数,是不同的。其他创建类方法、函数,是先确定存储顺序(C/F),再确定存储序列;而a.T则是先确定存储序列再确定存储顺序。前者如果确定后的存储顺序产生的存储序列同原数组的存储序列,它会浅拷贝,如果不同则会深拷贝。后者因为存储序列先天相同,所以一定是浅拷贝,只要修改存储顺序即可。
'''
'''
讲到这儿,不得不提及ndarray对象的shape属性了。对于shape属性而言(区别于方法、函数),利用shape属性修改原数组的形状,为何就是在原数组上进行修改了,而不是说像reshape方法一样,原数组不变,返回一个新的变形后的ndarray对象呢?
我认为其变形的机制本质上是控制ndarray对象每行的元素的个数,而这种机制只适用于原本就是按C顺序存储的序列。若原数组存储顺序为F的话,使用shape属性变形会报错(实践出来确实是这么个现象)。
之所以C模式下能利用shape属性变形,这就是C顺序的特性了,非常方便元素的存取,从序列开始的第一个元素到某某元素,就是第一行,再之后就是第二行第三行。我想,计算机将存储序列展开为二维表,在C模式下,就是依靠shape。只要模式不变,即使shape改变,但对元素地址的索引的架构不会发生改变。那么完全就可以对原数组直接变形,而不是返回个什么东西。
而对比a.T,虽然它和shape属性变形一样,不会改变存储序列,但它会改变存储顺序(C/F),那么对元素地址索引的架构也就要改变,所以需要创建一个新的ndarray实例对象,存储这种索引架构的信息。
'''
'''
其实,一直有个疑惑,order的K值和A值有什么区别,或者说在什么情境下,它们会展现出区别?
就拿ravel()来说,我觉得a.T可能是会有点特殊,但仔细想想,还是没区别。
同一个存储序列,依据不同的存储顺序(C/F),可以展开成不同的二维表,那对不同的二维表进行ravel(order='A')的话,不就是展开的逆操作,变成展开前的存储序列嘛,那order='A'不就是order='K',按存储序列展开嘛。
'''
a = numpy.arange(12).reshape(3, 4)
b=a.T 
print(id(a))  #2137691305520
print(id(a))  #2137691305520
print(id(b))  #2138105724144
print(id(b))  #2138105724144

print(id(b[1][2]))  #2138105985328
print(id(a[2][1]))  #2137685916080
print(id(b[1][2]))  #2138105985328
print(id(b[1][2]))  #2137685916080
print(id(b[1][2]))  #2138105985328
'''
在之前的学习过程中,我就尝试着观察变化前后两数组元素的id,想判断出变化前后两数组的元素是否引用的同一块内存。当时发现数组元素的id太奇怪了。
我依次输出b[0]至b[11]的id,发现它一直在5328、6080这两个值之间不断的跳跃,而直接输出a、b数组的id则不会出现这个状况,这说明b确实是一个新建的ndarray对象,可这元素的id又是咋回事呢?
我又一个间一个的输出a、b各自元素的id,发现所有b的元素id相同,所有a的元素id相同,这难不成还是薛定谔的猫不成?不拿a[0]id与b[0]id对照,b[0]与b[1]id不同;拿a[0]id与b[0]id对照后,b[0]与b[1]id又相同?会不会有这么一种可能性,我不停的访问这个数组的元素id,它们的id值就是左右切换着,哪怕我访问的一直是同一个元素的id。应验了,真的是这样。而且不仅如此,哪怕我再创建个c数组,与a、b数组毫无关系,但我输出c数组的元素id时,发现它和a、b数组元素id一样,在相同的一对不同id值之间左右跳跃。
ndarray实例对象的id是固定不变的,而所有ndarray实例对象元素的id确纠缠在了一起,这可能和nadarray类对象内部机制有关系了。暂不做进一步的研究。
'''

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值