numpy 和 pandas(处理数据的 python 库)中,有很多表示二维数组的类。为了定位到二维数组中的数组,这些类也提供了很多实例方法,比如脚标方法(e.g. data[0]
)。但除了脚标方法这个概念,numpy 和 pandas 在定位方法的设计上有很多不同。我们在这里简单梳理一下。
pandas 中的 loc 和 iloc
在 pandas 中,定位n个竖列(column)用脚标方法[]
:
df['column']
返回一个包含当前竖列数据的pd.Series
对象df[['column1', 'column2']]
返回一个包含两个竖列数据的pd.DataFrame
对象
但因为脚标方法被用来定位 columns,定位横排( rows )的时候用什么呢?pandas 想出的方法是创造两个新的对象属性 loc
和 iloc
,并用他们来访问 rows。
比如,对于这样一个 DataFrame:
1 | df = pd.DataFrame(data=[[1,2,3], [4,5,6], [7,8,9]], columns=['A','B','C'], index=['x','y','z']) |
A | B | C | |
---|---|---|---|
x | 1 | 2 | 3 |
y | 4 | 5 | 6 |
z | 7 | 8 | 9 |
其中,x, y, z 就是 df 的 index(在这个 df 中,index 都是 string):
1 | print(df.index) |
要想通过这些 df 的 index 来访问一整个 row 的数据,我们需要先访问 df 的 loc 属性,然后才能使用 index 作为脚标访问一整行的数据:
1 | print(df.loc) |
同时,pandas 还允许我们按照 rows 的顺序来访问数据,也就是像普通的 list 一样,用数字 index 来访问 df 中的数据。但就像上面的 loc 一样,我们这里也需要先访问 df 的一个属性,叫 iloc
属性:
1 | print(df.iloc) |
总之,因为 pandas 的设计,我们在按 rows 来访问 DataFrame 数据之前,都需要先访问 loc
或者 iloc
属性,两者的区别是传入的脚标是否被视为顺序的 index。
其他 pandas 的类也有类似设计,比如 pd.Series
,只不过后者通常是一维的,很多时候直接脚标访问数据就可以了。
numpy 的设计
我们在上面讨论了 pandas 中的方法设计,而 numpy 中是很不一样的设计风格。
比如,如果把上面的 df 转化为 numpy.ndarray
1 | array = np.asarray(df) |
然后访问一个 row 的数据:
1 | array[0] # => [1,2,3] |
或者访问一个 column 下的数据:
1 | array[:,0] # => [1,4,7] |
显然,numpy 采用的方法跟 pandas 不一样,在按‘行序号“访问 ndarray 时,不需要先访问 iloc 一类的属性。而且,ndarray 的 []
方法允许传入两个或两组脚标,第一个代表 rows 的定位,第二个代表 columns 的定位。(备注,pandas 的 DataFrame 的 iloc 属性也允许传入两个或两组角标,用法和 numpy 的 ndarray 基本一样)
What’s more
最后,总结一下,从上面的例子中看出 numpy 和 pands 对于二维数据(或者n维):
- 如果传入的脚标是一个单独的 index 的值,那么返回的数据就会降低到一维(n-1 维)
- 如果传入的脚标是个包含 index 的数组(
:
也算是数组),那么返回的数据不会降维
不论是通过 iloc,loc 的属性间接访问数据,还是直接传入脚标,上面这条设计是个共同点。
(这是归纳法得出的一个结论,吧)