Series的打印效果,让我们感觉它像个二维表格,实际上它还是一维的,其索引和numpy的一维数组比较类似,但还是有点区别的。
In [23]: se = pd.Series(np.linspace(1,4,5),index=list('abcde')) In [24]: se Out[24]: a 1.00 b 1.75 c 2.50 d 3.25 e 4.00 dtype: float64 In [28]: se['b'] # 利用我们专门指定的索引进行检索 Out[28]: 1.75 In [29]: se[2] # 实际上默认还有一个从0开始的索引供我们使用 Out[29]: 2.5 In [30]: se[2:4] Out[30]: c 2.50 d 3.25 dtype: float64 In [31]: se[['b','a','d']] # 根据索引顺序,值进行相应的排序,而不是我们认为的按原来的顺序 Out[31]: b 1.75 a 1.00 d 3.25 dtype: float64 In [32]: se[[1,3]] # 左闭右开 ,千万不要写成se[1,3] Out[32]: b 1.75 d 3.25 dtype: float64 In [33]: se[se>2] Out[33]: c 2.50 d 3.25 e 4.00 dtype: float64 In [35]: se['b':'c'] # 什么!居然是左闭右也闭! Out[35]: b 1.75 c 2.50 dtype: float64 In [36]: se['b':'c'] = 6 # 这样会修改原Series In [37]: se Out[37]: a 1.00 b 6.00 c 6.00 d 3.25 e 4.00 dtype: float64
注意:如果你的Series是显式的整数索引,那么s[1]
这样的取值操作会使用显式索引,而s[1:3]
这样的切片操作却会使用隐式索引。Pandas开发人员在历史中为这种问题头疼不已,但没办法,现在还是这么混乱。
In [21]: s = pd.Series(['a','b','c'], index=[1,3,5]) In [22]: s Out[22]: 1 a 3 b 5 c dtype: object In [23]: s[1] Out[23]: 'a' In [24]: s[1:3] Out[24]: 3 b 5 c dtype: object
对于DataFrame这种二维表格,情况有点不太一样,请务必注意!
核心思维:在DataFrame中,优先按列操作!
In [38]: df = pd.DataFrame(np.arange(16).reshape(4,4), index=list('abcd'),columns=['one','two','three','four']) In [39]: df Out[39]: one two three four a 0 1 2 3 b 4 5 6 7 c 8 9 10 11 d 12 13 14 15 In [40]: df['two'] # 对于DataFrame默认是按列索引 Out[40]: a 1 b 5 c 9 d 13 Name: two, dtype: int32 In [41]: df['b'] # KeyError,不能直接按行索引 In [43]: df[['one','four']] Out[43]: one four a 0 3 b 4 7 c 8 11 d 12 15 In [44]: df[:2] # 什么!切片的时候居然是按行进行! Out[44]: one two three four a 0 1 2 3 b 4 5 6 7 In [46]: df['c':'d'] # 注意闭合区间 Out[46]: one two three four c 8 9 10 11 d 12 13 14 15 In [47]: df ['one':'three'] # 试图用列索引来切片,但明显后台按行索引去找了,没找到。 Out[47]: Empty DataFrame Columns: [one, two, three, four] Index: [] In [48]: df < 5 Out[48]: one two three four a True True True True b True False False False c False False False False d False False False False In [49]: df[df<5] = 0 # 这一波操作和numpy很类似 In [50]: df Out[50]: one two three four a 0 0 0 0 b 0 5 6 7 c 8 9 10 11 d 12 13 14 15
是不是觉得好难理解记忆?还是numpy那种索引方式更符合人的思维习惯?没关系,Pandas考虑到了这一点,提供了类似numpy的行+列的索引标签,也就是loc和iloc。这两者差一个字母i。后者是以隐含的整数索引值来索引的,前者则使用你指定的显式的索引来定位值。
In [50]: df Out[50]: one two three four a 0 0 0 0 b 0 5 6 7 c 8 9 10 11 d 12 13 14 15 In [51]: df.loc['b', ['two','four']] # 使用显式索引值,用逗号分隔行和列参数 Out[51]: two 5 four 7 Name: b, dtype: int32 In [53]: df.loc['b':, 'two':'four'] # 切片方式,注意区间 Out[53]: two three four b 5 6 7 c 9 10 11 d 13 14 15 In [54]: df.iloc[2, [3, 0, 1]] # 用隐含的整数索引检索,但是这个打印格式好别扭 Out[54]: four 11 one 8 two 9 Name: c, dtype: int32 In [55]: df.iloc[2] Out[55]: one 8 two 9 three 10 four 11 Name: c, dtype: int32 In [56]: df.iloc[1:,2:3] # 注意区间 Out[56]: three b 6 c 10 d 14 In [57]: df.iloc[:,:3][df.three>5] # 先切片,再布尔判断 Out[57]: one two three b 0 5 6 c 8 9 10 d 12 13 14
提示:老版本的ix标签已经不提倡使用了。
df.loc['行', '列']
iloc很好用。
iloc很好用。
因为DataFrame是二维的,类似于数据库表,所以默认按列取值,这很符合常理。