pandas

重新索引

pandas对象的一个重要方法,其作用是创建一个适应新索引的新对象。

reindex在Series上的应用
In [3]: obj = Series([4.5, 7.2, -5.3, 3.6], index=['d','b','a','c'])

In [4]: obj
Out[4]:
d    4.5
b    7.2
a   -5.3
c    3.6
dtype: float64

In [5]: obj2 = reindex(['a', 'b', 'c', 'd', 'e'])

In [6]: obj2 = obj.reindex(['a', 'b', 'c', 'd', 'e'])

In [7]: obj2
Out[7]:
a   -5.3
b    7.2
c    3.6
d    4.5
e    NaN   #如果新索引之前不存在,那么它的值就为缺失值
dtype: float64

Series的reindex函数将会根据新索引对数据重新排列,并且返回一个新的Series对象。如果某个索引不存在,那么它对应的值就为缺失值。

如果想要对缺失值进行补充,那么也有下面这几个方法:

In [8]: obj.reindex(['a', 'b', 'c', 'd', 'e'],fill_value=0)
Out[8]:
a   -5.3
b    7.2
c    3.6
d    4.5
e    0.0
dtype: float64

这里直接预设了填充值为0,意味着该Series中所有的空缺值都将被替换成0
另外一种方法是:

obj3 = Series(['blue','purple','yellow'], index=[0, 2, 4])

In [10]: obj3.reindex(range(6), method='ffill')  # 'ffill'为前向填充,缺失值将前一位数据作为填充值,反之就是后向填充'bfill'

Out[10]:
0      blue
1      blue
2    purple
3    purple
4    yellow
5    yellow
dtype: object

In [11]: obj3
Out[11]:
0      blue
2    purple
4    yellow
dtype: object

如果不想把填充值固定,也可以考虑使用method选项,它可以依据前后数据做填充处理。

reindex在DataFrame上的应用

reindex不单可以修改行索引,也可以修改DataFrame的列索引

In [14]: frame = DataFrame(np.arange(9).reshape((3, 3)), index=['a', 'c', 'd'], columns=['Ohio', 'Texas', 'California'])

In [15]: frame
Out[15]:
   Ohio  Texas  California
a     0      1           2
c     3      4           5
d     6      7           8

In [16]: frame2 = frame.reindex(['a','b','c','d'])

In [17]: frame2
Out[17]:
   Ohio  Texas  California
a   0.0    1.0         2.0
b   NaN    NaN         NaN
c   3.0    4.0         5.0
d   6.0    7.0         8.0

同Series,在修改行索引的时候出现索引不存在的情况就会引入缺失值NaN

如何重新索引列:

In [18]: states = ['Texas', 'Utah', 'California']

In [19]: frame.reindex(columns=states)
Out[19]:
   Texas  Utah  California
a      1   NaN           2
c      4   NaN           5
d      7   NaN           8

method插值能否同时对行列产生作用

In [38]: frame.reindex(index=['a','b','c','d'],method='ffill', columns = ['Texas','Utah','California'])

>>> index must be monotonic increasing or decreasing

按照书中的写法,发现在现在这个版本中已经不适用了,会出现错误。在这个方法中如果存在插值属性method,那行索引和列索引都将会被补充,但是在例子中列索引并不像行索引一样是有序的,所以才会出现这的错误。

In [39]: frame.reindex(index=['a','b','c','d'], columns = ['Texas','Utah','California']).ffill()
Out[39]:
   Texas  Utah  California
a    1.0   NaN         2.0
b    1.0   NaN         2.0
c    4.0   NaN         5.0
d    7.0   NaN         8.0

改成这种写法就可以了。

丢弃指定轴上的项

丢弃指定轴上的项drop()在清理数据中是一个非常重要的功能。

drop函数在Series上的应用:

In [40]: obj = Series(np.arange(5.), index=['a','b','c','d','e'])

In [41]: new_obj = obj.drop('c')

In [42]: new_obj
Out[42]:
a    0.0
b    1.0
d    3.0
e    4.0
dtype: float64

当然也可以同时删除多个项:

In [43]: obj.drop(['d','c'])
Out[43]:
a    0.0
b    1.0
e    4.0
dtype: float64

drop函数在DataFrame上的应用

In [45]: data = DataFrame(np.arange(16).reshape(4,4), index=['Ohio','Colorado','Utah','New York'], columns=['one','two','thre
    ...: e','four'])

In [46]: data
Out[46]:
          one  two  three  four
Ohio        0    1      2     3
Colorado    4    5      6     7
Utah        8    9     10    11
New York   12   13     14    15

In [47]: data.drop(['Colorado', 'Ohio'])
Out[47]:
          one  two  three  four
Utah        8    9     10    11
New York   12   13     14    15

如果是删除行索引,同Series我们可以直接删除任意一个或多个轴上的值。

如果要删除列索引

In [50]: data.drop('two')

 >>> KeyError: "['two'] not found in axis"

它是不能直接删除的,会出现报错。意思是在默认的轴上并没有发现two这个索引。
因为dop函数默认的轴是横向的,如果想要删除某个列就必须告诉它我要删除纵向的轴。可通过下面这个方式:

In [49]: data.drop('two', axis=1)
Out[49]:
          one  three  four
Ohio        0      2     3
Colorado    4      6     7
Utah        8     10    11
New York   12     14    15
In [51]: data.drop(['two','four'], axis=1)
Out[51]:
          one  three
Ohio        0      2
Colorado    4      6
Utah        8     10
New York   12     14

索引、选区和过滤

Series最基本的索引:
In [52]: obj = Series(np.arange(4), index=['a','b','c','d'])

In [53]: obj['b']
Out[53]: 1

In [54]: obj[1]
Out[54]: 1
Series的切片索引、选取和过滤:
In [55]: obj[2:4]   #切片索引
Out[55]:
c    2
d    3
dtype: int64

In [56]: obj[[1, 3]]  # 选取索引
Out[56]:
b    1
d    3
dtype: int64

In [57]: obj[obj < 2] #过滤
Out[57]:
a    0
b    1
dtype: int64

这里还有一种比较好玩的切片选取方式,就是利用标签来切片:

In [58]: obj['b':'c']
Out[58]:
b    1
c    2
dtype: int64

如果是用标签来切片的情况下,它与Python传统切片不同,切片末端的数据也会被选取到。

DataFrame的切片索引、选取和过滤

DataFrame最基本的索引:

In [61]: data = DataFrame(np.arange(16).reshape((4,4)), index=['Ohio','Colorado','Utah','New York'], columns=['one','two','th
    ...: ree','four'])

In [62]: data
Out[62]:
          one  two  three  four
Ohio        0    1      2     3
Colorado    4    5      6     7
Utah        8    9     10    11
New York   12   13     14    15

In [63]: data['two']
Out[63]:
Ohio         1
Colorado     5
Utah         9
New York    13
Name: two, dtype: int64

In [64]: data[['three','two']]
Out[64]:
          three  two
Ohio          2    1
Colorado      6    5
Utah         10    9
New York     14   13

DataFrame的切片和过滤:

In [65]: data[:2]   #切片过程中,DataFrame默认也是选取行
Out[65]:
          one  two  three  four
Ohio        0    1      2     3
Colorado    4    5      6     7

布尔型数组也是默认选取行

In [66]: data[data['three'] > 5]
Out[66]:
          one  two  three  four
Colorado    4    5      6     7
Utah        8    9     10    11
New York   12   13     14    15

通过布尔型DataFrame进行选取:

In [69]: data < 5
Out[69]:
            one    two  three   four
Ohio       True   True   True   True
Colorado   True  False  False  False
Utah      False  False  False  False
New York  False  False  False  False

再看一下data里有哪些数据是<5

In [70]: data[data < 5]
Out[70]:
          one  two  three  four
Ohio      0.0  1.0    2.0   3.0
Colorado  4.0  NaN    NaN   NaN
Utah      NaN  NaN    NaN   NaN
New York  NaN  NaN    NaN   NaN

把这些值全都改成0:

In [71]: data[data < 5] = 0

In [72]: data
Out[72]:
          one  two  three  four
Ohio        0    0      0     0
Colorado    0    5      6     7
Utah        8    9     10    11
New York   12   13     14    15

进阶选取,先选取列数据再选取行数据:
在新版本pandas中,复杂的选取方式我们可以通过以下2种方式loc函数和iloc函数。

loc函数

loc函数有以下多种方式来选取以及过滤数据的:

  • 标签类型
  • 切片
  • 布尔值/逻辑判断

它的语法为data.loc[<row selection>, <column selection>]

标签类型

In [75]: data.loc['Colorado',['two','three']]
Out[75]:
two      5
three    6
Name: Colorado, dtype: int64
In [101]: data.loc[:'Utah', 'two']
Out[101]:
Ohio        0
Colorado    5
Utah        9
Name: two, dtype: int64

切片

In [112]: data.loc['Utah',:'two']
Out[112]:
one    8
two    9
Name: Utah, dtype: int64

布尔值/逻辑判断

In [116]: data.three > 5
Out[116]:
Ohio        False
Colorado     True
Utah         True
New York     True
Name: three, dtype: bool
In [115]: data.loc[data.three > 5]
Out[115]:
          one  two  three  four
Colorado    0    5      6     7
Utah        8    9     10    11
New York   12   13     14    15

由于data.three > 5最终会返回一个Series对象,DataFrame会通过这个布尔型Series来相互匹配选取布尔值True对应的数据最终得到了过滤后的数据。

iloc函数

iloc函数则是基于整数参数来获取数据的,它的语法为data.loc[<row selection>, <column selection>]

In [96]: data.iloc[2]
Out[96]:
one       8
two       9
three    10
four     11
Name: Utah, dtype: int64

单独选择了第三行,返回UtahSeries对象。因为参数中是一个单独的整数,所以iloc函数会返回Series对象。
如果想要它返回DataFrame对象,可以这么写:

In [119]: data.iloc[[2]]
Out[119]:
      one  two  three  four
Utah    8    9     10    11

iloc函数中,传入一个数组就可以了。

行列混合选取:

In [117]: data.iloc[[0,1,2],[0,1]]
Out[117]:
          one  two
Ohio        0    0
Colorado    0    5
Utah        8    9

选取最后一行:

In [120]: data.iloc[-1]
Out[120]:
one      12
two      13
three    14
four     15
Name: New York, dtype: int64