数据结构的内置方法

这一节介绍常用的pandas数据结构内置方法。很重要的一节。

创建本节要用到的数据结构。


In [1]:
import numpy as np
import pandas as pd

In [2]:
index  = pd.date_range('1/1/2000', periods=8)
s = pd.Series(np.random.randn(5), index=['a', 'b', 'c', 'd', 'e'])
df = pd.DataFrame(np.random.randn(8, 3), index=index, columns=['A', 'B', 'C'])
wp = pd.Panel(np.random.randn(2,5,4), items=['Item1', 'Item2'], major_axis=pd.date_range('1/1/2000',periods=5),
             minor_axis=['A', 'B', 'C', 'D'])

Head() Tail()

想要预览Series或DataFrame对象,可以使用head()和tail()方法。默认显示5行数据,你也可以自己设置显示的行数。


In [3]:
long_series = pd.Series(np.random.randn(1000))

In [4]:
long_series.head()


Out[4]:
0   -0.712204
1    1.003541
2   -1.151193
3    0.584687
4   -0.414543
dtype: float64

In [5]:
long_series.tail(3)


Out[5]:
997    0.627391
998   -0.906766
999   -0.541169
dtype: float64

属性和 ndarray

pandas对象有很多属性,你可以通过这些属性访问数据。

  • shape: 显示对象的维度,同ndarray
  • 坐标label
    • Series: index
    • DataFrame: index(行)和columns
    • Panel: items, major_axis and minor_axis

可以通过属性进行安全赋值。


In [6]:
df[:2]


Out[6]:
A B C
2000-01-01 0.337211 0.588094 1.301466
2000-01-02 -0.606657 0.009183 0.001601

In [7]:
df.columns = [x.lower() for x in df.columns] #将列名重置为小写

In [8]:
df


Out[8]:
a b c
2000-01-01 0.337211 0.588094 1.301466
2000-01-02 -0.606657 0.009183 0.001601
2000-01-03 0.660376 -1.312065 -2.423232
2000-01-04 0.341942 0.653027 0.855557
2000-01-05 2.796017 -1.075060 -0.448727
2000-01-06 0.491867 0.080065 -0.552485
2000-01-07 -1.599258 -0.051114 -0.443676
2000-01-08 -0.630999 0.558674 0.465817

只想得到对象中的数据而忽略index和columns,使用values属性就可以


In [9]:
s.values


Out[9]:
array([-0.55204355, -0.46409144,  1.01618165, -1.53979293,  0.00783646])

In [10]:
df.values


Out[10]:
array([[  3.37211396e-01,   5.88094284e-01,   1.30146647e+00],
       [ -6.06656985e-01,   9.18285067e-03,   1.60067005e-03],
       [  6.60375728e-01,  -1.31206488e+00,  -2.42323176e+00],
       [  3.41941833e-01,   6.53027341e-01,   8.55557057e-01],
       [  2.79601692e+00,  -1.07506020e+00,  -4.48727468e-01],
       [  4.91867100e-01,   8.00653161e-02,  -5.52484534e-01],
       [ -1.59925789e+00,  -5.11144982e-02,  -4.43675671e-01],
       [ -6.30998968e-01,   5.58673913e-01,   4.65816631e-01]])

In [11]:
type(df.values)


Out[11]:
numpy.ndarray

In [12]:
wp.values


Out[12]:
array([[[ 0.87083136, -0.51316014, -1.62289918, -0.07470496],
        [-0.4668945 , -0.54880645,  0.09181663,  0.20264669],
        [-1.85567727,  1.01278604,  0.37039624, -1.00315488],
        [ 0.9155001 ,  1.11350736, -0.0468761 , -0.82779137],
        [ 0.52935663, -0.99737517, -0.17431866, -0.94927201]],

       [[-0.56941218,  0.69127022,  0.71345597, -0.7124779 ],
        [ 1.74832081,  0.27725204, -0.18463295,  1.29585854],
        [ 1.03911335,  0.8479726 , -0.8960105 , -0.20592655],
        [-1.04280407,  0.95349015,  0.02439139,  0.14193113],
        [ 0.99563275,  0.83506317, -1.36956838, -1.39777443]]])

如果DataFrame或Panel对象的数据类型相同(比如都是 int64),修改object.values相当于直接修改原对象的值。如果数据类型不相同,则根本不能对values属性返回值进行赋值。

注意:

如果对象内数据类型不同,values返回的ndarray的dtype将是能够兼容所有数据类型的类型。比如,有的列数据是int,有的列数据是float,.values返回的ndarray的dtype将是float。

加速的操作

pandas从0.11.0版本开始使用numexpr库对二值数值类型操作加速,用bottleneck库对布尔操作加速。

加速效果对大数据尤其明显。

这里有一个速度的简单对比,使用100,000行* 100列的DataFrame:

所以,在安装pandas后也要顺便安装numexpr, bottleneck。

灵活的二元运算

在所有的pandas对象之间的二元运算中,大家最感兴趣的一般是下面两个:

  • 高维数据结构(比如DataFrame)和低维数据结构(比如Series)之间计算时的广播(broadcasting)行为
  • 计算时有缺失值

广播

DataFrame对象内置add(),sub(),mul(),div()以及radd(), rsub(),...等方法。

至于广播计算,Series的输入是最有意思的。


In [67]:
df = pd.DataFrame({'one' : pd.Series(np.random.randn(3), index=['a', 'b', 'c']),
                       'two' : pd.Series(np.random.randn(4), index=['a', 'b', 'c', 'd']),
                       'three' : pd.Series(np.random.randn(3), index=['b', 'c', 'd'])})

In [68]:
df


Out[68]:
one three two
a -0.819889 NaN -0.748560
b 1.206005 -0.586788 0.630745
c -0.620845 -0.080498 -0.227499
d NaN -1.495108 -1.590267

In [69]:
row = df.ix[1]
row


Out[69]:
one      1.206005
three   -0.586788
two      0.630745
Name: b, dtype: float64

In [70]:
column = df['two']

In [71]:
column


Out[71]:
a   -0.748560
b    0.630745
c   -0.227499
d   -1.590267
Name: two, dtype: float64

In [72]:
df.sub(row, axis='columns')


Out[72]:
one three two
a -2.025895 NaN -1.379305
b 0.000000 0.000000 0.000000
c -1.826850 0.506291 -0.858244
d NaN -0.908320 -2.221013

In [73]:
df.sub(row, axis=1)


Out[73]:
one three two
a -2.025895 NaN -1.379305
b 0.000000 0.000000 0.000000
c -1.826850 0.506291 -0.858244
d NaN -0.908320 -2.221013

In [74]:
df.sub(row, axis='index')


Out[74]:
one three two
a NaN NaN NaN
b NaN NaN NaN
c NaN NaN NaN
d NaN NaN NaN
one NaN NaN NaN
three NaN NaN NaN
two NaN NaN NaN

In [75]:
df.sub(row, axis=0)


Out[75]:
one three two
a NaN NaN NaN
b NaN NaN NaN
c NaN NaN NaN
d NaN NaN NaN
one NaN NaN NaN
three NaN NaN NaN
two NaN NaN NaN

填充缺失值

在Series和DataFrame中,算术运算方法(比如add())有一个fill_value参数,含义很明显,计算前用一个值来代替缺失值,然后再参与运算。注意,如果参与运算的两个object同一位置(同行同列)都是NaN,fill_value不起作用,计算结果还是NaN。

看例子:


In [76]:
df


Out[76]:
one three two
a -0.819889 NaN -0.748560
b 1.206005 -0.586788 0.630745
c -0.620845 -0.080498 -0.227499
d NaN -1.495108 -1.590267

In [91]:
df2 = pd.DataFrame({'one' : pd.Series(np.random.randn(3), index=['a', 'b', 'c']),
                       'two' : pd.Series(np.random.randn(4), index=['a', 'b', 'c', 'd']),
                       'three' : pd.Series(np.random.randn(4), index=['a', 'b', 'c', 'd'])})

In [92]:
df2


Out[92]:
one three two
a -0.745516 -0.657512 -1.358255
b 0.249448 -0.829815 0.258827
c -0.117322 -0.016284 0.144683
d NaN 0.213930 1.766173

In [93]:
df + df2


Out[93]:
one three two
a -1.565406 NaN -0.358255
b 1.455453 -1.416603 0.889572
c -0.738167 -0.096782 -0.082815
d NaN -1.281178 0.175906

In [95]:
df.add(df2, fill_value=0) #注意['a', 'three']不是NaN


Out[95]:
one three two
a -1.565406 -0.657512 -0.358255
b 1.455453 -1.416603 0.889572
c -0.738167 -0.096782 -0.082815
d NaN -1.281178 0.175906

In [ ]:

灵活的比较操作

pandas引入了二元比较运算方法:eq, ne, lt, gt, le。


In [96]:
df.gt(df2)


Out[96]:
one three two
a False False True
b True True True
c False False False
d False False False

In [97]:
df2.ne(df)


Out[97]:
one three two
a True True True
b True True True
c True True True
d True True True

意思操作返回一个和输入对象同类型的对象,值类型为bool,返回结果可以用于检索。

布尔降维 Boolean Reductions

pandas提供了三个方法(any(), all(), bool())和一个empty属性来对布尔结果进行降维。


In [100]:
df>0


Out[100]:
one three two
a False False True
b True False True
c False False False
d False False False

In [101]:
(df>0).all() #与操作


Out[101]:
one      False
three    False
two      False
dtype: bool

In [103]:
(df > 0).any()#或操作


Out[103]:
one       True
three    False
two       True
dtype: bool

同样可以对降维后的结果再进行降维。


In [104]:
(df > 0).any().any()


Out[104]:
True

使用empty属性检测一个pandas对象是否为空。


In [105]:
df.empty


Out[105]:
False

In [106]:
pd.DataFrame(columns=list('ABC')).empty


Out[106]:
True

对于只含有一个元素的pandas对象,对其进行布尔检测,使用bool():


In [108]:
pd.Series([True]).bool()


Out[108]:
True

In [109]:
pd.Series([False]).bool()


Out[109]:
False

In [111]:
pd.DataFrame([[True]]).bool()


Out[111]:
True

In [112]:
pd.DataFrame([[False]]).bool()


Out[112]:
False

比较对象是否相等

一个问题通常有多种解法。一个最简单的例子:df+df和df*2。为了检测两个计算结果是否相等,你可能想到:(df+df == df*2).all(),然而,这样计算得到的结果是False:


In [113]:
df + df == df*2


Out[113]:
one three two
a True False True
b True True True
c True True True
d False True True

In [114]:
(df+df == df*2).all()


Out[114]:
one      False
three    False
two       True
dtype: bool

为什么df + df == df*2 返回的结果含有False?因为NaN和NaN比较厚结果为False!


In [116]:
np.nan == np.nan


Out[116]:
False

还好pandas提供了equals()方法解决上面NaN之间不想等的问题。


In [119]:
(df+df).equals(df*2)


Out[119]:
True

注意

在使用equals()方法进行比较时,两个对象如果数据不一致必为False。


In [120]:
df1 = pd.DataFrame({'c':['f',0,np.nan]})
df1


Out[120]:
c
0 f
1 0
2 NaN

In [121]:
df2 = pd.DataFrame({'c':[np.nan, 0, 'f']}, index=[2,1,0])
df2


Out[121]:
c
2 NaN
1 0
0 f

In [122]:
df1.equals(df2)


Out[122]:
False

In [123]:
df1.equals(df2.sort_index()) #对df2的索引排序,然后再比较


Out[123]:
True

不同类型的对象之间 逐元素比较

你可以直接对pandas对象和一个常量值进行逐元素比较:


In [124]:
pd.Series(['foo', 'bar', 'baz']) == 'foo'


Out[124]:
0     True
1    False
2    False
dtype: bool

In [125]:
pd.Index(['foo', 'bar', 'baz']) == 'foo'


Out[125]:
array([ True, False, False], dtype=bool)

不同类型的对象(比如pandas数据结构、numpy数组)之间进行逐元素的比较也是没有问题的,前提是两个对象的shape要相同


In [128]:
pd.Series(['foo', 'bar', 'baz']) == pd.Index(['foo', 'bar', 'qux'])


Out[128]:
0     True
1     True
2    False
dtype: bool

In [129]:
pd.Series(['foo', 'bar', 'baz']) == np.array(['foo', 'bar', 'qux'])


Out[129]:
0     True
1     True
2    False
dtype: bool

In [130]:
pd.Series(['foo', 'bar', 'baz']) == pd.Series(['foo', 'bar']) #长度不相同


---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-130-a98f3718cffe> in <module>()
----> 1 pd.Series(['foo', 'bar', 'baz']) == pd.Series(['foo', 'bar']) #长度不相同

c:\python27\lib\site-packages\pandas\core\ops.pyc in wrapper(self, other, axis)
    731             name = _maybe_match_name(self, other)
    732             if len(self) != len(other):
--> 733                 raise ValueError('Series lengths must match to compare')
    734             return self._constructor(na_op(self.values, other.values),
    735                                      index=self.index, name=name)

ValueError: Series lengths must match to compare

但要知道不同shape的numpy数组之间是可以直接比较的!因为广播!即使无法广播,也不会Error而是返回False。


In [133]:
np.array([1,2,3]) == np.array([2])


Out[133]:
array([False,  True, False], dtype=bool)

In [134]:
np.array([1, 2, 3]) == np.array([1, 2])


c:\python27\lib\site-packages\ipykernel\__main__.py:1: DeprecationWarning: elementwise == comparison failed; this will raise an error in the future.
  if __name__ == '__main__':
Out[134]:
False

combine_first()

看一下例子:


In [135]:
df1 = pd.DataFrame({'A' : [1., np.nan, 3., 5., np.nan],
                    'B' : [np.nan, 2., 3., np.nan, 6.]})
df1


Out[135]:
A B
0 1.0 NaN
1 NaN 2.0
2 3.0 3.0
3 5.0 NaN
4 NaN 6.0

In [136]:
df2 = pd.DataFrame({'A' : [5., 2., 4., np.nan, 3., 7.],
                        'B' : [np.nan, np.nan, 3., 4., 6., 8.]})
df2


Out[136]:
A B
0 5.0 NaN
1 2.0 NaN
2 4.0 3.0
3 NaN 4.0
4 3.0 6.0
5 7.0 8.0

In [137]:
df1.combine_first(df2)


Out[137]:
A B
0 1.0 NaN
1 2.0 2.0
2 3.0 3.0
3 5.0 4.0
4 3.0 6.0
5 7.0 8.0

解释:

对于df1中NaN的元素,用df2中对应位置的元素替换!

DataFrame.combine()

DataFrame.combine()方法接收一个DF对象和一个combiner方法。


In [140]:
combiner = lambda x,y: np.where(pd.isnull(x), y,x)

In [141]:
df1.combine(df2, combiner)


Out[141]:
A B
0 1.0 NaN
1 2.0 2.0
2 3.0 3.0
3 5.0 4.0
4 3.0 6.0
5 7.0 8.0

统计相关 的方法

Series, DataFrame和Panel内置了许多计算统计相关指标的方法。这些方法大致分为两类:

  • 返回低维结果,比如sum(),mean(),quantile()
  • 返回同原对象同样大小的对象,比如cumsum(), cumprod()

总体来说,这些方法接收一个坐标轴参数:

  • Series不需要坐标轴参数
  • DataFrame 默认axis=0(index), axis=1(columns)
  • Panel 默认axis=1(major), axis=0(items), axis=2(minor)

In [142]:
df


Out[142]:
one three two
a -0.819889 NaN 1.000000
b 1.206005 -0.586788 0.630745
c -0.620845 -0.080498 -0.227499
d NaN -1.495108 -1.590267

In [146]:
df.mean() #axis=0, 计算每一列的平均值


Out[146]:
one     -0.078243
three   -0.720798
two     -0.046755
dtype: float64

In [147]:
df.mean(1) #计算每一行的平均值


Out[147]:
a    0.090055
b    0.416654
c   -0.309614
d   -1.542688
dtype: float64

所有的这些方法都有skipna参数,含义是计算过程中是否剔除缺失值,skipna默认值为True。


In [148]:
df.sum(0, skipna=False)


Out[148]:
one           NaN
three         NaN
two     -0.187021
dtype: float64

In [149]:
df.sum(axis=1, skipna=True)


Out[149]:
a    0.180111
b    1.249962
c   -0.928841
d   -3.085375
dtype: float64

这些函数可以参与算术和广播运算。

比如:


In [152]:
ts_stand = (df-df.mean())/df.std()

In [153]:
ts_stand.std()


Out[153]:
one      1.0
three    1.0
two      1.0
dtype: float64

In [154]:
xs_stand = df.sub(df.mean(1), axis=0).div(df.std(1), axis=0)

In [155]:
xs_stand.std(1)


Out[155]:
a    1.0
b    1.0
c    1.0
d    1.0
dtype: float64

注意cumsum() cumprod()方法 保留NA值的位置。


In [156]:
df.cumsum()


Out[156]:
one three two
a -0.819889 NaN 1.000000
b 0.386116 -0.586788 1.630745
c -0.234729 -0.667286 1.403247
d NaN -2.162394 -0.187021

下面列出常用的方法及其描述。提醒每一个方法都有一个level参数用于具有层次索引的对象。

方法 描述
count 沿着坐标轴统计非空的行数
sum 沿着坐标轴取加和
mean 沿着坐标轴求均值
mad 沿着坐标轴计算平均绝对偏差
median 沿着坐标轴计算中位数
min 沿着坐标轴取最小值
max 沿着坐标轴取最大值
mode 沿着坐标轴取众数
abs 计算每一个值的绝对值
prod 沿着坐标轴求乘积
std 沿着坐标轴计算标准差
var 沿着坐标轴计算无偏方差
sem 沿着坐标轴计算标准差
skew 沿着坐标轴计算样本偏斜
kurt 沿着坐标轴计算样本峰度
quantile 沿着坐标轴计算样本分位数,单位%
cumsum 沿着坐标轴计算累加和
cumprod 沿着坐标轴计算累积乘
cummax 沿着坐标轴计算累计最大
cummin 沿着坐标轴计算累计最小

Note:所有需要沿着坐标轴计算的方法,默认axis=0,即将方法应用到每一列数据上。

Series还有一个nunique()方法返回非空数值 组成的集合的大小。


In [32]:
series = pd.Series(np.random.randn(500))
series[20:500]=np.nan

In [33]:
series[10:20]=5

In [35]:
series.nunique()


Out[35]:
11

In [36]:
series


Out[36]:
0      0.424958
1      0.167252
2     -1.667684
3     -1.375883
4     -0.272095
5     -1.118394
6     -1.478117
7      0.779770
8     -0.824979
9      0.356511
10     5.000000
11     5.000000
12     5.000000
13     5.000000
14     5.000000
15     5.000000
16     5.000000
17     5.000000
18     5.000000
19     5.000000
20          NaN
21          NaN
22          NaN
23          NaN
24          NaN
25          NaN
26          NaN
27          NaN
28          NaN
29          NaN
         ...   
470         NaN
471         NaN
472         NaN
473         NaN
474         NaN
475         NaN
476         NaN
477         NaN
478         NaN
479         NaN
480         NaN
481         NaN
482         NaN
483         NaN
484         NaN
485         NaN
486         NaN
487         NaN
488         NaN
489         NaN
490         NaN
491         NaN
492         NaN
493         NaN
494         NaN
495         NaN
496         NaN
497         NaN
498         NaN
499         NaN
dtype: float64

descrieb(), 数据摘要

describe()方法非常有用,它计算数据的各种常用统计指标(比如平均值、标准差等),计算时不包括NA。拿到数据首先要有大概的了解,使用describe()方法就对了。


In [37]:
series = pd.Series(np.random.randn(1000))
series[::2]=np.nan

In [38]:
series.describe()


Out[38]:
count    500.000000
mean       0.024341
std        0.987292
min       -2.371843
25%       -0.724967
50%        0.011554
75%        0.682236
max        2.763247
dtype: float64

In [39]:
frame = pd.DataFrame(np.random.randn(1000, 5), columns=['a', 'b', 'c', 'd', 'e'])

In [40]:
frame.ix[::2]=np.nan

In [41]:
frame.describe()


Out[41]:
a b c d e
count 500.000000 500.000000 500.000000 500.000000 500.000000
mean -0.030325 0.001974 -0.060932 0.018964 0.027747
std 0.999444 1.027741 0.976023 0.939193 1.108105
min -3.038502 -3.152980 -3.343954 -2.478286 -3.260736
25% -0.722298 -0.654264 -0.698861 -0.632413 -0.705261
50% -0.009268 -0.001924 -0.064390 0.019038 0.042032
75% 0.624942 0.709595 0.550053 0.615007 0.792178
max 2.825107 2.519475 2.820095 3.619928 3.826766

默认describe()只包含25%, 50%, 75%, 也可以通过percentiles参数进行指定。


In [42]:
series.describe(percentiles=[.05, .25, .75, .95])


Out[42]:
count    500.000000
mean       0.024341
std        0.987292
min       -2.371843
5%        -1.474114
25%       -0.724967
50%        0.011554
75%        0.682236
95%        1.693779
max        2.763247
dtype: float64

如果Series内数据是非数值类型,describe()也能给出一定的统计结果


In [43]:
s = pd.Series(['a', 'a', 'b', 'b', 'a', 'a', np.nan, 'c', 'd', 'a'])

In [70]:
s.describe()


Out[70]:
count     9
unique    4
top       a
freq      5
dtype: object

如果DataFrame对象有的列是数值类型,有的列不是数值类型,describe()仅对数值类型的列进行计算。


In [47]:
frame = pd.DataFrame({'a':['Yes', 'Yes', 'NO', 'No'], 'b':range(4)})

In [48]:
frame.describe()


Out[48]:
b
count 4.000000
mean 1.500000
std 1.290994
min 0.000000
25% 0.750000
50% 1.500000
75% 2.250000
max 3.000000

如果非要知道非数值列的统计指标呢?describe提供了include参数,取值范围{'object', 'number', 'all'}。

看一下例子, 注意'object'和'number'都是在列表中,而'all'不需要放在列表中:


In [57]:
frame.describe(include=['object']) #只对非数值列进行统计计算


Out[57]:
a
count 4
unique 3
top Yes
freq 2

In [58]:
frame.describe(include=['number'])


Out[58]:
b
count 4.000000
mean 1.500000
std 1.290994
min 0.000000
25% 0.750000
50% 1.500000
75% 2.250000
max 3.000000

In [59]:
frame.describe(include='all')#'all'不是列表


Out[59]:
a b
count 4 4.000000
unique 3 NaN
top Yes NaN
freq 2 NaN
mean NaN 1.500000
std NaN 1.290994
min NaN 0.000000
25% NaN 0.750000
50% NaN 1.500000
75% NaN 2.250000
max NaN 3.000000

最大/最小值对应的索引值

Series和DataFrame内置的idxmin() idxmax()方法求得 最小值、最大值对应的索引值,看一下例子:


In [60]:
s1 = pd.Series(np.random.randn(5))
s1


Out[60]:
0    0.619835
1   -0.296405
2    0.598713
3    1.735420
4    0.072205
dtype: float64

In [62]:
s1.idxmin(), s1.idxmax() #最小值:-0.296405, 最大值:1.735420


Out[62]:
(1, 3)

In [63]:
df1 = pd.DataFrame(np.random.randn(5,3), columns=list('ABC'))
df1


Out[63]:
A B C
0 -0.403992 -0.267194 0.362908
1 0.509844 -0.191461 -0.212362
2 1.012935 -0.180596 0.050764
3 1.249444 0.082952 1.061835
4 -1.861369 0.674862 -0.084830

In [66]:
df1.idxmin(axis=0)


Out[66]:
A    4
B    0
C    1
dtype: int64

In [67]:
df1.idxmax(axis=1)


Out[67]:
0    C
1    A
2    A
3    A
4    B
dtype: object

如果多个数值都是最大值或最小值,idxmax() idxmin()返回最大值、最小值第一次出现对应的索引值


In [68]:
df3 = pd.DataFrame([2, 1, 1, 3, np.nan], columns=['A'], index=list('edcba'))
df3


Out[68]:
A
e 2.0
d 1.0
c 1.0
b 3.0
a NaN

In [69]:
df3['A'].idxmin()


Out[69]:
'd'

实际上,idxmin和idxmax就是NumPy中的argmin和argmax

value_counts() 数值计数

value_counts()计算一维度数据结构的直方图。


In [71]:
data = np.random.randint(0, 7, size=50)
data


Out[71]:
array([0, 3, 4, 1, 5, 5, 2, 5, 0, 3, 0, 2, 3, 0, 5, 5, 4, 1, 1, 1, 6, 4, 0,
       6, 0, 2, 1, 4, 1, 1, 0, 6, 3, 0, 5, 2, 3, 3, 0, 4, 0, 6, 1, 2, 1, 5,
       1, 1, 5, 0])

In [72]:
s = pd.Series(data)

In [73]:
s.value_counts()


Out[73]:
1    11
0    11
5     8
3     6
4     5
2     5
6     4
dtype: int64

In [75]:
pd.value_counts(data) #也是全局方法


Out[75]:
1    11
0    11
5     8
3     6
4     5
2     5
6     4
dtype: int64

虽然前面介绍过mode()方法了,看两个例子吧:


In [76]:
s5 = pd.Series([1,1,3,3,3,5,5,7,7,7])

In [77]:
s5.mode()


Out[77]:
0    3
1    7
dtype: int64

In [83]:
df5 = pd.DataFrame({"A": np.random.randint(0, 7, size=50),
                    "B": np.random.randint(-10, 15, size=50)})

In [106]:
df5


Out[106]:
A B
0 1 -3
1 1 6
2 0 -8
3 0 4
4 1 -7
5 1 14
6 0 0
7 3 10
8 6 -7
9 3 12
10 0 1
11 5 6
12 0 11
13 1 -4
14 3 -8
15 5 4
16 1 -3
17 6 -8
18 6 -9
19 3 3
20 6 -6
21 2 -1
22 2 4
23 1 8
24 1 9
25 4 -3
26 6 -10
27 6 -9
28 1 -3
29 4 0
30 6 -5
31 1 -1
32 0 10
33 2 -8
34 0 -5
35 3 -5
36 5 5
37 6 3
38 2 4
39 5 -9
40 2 12
41 6 6
42 1 7
43 2 -7
44 1 -5
45 0 1
46 3 -2
47 1 0
48 3 5
49 2 2

In [107]:
df5.mode()


Out[107]:
A B
0 1.0 -8
1 NaN -5
2 NaN -3
3 NaN 4

区间离散化

cut() qcut()方法可以对连续数据进行离散化


In [108]:
arr = np.random.randn(20)

In [109]:
factor = pd.cut(arr, 4)

In [110]:
factor


Out[110]:
[(0.143, 1.156], (0.143, 1.156], (-1.886, -0.869], (1.156, 2.168], (0.143, 1.156], ..., (1.156, 2.168], (-0.869, 0.143], (0.143, 1.156], (0.143, 1.156], (-0.869, 0.143]]
Length: 20
Categories (4, object): [(-1.886, -0.869] < (-0.869, 0.143] < (0.143, 1.156] < (1.156, 2.168]]

In [111]:
factor = pd.cut(arr, [-5, -1, 0, 1, 5]) #输入 离散区间

In [112]:
factor


Out[112]:
[(0, 1], (0, 1], (-5, -1], (1, 5], (0, 1], ..., (1, 5], (-1, 0], (0, 1], (0, 1], (-1, 0]]
Length: 20
Categories (4, object): [(-5, -1] < (-1, 0] < (0, 1] < (1, 5]]

qcut()方法计算样本的分位数,比如我们可以将正态分布的数据 进行四分位数离散化:


In [113]:
arr = np.random.randn(30)

In [114]:
factor = pd.qcut(arr, [0, .25, .5, .75, 1])

In [115]:
factor


Out[115]:
[(-0.0783, 0.444], (-0.0783, 0.444], (-0.799, -0.0783], [-2.71, -0.799], (-0.799, -0.0783], ..., [-2.71, -0.799], (-0.799, -0.0783], (0.444, 1.963], (-0.0783, 0.444], (-0.799, -0.0783]]
Length: 30
Categories (4, object): [[-2.71, -0.799] < (-0.799, -0.0783] < (-0.0783, 0.444] < (0.444, 1.963]]

In [116]:
pd.value_counts(factor)


Out[116]:
(0.444, 1.963]       8
[-2.71, -0.799]      8
(-0.0783, 0.444]     7
(-0.799, -0.0783]    7
dtype: int64

离散区间也可以用极限定义


In [117]:
arr = np.random.randn(20)

In [118]:
factor = pd.cut(arr, [-np.inf, 0, np.inf])

In [119]:
factor


Out[119]:
[(-inf, 0], (-inf, 0], (0, inf], (-inf, 0], (0, inf], ..., (-inf, 0], (-inf, 0], (0, inf], (-inf, 0], (0, inf]]
Length: 20
Categories (2, object): [(-inf, 0] < (0, inf]]

In [ ]:

函数应用

如果你想用自己写的方法或其他库方法操作pandas对象,你应该知道下面的三种方式。 具体选择哪种方式取决于你是想操作整个DataFrame对象还是DataFrame对象的某几行或某几列,或者逐元素操作。

  • 管道 pipe()
  • 基于列或行的函数引用 apply()
  • 对DataFrame对象逐元素计算 applymap()

对管道

DataFrame和Series当然能够作为参数传入方法。然而,如果涉及到多个方法的序列调用,推荐使用pipe()。看一下例子:


In [ ]:
#f, g 和h是三个方法,接收DataFrame对象,返回DataFrame对象
f(g(h(df), arg1=1), arg2=2, arg3=3)

上面一行代码推荐用下面的等价写法:


In [ ]:
(df.pipe(h).pipe(g, arg1=1).pipe(f, arg2=2, arg3=3))

注意 f g h三个方法中DataFrame都是作为第一个参数。如果DataFrame作为第二个参数呢?方法是为pipe提供(callable, data_keyword),pipe会自动调用DataFrame对象。

比如,使用statsmodels处理回归问题,他们的API期望第一个参数是公式,第二个参数是DataFrame对象data。我们使用pipe传递(sm.poisson, 'data'):

pipe灵感来自于Unix中伟大的艺术:管道。pandas中pipe()的实现很简洁,推荐阅读源代码pd.DataFrame.pipe

基于行或者列的函数应用

任意函数都可以直接对DataFrame或Panel某一坐标轴进行直接操纵,只需要使用apply()方法即可,同描述性统计方法一样,apply()方法接收axis参数。


In [5]:
df.apply(np.mean)


Out[5]:
A   -0.082000
B   -0.039589
C   -0.226022
dtype: float64

In [7]:
df.apply(np.mean, axis=1)


Out[7]:
2000-01-01    0.031020
2000-01-02    0.754696
2000-01-03   -0.861633
2000-01-04    0.707869
2000-01-05   -0.191752
2000-01-06    0.329149
2000-01-07   -1.213012
2000-01-08   -0.483304
Freq: D, dtype: float64

In [11]:
df.apply(lambda x: x.max() - x.min())


Out[11]:
A    1.991008
B    3.883607
C    3.555682
dtype: float64

In [12]:
df.apply(np.cumsum)


Out[12]:
A B C
2000-01-01 -0.142261 -0.060360 0.295683
2000-01-02 0.460755 2.086278 -0.189882
2000-01-03 -0.532777 0.994217 -0.689186
2000-01-04 0.464698 2.055012 -0.623848
2000-01-05 0.784671 1.499974 -0.964040
2000-01-06 0.516696 0.778774 1.012581
2000-01-07 0.193691 -0.958194 -0.566480
2000-01-08 -0.656002 -0.316716 -1.808178

In [13]:
df.apply(np.exp)


Out[13]:
A B C
2000-01-01 0.867394 0.941425 1.344044
2000-01-02 1.827624 8.556042 0.615349
2000-01-03 0.370266 0.335524 0.606953
2000-01-04 2.711427 2.888666 1.067520
2000-01-05 1.377091 0.574050 0.711634
2000-01-06 0.764927 0.486169 7.218311
2000-01-07 0.723970 0.176053 0.206169
2000-01-08 0.427546 1.899287 0.288893

灵活运用apply()方法可以统计出数据集的很多特性。比如,假设我们希望从数据中抽取每一列最大值的索引值。


In [21]:
tsdf = pd.DataFrame(np.random.randn(1000, 3), columns=['A', 'B', 'C'],
                   index=pd.date_range('1/1/2000', periods=1000))
tsdf


Out[21]:
A B C
2000-01-01 1.508512 -0.337924 -0.322681
2000-01-02 0.546119 -0.569760 -0.475934
2000-01-03 0.479077 0.141438 -1.540489
2000-01-04 -0.829857 -0.823538 1.643723
2000-01-05 0.255760 1.210986 0.931286
2000-01-06 2.070021 1.276612 -0.115412
2000-01-07 -0.473810 0.291923 -1.695630
2000-01-08 0.602344 -1.268760 0.181028
2000-01-09 1.004540 -0.616671 -0.362409
2000-01-10 0.485239 0.971017 -0.087146
2000-01-11 0.133297 -0.348421 -1.032877
2000-01-12 -0.940945 -0.507634 0.575378
2000-01-13 0.606164 -0.641187 -1.049049
2000-01-14 0.646394 -0.504994 -0.112327
2000-01-15 -0.347899 0.132691 0.400609
2000-01-16 0.621119 -0.004572 -0.340887
2000-01-17 -0.736580 0.399046 0.088845
2000-01-18 -0.912036 0.840877 -0.074514
2000-01-19 1.287786 0.779607 -0.067636
2000-01-20 -0.599940 0.094742 -0.163426
2000-01-21 0.935834 -0.144410 -0.085487
2000-01-22 1.226581 -1.117103 0.246942
2000-01-23 1.530435 -1.438474 0.542377
2000-01-24 -0.838566 -0.324698 1.184812
2000-01-25 -0.311246 -1.377314 -0.431623
2000-01-26 0.801814 0.438467 -1.915434
2000-01-27 0.815048 -1.009805 0.501989
2000-01-28 0.897600 0.628330 0.475561
2000-01-29 0.696502 -0.822199 -0.448787
2000-01-30 0.471048 -1.841923 0.158116
... ... ... ...
2002-08-28 -0.184911 1.282684 0.951569
2002-08-29 -0.656969 -0.103318 -0.464619
2002-08-30 -1.051274 0.722578 -0.795858
2002-08-31 1.869913 -2.879455 -0.092262
2002-09-01 -1.186259 0.897260 -0.770680
2002-09-02 0.898835 -0.175212 -0.485235
2002-09-03 -1.657890 0.588649 0.802933
2002-09-04 -0.184906 -0.596059 0.759456
2002-09-05 1.069876 -1.375438 0.821087
2002-09-06 -0.721034 -0.424185 0.150196
2002-09-07 0.048521 0.938075 0.420614
2002-09-08 1.710716 -0.988647 -1.014892
2002-09-09 0.051754 0.758752 0.068914
2002-09-10 -0.404318 -1.102603 -0.641363
2002-09-11 -0.711666 -0.850081 1.223433
2002-09-12 0.105811 0.540562 -0.662475
2002-09-13 -0.182622 -0.815966 -1.001960
2002-09-14 -0.831867 -0.664711 -1.958620
2002-09-15 -0.178157 -0.865264 0.403366
2002-09-16 0.775322 -0.339516 0.419001
2002-09-17 1.363952 1.164906 0.081826
2002-09-18 0.072301 -0.449992 1.272230
2002-09-19 -0.310564 0.330637 0.183283
2002-09-20 -0.884466 -1.538738 -1.199347
2002-09-21 -1.368203 -0.300517 -2.301899
2002-09-22 -0.751779 0.905494 -1.756754
2002-09-23 -0.026914 -0.329971 -1.294168
2002-09-24 0.511469 0.101785 0.001063
2002-09-25 -0.498993 -0.328754 0.301644
2002-09-26 0.564092 0.466081 -0.599783

1000 rows × 3 columns


In [22]:
tsdf.apply(lambda x:x.idxmax())


Out[22]:
A   2001-07-13
B   2002-05-25
C   2001-11-26
dtype: datetime64[ns]

apply()方法当然支持接收其他参数了,比如下面的例子:


In [23]:
def subtract_and_divide(x, sub, divide=1):
    return (x - sub)/divide

In [24]:
df.apply(subtract_and_divide, args=(5,),divide=3)


Out[24]:
A B C
2000-01-01 -1.714087 -1.686787 -1.568106
2000-01-02 -1.465661 -0.951121 -1.828522
2000-01-03 -1.997844 -2.030687 -1.833101
2000-01-04 -1.334175 -1.313068 -1.644887
2000-01-05 -1.560009 -1.851679 -1.780064
2000-01-06 -1.755992 -1.907066 -1.007793
2000-01-07 -1.774335 -2.245656 -2.193020
2000-01-08 -1.949898 -1.452840 -2.080566

另一个有用的特性是对DataFrame对象传递Series方法,然后针对DF对象的每一列或每一行执行 Series内置的方法!


In [26]:
df


Out[26]:
A B C
2000-01-01 -0.142261 -0.060360 0.295683
2000-01-02 0.603017 2.146638 -0.485565
2000-01-03 -0.993533 -1.092061 -0.499304
2000-01-04 0.997475 1.060795 0.065338
2000-01-05 0.319973 -0.555038 -0.340192
2000-01-06 -0.267975 -0.721199 1.976621
2000-01-07 -0.323005 -1.736969 -1.579061
2000-01-08 -0.849693 0.641479 -1.241698

In [27]:
df.apply(pd.Series.interpolate)


Out[27]:
A B C
2000-01-01 -0.142261 -0.060360 0.295683
2000-01-02 0.603017 2.146638 -0.485565
2000-01-03 -0.993533 -1.092061 -0.499304
2000-01-04 0.997475 1.060795 0.065338
2000-01-05 0.319973 -0.555038 -0.340192
2000-01-06 -0.267975 -0.721199 1.976621
2000-01-07 -0.323005 -1.736969 -1.579061
2000-01-08 -0.849693 0.641479 -1.241698

应用逐元素操作的Python方法

既然不是所有的方法都能被向量化(接收NumPy数组,返回另一个数组或者值),但是DataFrame内置的applymap()和Series的map()方法能够接收任意的接收一个值且返回一个值的Python方法。


In [29]:
df4 = pd.DataFrame(np.random.randn(4, 3),index=['a','b','c','d'],columns=['one', 'two', 'three'])
df4


Out[29]:
one two three
a -1.180842 0.379143 -0.867448
b -0.222145 -0.212116 0.454593
c -0.731593 0.830485 0.585720
d -1.627282 -0.230078 0.489214

In [30]:
f = lambda x:len(str(x))

In [31]:
df4['one'].map(f)


Out[31]:
a    14
b    15
c    15
d    13
Name: one, dtype: int64

In [32]:
df4.applymap(f)


Out[32]:
one two three
a 14 14 15
b 15 15 14
c 15 14 14
d 13 15 14

Series.map()还有一个功能是模仿merge(), join()


In [38]:
s = pd.Series(['six', 'seven', 'six', 'seven', 'six'], index=['a', 'b', 'c', 'd', 'e'])

In [39]:
t = pd.Series({'six':6., 'seven':7.})

In [40]:
s


Out[40]:
a      six
b    seven
c      six
d    seven
e      six
dtype: object

In [41]:
t


Out[41]:
seven    7.0
six      6.0
dtype: float64

In [42]:
s.map(t)


Out[42]:
a    6.0
b    7.0
c    6.0
d    7.0
e    6.0
dtype: float64

In [ ]:

重新索引和改变label

reindex()是pandas中基本的数据对其方法。其他所有依赖label对齐的方法基本都要靠reindex()实现。reindex(重新索引)意味着是沿着某条轴转换数据以匹配新设定的label。具体来说,reindex()做了三件事情:

  • 对数据进行排序以匹配新的labels
  • 如果新label对应的位置没有数据,插入缺失值NA
  • 可以指定调用fill填充数据。

下面是一个简单的例子:


In [43]:
s = pd.Series(np.random.randn(5), index=['a','b','c','d','e'])

In [44]:
s


Out[44]:
a    0.735912
b   -0.102690
c    2.403671
d   -0.472632
e   -0.735369
dtype: float64

In [45]:
s.reindex(['e', 'b', 'f', 'd'])


Out[45]:
e   -0.735369
b   -0.102690
f         NaN
d   -0.472632
dtype: float64

对于DataFrame来说,你可以同时改变列名和索引值。


In [48]:
df


Out[48]:
A B C
2000-01-01 -0.142261 -0.060360 0.295683
2000-01-02 0.603017 2.146638 -0.485565
2000-01-03 -0.993533 -1.092061 -0.499304
2000-01-04 0.997475 1.060795 0.065338
2000-01-05 0.319973 -0.555038 -0.340192
2000-01-06 -0.267975 -0.721199 1.976621
2000-01-07 -0.323005 -1.736969 -1.579061
2000-01-08 -0.849693 0.641479 -1.241698

In [49]:
df.reindex(index=['c', 'f', 'b'], columns=['three', 'two', 'one'])


Out[49]:
three two one
c NaN NaN NaN
f NaN NaN NaN
b NaN NaN NaN

如果只想改变列或者索引的label,DataFrame也提供了reindex_axis()方法,接收label和axis。


In [50]:
rs = s.reindex(df.index)

In [51]:
rs


Out[51]:
2000-01-01   NaN
2000-01-02   NaN
2000-01-03   NaN
2000-01-04   NaN
2000-01-05   NaN
2000-01-06   NaN
2000-01-07   NaN
2000-01-08   NaN
Freq: D, dtype: float64

In [52]:
rs.index is df.index


Out[52]:
True

上面一行代码顺便说明了Series的索引和DataFrame的索引是同一类的实例。

重新索引来和另一个对象对齐 reindex_like()

你可能想传递一个对象,使得原来对象的label和传入的对象一样,使用reindex_like()即可。


In [3]:
df2 = pd.DataFrame(np.random.randn(3, 2),index=['a','b','c'],columns=['one', 'two'])

In [4]:
df2


Out[4]:
one two
a -0.207263 0.618381
b 0.271959 -0.013542
c 0.486730 1.308178

In [56]:
df


Out[56]:
A B C
2000-01-01 -0.142261 -0.060360 0.295683
2000-01-02 0.603017 2.146638 -0.485565
2000-01-03 -0.993533 -1.092061 -0.499304
2000-01-04 0.997475 1.060795 0.065338
2000-01-05 0.319973 -0.555038 -0.340192
2000-01-06 -0.267975 -0.721199 1.976621
2000-01-07 -0.323005 -1.736969 -1.579061
2000-01-08 -0.849693 0.641479 -1.241698

In [57]:
df.reindex_like(df2)


Out[57]:
one two
a NaN NaN
b NaN NaN
c NaN NaN

使用align() 是两个对象相互对齐

align()方法是让两个对象同事对齐的最快方法。它含有join参数,

  • join='outer': 取得两个对象的索引并集,这也是join的默认值。
  • join='left': 使用调用对象的索引值
  • join='right':使用被调用对象的索引值
  • join='inner': 使用两个对象的索引交集

align()方法返回一个元组,元素元素是重新索引的Series对象。


In [5]:
s = pd.Series(np.random.randn(5), index=['a', 'b', 'c', 'd', 'e'])

In [9]:
s1 = s[:4]
s2 = s[1:]

In [10]:
s1


Out[10]:
a   -1.131265
b    0.267754
c    0.679747
d    0.185136
dtype: float64

In [11]:
s2


Out[11]:
b    0.267754
c    0.679747
d    0.185136
e   -0.440251
dtype: float64

In [12]:
s1.align(s2)


Out[12]:
(a   -1.131265
 b    0.267754
 c    0.679747
 d    0.185136
 e         NaN
 dtype: float64, a         NaN
 b    0.267754
 c    0.679747
 d    0.185136
 e   -0.440251
 dtype: float64)

In [14]:
s1.align(s2, join='inner') #交集是 'b', 'c', 'd'


Out[14]:
(b    0.267754
 c    0.679747
 d    0.185136
 dtype: float64, b    0.267754
 c    0.679747
 d    0.185136
 dtype: float64)

对于DataFrame来说,join方法默认会应用到索引和列名。


In [16]:
df


Out[16]:
A B C
2000-01-01 -0.064020 1.089580 -1.007871
2000-01-02 -1.067990 0.075548 -1.326231
2000-01-03 0.813001 0.010123 0.729032
2000-01-04 0.283158 0.252955 -0.196908
2000-01-05 -1.481362 -0.773020 -0.177803
2000-01-06 1.760388 -1.276605 0.583953
2000-01-07 1.197909 0.013248 0.027281
2000-01-08 1.000680 -0.523045 0.821203

In [23]:
df2 = df.iloc[:5,:2]

In [24]:
df2


Out[24]:
A B
2000-01-01 -0.064020 1.089580
2000-01-02 -1.067990 0.075548
2000-01-03 0.813001 0.010123
2000-01-04 0.283158 0.252955
2000-01-05 -1.481362 -0.773020

In [25]:
df.align(df2, join='inner')


Out[25]:
(                   A         B
 2000-01-01 -0.064020  1.089580
 2000-01-02 -1.067990  0.075548
 2000-01-03  0.813001  0.010123
 2000-01-04  0.283158  0.252955
 2000-01-05 -1.481362 -0.773020,                    A         B
 2000-01-01 -0.064020  1.089580
 2000-01-02 -1.067990  0.075548
 2000-01-03  0.813001  0.010123
 2000-01-04  0.283158  0.252955
 2000-01-05 -1.481362 -0.773020)

In [26]:
df.align(df2)


Out[26]:
(                   A         B         C
 2000-01-01 -0.064020  1.089580 -1.007871
 2000-01-02 -1.067990  0.075548 -1.326231
 2000-01-03  0.813001  0.010123  0.729032
 2000-01-04  0.283158  0.252955 -0.196908
 2000-01-05 -1.481362 -0.773020 -0.177803
 2000-01-06  1.760388 -1.276605  0.583953
 2000-01-07  1.197909  0.013248  0.027281
 2000-01-08  1.000680 -0.523045  0.821203,                    A         B   C
 2000-01-01 -0.064020  1.089580 NaN
 2000-01-02 -1.067990  0.075548 NaN
 2000-01-03  0.813001  0.010123 NaN
 2000-01-04  0.283158  0.252955 NaN
 2000-01-05 -1.481362 -0.773020 NaN
 2000-01-06       NaN       NaN NaN
 2000-01-07       NaN       NaN NaN
 2000-01-08       NaN       NaN NaN)

align()也含有一个axis参数,指定仅对于某一坐标轴进行对齐。


In [27]:
df.align(df2, join='inner', axis=0)


Out[27]:
(                   A         B         C
 2000-01-01 -0.064020  1.089580 -1.007871
 2000-01-02 -1.067990  0.075548 -1.326231
 2000-01-03  0.813001  0.010123  0.729032
 2000-01-04  0.283158  0.252955 -0.196908
 2000-01-05 -1.481362 -0.773020 -0.177803,                    A         B
 2000-01-01 -0.064020  1.089580
 2000-01-02 -1.067990  0.075548
 2000-01-03  0.813001  0.010123
 2000-01-04  0.283158  0.252955
 2000-01-05 -1.481362 -0.773020)

DataFrame.align()同样能接收Series对象,此时axis指的是DataFrame对象的索引或列。


In [28]:
df.align(df2.ix[0], axis=1)


Out[28]:
(                   A         B         C
 2000-01-01 -0.064020  1.089580 -1.007871
 2000-01-02 -1.067990  0.075548 -1.326231
 2000-01-03  0.813001  0.010123  0.729032
 2000-01-04  0.283158  0.252955 -0.196908
 2000-01-05 -1.481362 -0.773020 -0.177803
 2000-01-06  1.760388 -1.276605  0.583953
 2000-01-07  1.197909  0.013248  0.027281
 2000-01-08  1.000680 -0.523045  0.821203, A   -0.06402
 B    1.08958
 C        NaN
 Name: 2000-01-01 00:00:00, dtype: float64)

重索引时顺便填充数值

reindex()方法还有一个method参数,用于填充数值,method取值如下:

  • pad/ffill: 使用后面的值填充数值
  • bfill/backfill: 使用前面的值填充数值
  • nearest: 使用最近的索引值进行填充

以Series为例,看一下:


In [30]:
rng = pd.date_range('1/3/2000', periods=8)

In [31]:
ts = pd.Series(np.random.randn(8), index=rng)

In [32]:
ts2 = ts[[0, 3, 6]]

In [33]:
ts


Out[33]:
2000-01-03   -0.765910
2000-01-04    0.077131
2000-01-05   -0.714099
2000-01-06   -0.109570
2000-01-07   -0.942098
2000-01-08   -0.242916
2000-01-09   -0.733449
2000-01-10    0.671837
Freq: D, dtype: float64

In [34]:
ts2


Out[34]:
2000-01-03   -0.765910
2000-01-06   -0.109570
2000-01-09   -0.733449
dtype: float64

In [35]:
ts2.reindex(ts.index)


Out[35]:
2000-01-03   -0.765910
2000-01-04         NaN
2000-01-05         NaN
2000-01-06   -0.109570
2000-01-07         NaN
2000-01-08         NaN
2000-01-09   -0.733449
2000-01-10         NaN
Freq: D, dtype: float64

In [36]:
ts2.reindex(ts.index, method='ffill') #索引小那一行的数值填充NaN


Out[36]:
2000-01-03   -0.765910
2000-01-04   -0.765910
2000-01-05   -0.765910
2000-01-06   -0.109570
2000-01-07   -0.109570
2000-01-08   -0.109570
2000-01-09   -0.733449
2000-01-10   -0.733449
Freq: D, dtype: float64

In [38]:
ts2.reindex(ts.index, method='bfill') #索引大的非NaN的数值填充NaN


Out[38]:
2000-01-03   -0.765910
2000-01-04   -0.109570
2000-01-05   -0.109570
2000-01-06   -0.109570
2000-01-07   -0.733449
2000-01-08   -0.733449
2000-01-09   -0.733449
2000-01-10         NaN
Freq: D, dtype: float64

In [39]:
ts2.reindex(ts.index, method='nearest')


Out[39]:
2000-01-03   -0.765910
2000-01-04   -0.765910
2000-01-05   -0.109570
2000-01-06   -0.109570
2000-01-07   -0.109570
2000-01-08   -0.733449
2000-01-09   -0.733449
2000-01-10   -0.733449
Freq: D, dtype: float64

method参数要求索引必须是有序的:递增或递减。

除了method='nearest',其他method取值也能用fillna()方法实现:


In [40]:
ts2.reindex(ts.index).fillna(method='ffill')


Out[40]:
2000-01-03   -0.765910
2000-01-04   -0.765910
2000-01-05   -0.765910
2000-01-06   -0.109570
2000-01-07   -0.109570
2000-01-08   -0.109570
2000-01-09   -0.733449
2000-01-10   -0.733449
Freq: D, dtype: float64

二者的区别是:如果索引不是有序的,reindex()会报错,而fillna()和interpolate()不会检查索引是否有序。

重索引时 有条件地填充NaN

limit和tolerance参数会对填充操作进行条件限制,通常限制填充的次数。


In [41]:
ts2.reindex(ts.index, method='ffill', limit=1)


Out[41]:
2000-01-03   -0.765910
2000-01-04   -0.765910
2000-01-05         NaN
2000-01-06   -0.109570
2000-01-07   -0.109570
2000-01-08         NaN
2000-01-09   -0.733449
2000-01-10   -0.733449
Freq: D, dtype: float64

In [42]:
ts2


Out[42]:
2000-01-03   -0.765910
2000-01-06   -0.109570
2000-01-09   -0.733449
dtype: float64

In [43]:
ts


Out[43]:
2000-01-03   -0.765910
2000-01-04    0.077131
2000-01-05   -0.714099
2000-01-06   -0.109570
2000-01-07   -0.942098
2000-01-08   -0.242916
2000-01-09   -0.733449
2000-01-10    0.671837
Freq: D, dtype: float64

In [44]:
ts2.reindex(ts.index, method='ffill', tolerance='1 day')


Out[44]:
2000-01-03   -0.765910
2000-01-04   -0.765910
2000-01-05         NaN
2000-01-06   -0.109570
2000-01-07   -0.109570
2000-01-08         NaN
2000-01-09   -0.733449
2000-01-10   -0.733449
Freq: D, dtype: float64

移除某些索引值

和reindex()方法很相似的是drop(),用于移除索引的某些取值。


In [52]:
df


Out[52]:
A B C
2000-01-01 -0.064020 1.089580 -1.007871
2000-01-02 -1.067990 0.075548 -1.326231
2000-01-03 0.813001 0.010123 0.729032
2000-01-04 0.283158 0.252955 -0.196908
2000-01-05 -1.481362 -0.773020 -0.177803
2000-01-06 1.760388 -1.276605 0.583953
2000-01-07 1.197909 0.013248 0.027281
2000-01-08 1.000680 -0.523045 0.821203

In [53]:
df.drop(['A'], axis=1)


Out[53]:
B C
2000-01-01 1.089580 -1.007871
2000-01-02 0.075548 -1.326231
2000-01-03 0.010123 0.729032
2000-01-04 0.252955 -0.196908
2000-01-05 -0.773020 -0.177803
2000-01-06 -1.276605 0.583953
2000-01-07 0.013248 0.027281
2000-01-08 -0.523045 0.821203

重命名索引值

rename() 方法可以对索引值重新命名,命名方式可以是字典或Series,也可以是任意的方法。


In [56]:
s


Out[56]:
a   -1.131265
b    0.267754
c    0.679747
d    0.185136
e   -0.440251
dtype: float64

In [57]:
s.rename(str.upper)


Out[57]:
A   -1.131265
B    0.267754
C    0.679747
D    0.185136
E   -0.440251
dtype: float64

唯一的要求是传入的函数调用索引值时必须有一个返回值,如果你传入的是字典或Series,要求是索引值必须是其键值。这点很好理解。


In [59]:
df = pd.DataFrame({'one' : pd.Series(np.random.randn(3), index=['a', 'b', 'c']),
                   'two' : pd.Series(np.random.randn(4), index=['a', 'b', 'c', 'd']),
                    'three' : pd.Series(np.random.randn(3), index=['b', 'c', 'd'])})
df


Out[59]:
one three two
a -0.074436 NaN -1.720569
b 1.154073 -0.335651 0.238351
c 0.147157 0.848397 0.827290
d NaN 0.699900 -1.079261

In [60]:
df.rename(columns={'one' : 'foo', 'two' : 'bar'},
          index={'a' : 'apple', 'b' : 'banana', 'd' : 'durian'})


Out[60]:
foo three bar
apple -0.074436 NaN -1.720569
banana 1.154073 -0.335651 0.238351
c 0.147157 0.848397 0.827290
durian NaN 0.699900 -1.079261

默认情况下修改的仅仅是副本,如果想对原对象索引值修改,inplace=True.

在0.18.0版本中,rename方法也能修改Series.name


In [61]:
s.rename('sclar-name')


Out[61]:
a   -1.131265
b    0.267754
c    0.679747
d    0.185136
e   -0.440251
Name: sclar-name, dtype: float64

In [ ]:

迭代操作 Iteration

pandas中迭代操作依赖于具体的对象。迭代Series对象时类似迭代数组,产生的是值,迭代DataFrame或Panel对象时类似迭代字典的键值。

一句话,(for i in object)产生:

  • Series: 值
  • DataFrame: 列名
  • Panel: item名

看一下例子吧:


In [62]:
df = pd.DataFrame({'col1' : np.random.randn(3), 'col2' : np.random.randn(3)},
                  index=['a', 'b', 'c'])
df


Out[62]:
col1 col2
a 0.172851 -0.382805
b -0.066942 0.672660
c -2.091001 0.510819

In [64]:
for col in df: #产生的是列名
    print col


col1
col2

pandas对象也有类似字典的iteritems()方法来迭代(key, value)。

为了每一行迭代DataFrame对象,有两种方法:

  • iterrows(): 按照行来迭代(index, Series)。会把每一行转为Series对象。
  • itertuples(): 按照行来迭代namedtuples. 这种方法比iterrows()快,大多数情况下推荐使用此方法。

警告

迭代pandas对象通常会比较慢。所以尽量避免迭代操作,可以用以下方法替换迭代:

  • 数据结构的内置方法,索引或numpy方法等
  • apply()
  • 使用cython写内循环

警告

当迭代进行时永远不要有修改操作

iteritems()

类似字典的接口,iteritems()对键值对进行迭代操作:

  • Series: (index, scalar value)
  • DataFrame: (column, Series)
  • Panel: (item, DataFrame)

看一下例子:


In [65]:
for item, frame in df.iteritems():
    print item, frame


col1 a    0.172851
b   -0.066942
c   -2.091001
Name: col1, dtype: float64
col2 a   -0.382805
b    0.672660
c    0.510819
Name: col2, dtype: float64

iterrows()

iterrows()方法用于迭代DataFrame的每一行,返回的是索引和Series的迭代器,但要注意Series的dtype可能和原来每一行的dtype不同。


In [68]:
for row_index, row in df.iterrows():
    print  row_index, row


a col1    0.172851
col2   -0.382805
Name: a, dtype: float64
b col1   -0.066942
col2    0.672660
Name: b, dtype: float64
c col1   -2.091001
col2    0.510819
Name: c, dtype: float64

itertuples()

itertuples()方法迭代DataFrame每一行,返回的是namedtuple。因为返回的不是Series,所以会保留DataFrame中值的dtype。


In [70]:
for row in df.itertuples():
    print row


Pandas(Index='a', col1=0.17285076817271622, col2=-0.38280463605747844)
Pandas(Index='b', col1=-0.066941511967637243, col2=0.67266041180134961)
Pandas(Index='c', col1=-2.0910005480409719, col2=0.51081932119946261)

.dt 访问器

Series对象如果索引是datetime/period,可以用自带的.dt访问器返回日期、小时、分钟。


In [71]:
s = pd.Series(pd.date_range('20160101 09:10:12', periods=4))

In [72]:
s


Out[72]:
0   2016-01-01 09:10:12
1   2016-01-02 09:10:12
2   2016-01-03 09:10:12
3   2016-01-04 09:10:12
dtype: datetime64[ns]

In [73]:
s.dt.hour


Out[73]:
0    9
1    9
2    9
3    9
dtype: int64

In [74]:
s.dt.second


Out[74]:
0    12
1    12
2    12
3    12
dtype: int64

In [75]:
s.dt.day


Out[75]:
0    1
1    2
2    3
3    4
dtype: int64

改变时间的格式也很方便,Series.dt.strftime()


In [76]:
s = pd.Series(pd.date_range('20130101', periods=4))

In [77]:
s


Out[77]:
0   2013-01-01
1   2013-01-02
2   2013-01-03
3   2013-01-04
dtype: datetime64[ns]

In [78]:
s.dt.strftime('%Y/%m/%d')


Out[78]:
0    2013/01/01
1    2013/01/02
2    2013/01/03
3    2013/01/04
dtype: object

In [ ]:

字符串处理方法

Series带有一系列的字符串处理, 默认不对NaN处理。


In [79]:
s = pd.Series(['A', 'B', 'C', 'Aaba', 'Baca', np.nan, 'CABA', 'dog', 'cat'])

In [80]:
s


Out[80]:
0       A
1       B
2       C
3    Aaba
4    Baca
5     NaN
6    CABA
7     dog
8     cat
dtype: object

In [81]:
s.str.lower()


Out[81]:
0       a
1       b
2       c
3    aaba
4    baca
5     NaN
6    caba
7     dog
8     cat
dtype: object

In [ ]:

排序

排序方法可以分为两大类: 按照实际的值排序和按照label排序。

按照索引排序 sort_index()

Series.sort_index(), DataFrame.sort_index(), 参数是ascending, axis。


In [88]:
unsorted_df = df.reindex(index=['a', 'd', 'c', 'b'],
                         columns=['three', 'two', 'one'])
unsorted_df


Out[88]:
three two one
a NaN NaN NaN
d NaN NaN NaN
c NaN NaN NaN
b NaN NaN NaN

In [89]:
unsorted_df.sort_index()


Out[89]:
three two one
a NaN NaN NaN
b NaN NaN NaN
c NaN NaN NaN
d NaN NaN NaN

In [90]:
unsorted_df.sort_index(ascending=False)


Out[90]:
three two one
d NaN NaN NaN
c NaN NaN NaN
b NaN NaN NaN
a NaN NaN NaN

In [91]:
unsorted_df.sort_index(axis=1)


Out[91]:
one three two
a NaN NaN NaN
d NaN NaN NaN
c NaN NaN NaN
b NaN NaN NaN

In [92]:
unsorted_df['three'].sort_index() # Series


Out[92]:
a   NaN
b   NaN
c   NaN
d   NaN
Name: three, dtype: float64

按照值排序

Series.sort_values(), DataFrame.sort_values()用于按照值进行排序,参数有by


In [93]:
df1 = pd.DataFrame({'one':[2,1,1,1],'two':[1,3,2,4],'three':[5,4,3,2]})
df1


Out[93]:
one three two
0 2 5 1
1 1 4 3
2 1 3 2
3 1 2 4

In [94]:
df1.sort_values(by='two')


Out[94]:
one three two
0 2 5 1
2 1 3 2
1 1 4 3
3 1 2 4

In [95]:
df1.sort_values(by=['one', 'two'])


Out[95]:
one three two
2 1 3 2
1 1 4 3
3 1 2 4
0 2 5 1

通过na_position参数处理NA值。


In [96]:
s[2] = np.nan

In [97]:
s.sort_values()


Out[97]:
0       A
3    Aaba
1       B
4    Baca
6    CABA
8     cat
7     dog
2     NaN
5     NaN
dtype: object

In [99]:
s.sort_values(na_position='first') #将NA放在前面


Out[99]:
2     NaN
5     NaN
0       A
3    Aaba
1       B
4    Baca
6    CABA
8     cat
7     dog
dtype: object

searchsorted()

Series.searchsorted()类似numpy.ndarray.searchsorted()。 找到元素在排好序后的位置(下标)。


In [3]:
ser = pd.Series([1,2,3])

In [10]:
ser.searchsorted([0, 3]) #元素0下标是0, 元素3下标是2。注意不同元素之间是独立的,所以元素3的位置是2而不是插入0后的3.


Out[10]:
array([0, 3], dtype=int64)

In [11]:
ser.searchsorted([0, 4])


Out[11]:
array([0, 3], dtype=int64)

In [6]:
ser.searchsorted([1, 3], side='right')


Out[6]:
array([1, 3], dtype=int64)

In [7]:
ser.searchsorted([1, 3], side='left')


Out[7]:
array([0, 2], dtype=int64)

In [8]:
ser = pd.Series([3, 1, 2])

In [9]:
ser.searchsorted([0, 3], sorter=np.argsort(ser))


Out[9]:
array([0, 2], dtype=int64)

最小/最大值

Series有nsmallest() nlargest()方法能够返回最小或最大的n个值。如果Series对象很大,这两种方法会比先排序后使用head()方法快很多。


In [12]:
s = pd.Series(np.random.permutation(10))
s


Out[12]:
0    6
1    3
2    8
3    7
4    5
5    2
6    4
7    0
8    1
9    9
dtype: int32

In [13]:
s.sort_values()


Out[13]:
7    0
8    1
5    2
1    3
6    4
4    5
0    6
3    7
2    8
9    9
dtype: int32

In [14]:
s.nsmallest(3)


Out[14]:
7    0
8    1
5    2
dtype: int32

In [15]:
s.nlargest(3)


Out[15]:
9    9
2    8
3    7
dtype: int32

从v0.17.0开始,DataFrame也有了以上两个方法。


In [16]:
df = pd.DataFrame({'a': [-2, -1, 1, 10, 8, 11, -1],
                      'b': list('abdceff'),
                       'c': [1.0, 2.0, 4.0, 3.2, np.nan, 3.0, 4.0]})

In [25]:
df


Out[25]:
a b c
0 -2 a 1.0
1 -1 b 2.0
2 1 d 4.0
3 10 c 3.2
4 8 e NaN
5 11 f 3.0
6 -1 f 4.0

In [28]:
df.nlargest(5, 'a') #列 'a'最大的3个值


Out[28]:
a b c
5 11 f 3.0
3 10 c 3.2
4 8 e NaN
2 1 d 4.0
1 -1 b 2.0

In [27]:
df.nlargest(5, ['a', 'c'])


Out[27]:
a b c
5 11 f 3.0
3 10 c 3.2
4 8 e NaN
2 1 d 4.0
1 -1 b 2.0

In [22]:
df.nsmallest(3, 'a')


Out[22]:
a b c
0 -2 a 1.0
1 -1 b 2.0
6 -1 f 4.0

In [24]:
df.nsmallest(5, ['a', 'c'])


Out[24]:
a b c
0 -2 a 1.0
1 -1 b 2.0
6 -1 f 4.0
2 1 d 4.0
4 8 e NaN

多索引列 排序

如果一列是多索引,你必须指定全部每一级的索引。


In [30]:
df1 = pd.DataFrame({'one':[2,1,1,1],'two':[1,3,2,4],'three':[5,4,3,2]})

In [31]:
df1.columns = pd.MultiIndex.from_tuples([('a','one'),('a','two'),('b','three')])

In [32]:
df1


Out[32]:
a b
one two three
0 2 5 1
1 1 4 3
2 1 3 2
3 1 2 4

In [33]:
df1.sort_values(by=('a','two'))


Out[33]:
a b
one two three
3 1 2 4
2 1 3 2
1 1 4 3
0 2 5 1

In [ ]:

复制

copy()方法复制数据结构的值并返回一个新的对象。记住复制操作不到万不得已不使用。 比如,改变DataFrame对象值的几种方法:

  • inserting, deleting, modifying a column
  • 为索引、列 赋值
  • 对于同构数据,直接使用values属性修改值。

几乎所有的方法都不对原对象进行直接修改,而是返回修改后的一个新对象!如果原对象数据被修改,肯定是你显示指定的修改操作。

dtypes属性

pandas对象的主要数据类型包括: float, int, bool, datetime64[ns], datetime64[ns, tz], timedelta[ns], category, object. 除此之外还有更具体的说明存储比特数的数据类型比如int64, int32。

DataFrame的dtypes属性返回一个Series对象,Series值是DF中每一列的数据类型。


In [39]:
df = pd.DataFrame(dict(A = np.random.rand(3),
                            B = 1,
                           C = 'foo',
                            D = pd.Timestamp('20010102'),
                           E = pd.Series([1.0]*3).astype('float32'),
                                        F = False,
                                       G = pd.Series([1]*3,dtype='int8')))

In [40]:
df


Out[40]:
A B C D E F G
0 0.223911 1 foo 2001-01-02 1.0 False 1
1 0.306255 1 foo 2001-01-02 1.0 False 1
2 0.435360 1 foo 2001-01-02 1.0 False 1

In [41]:
df.dtypes


Out[41]:
A           float64
B             int64
C            object
D    datetime64[ns]
E           float32
F              bool
G              int8
dtype: object

Series同样有dtypes属性


In [42]:
df['A'].dtype


Out[42]:
dtype('float64')

如果pandas对象的一列中有多种数据类型,dtype返回的是能兼容所有数据类型的类型,object范围最大的。


In [43]:
pd.Series([1,2,3,4,5,6.])


Out[43]:
0    1.0
1    2.0
2    3.0
3    4.0
4    5.0
5    6.0
dtype: float64

In [44]:
pd.Series([1,2,3,6.,'foo'])


Out[44]:
0      1
1      2
2      3
3      6
4    foo
dtype: object

get_dtype_counts()方法返回DataFrame中每一种数据类型的列数。


In [50]:
df.get_dtype_counts()


Out[50]:
bool              1
datetime64[ns]    1
float32           1
float64           1
int64             1
int8              1
object            1
dtype: int64

数值数据类型可以在ndarray,Series和DataFrame中传播。


In [51]:
df1 = pd.DataFrame(np.random.randn(8, 1), columns=['A'], dtype='float32')

In [52]:
df1


Out[52]:
A
0 0.325100
1 -1.052396
2 1.866763
3 -0.647942
4 -1.518647
5 0.982795
6 -0.068309
7 2.034926

In [53]:
df1.dtypes


Out[53]:
A    float32
dtype: object

In [56]:
df2 = pd.DataFrame(dict( A = pd.Series(np.random.randn(8), dtype='float16'),
                         B = pd.Series(np.random.randn(8)),
                         C = pd.Series(np.array(np.random.randn(8), dtype='uint8')) )) #这里是float16, uint8
df2


Out[56]:
A B C
0 -0.427979 0.280275 0
1 -0.701172 -0.456572 0
2 -0.558105 -0.248928 255
3 -0.361572 0.746420 0
4 -1.667969 0.722280 255
5 -1.436523 -0.864915 0
6 0.147949 1.620295 0
7 0.075989 -0.527997 0

In [57]:
df2.dtypes


Out[57]:
A    float16
B    float64
C      uint8
dtype: object

数据类型的默认值

整型的默认值蕾西int64,浮点型的默认类型是float64,和你用的是32位还是64位的系统无关。


In [59]:
pd.DataFrame([1, 2], columns=['a']).dtypes


Out[59]:
a    int64
dtype: object

In [60]:
pd.DataFrame({'a': [1, 2]}).dtypes


Out[60]:
a    int64
dtype: object

In [61]:
pd.DataFrame({'a': 1}, index=list(range(2))).dtypes


Out[61]:
a    int64
dtype: object

Numpy中数值的具体类型则要依赖于平台。


In [64]:
frame = pd.DataFrame(np.array([1, 2])) #如果是在32位系统,数据类型int32

upcasting

不同类型结合时会upcast,即得到更通用的类型,看例子吧:


In [75]:
df1.dtypes


Out[75]:
A    float32
dtype: object

In [76]:
df2.dtypes


Out[76]:
A    float16
B    float64
C      uint8
dtype: object

In [77]:
df1.reindex_like(df2).fillna(value=0.0).dtypes


Out[77]:
A    float32
B    float64
C    float64
dtype: object

In [78]:
df3 = df1.reindex_like(df2).fillna(value=0.0) + df2

In [79]:
df3.dtypes


Out[79]:
A    float32
B    float64
C    float64
dtype: object

astype()方法

使用astype()显示的进行转型。默认会返回原对象的副本,即使数据类型不变。当然可以传递copy=False参数直接对原对象转型。


In [80]:
df3


Out[80]:
A B C
0 -0.102879 0.280275 0.0
1 -1.753568 -0.456572 0.0
2 1.308658 -0.248928 255.0
3 -1.009514 0.746420 0.0
4 -3.186615 0.722280 255.0
5 -0.453728 -0.864915 0.0
6 0.079640 1.620295 0.0
7 2.110915 -0.527997 0.0

In [81]:
df3.dtypes


Out[81]:
A    float32
B    float64
C    float64
dtype: object

In [82]:
df3.astype('float32').dtypes


Out[82]:
A    float32
B    float32
C    float32
dtype: object

对object类型进行转型

convert_objects()方法能对object类型进行转型。如果想转为数字,参数是convert_numeric=True。


In [84]:
df3['D'] = '1.'

In [85]:
df3['E'] = '1'

In [86]:
df3


Out[86]:
A B C D E
0 -0.102879 0.280275 0.0 1. 1
1 -1.753568 -0.456572 0.0 1. 1
2 1.308658 -0.248928 255.0 1. 1
3 -1.009514 0.746420 0.0 1. 1
4 -3.186615 0.722280 255.0 1. 1
5 -0.453728 -0.864915 0.0 1. 1
6 0.079640 1.620295 0.0 1. 1
7 2.110915 -0.527997 0.0 1. 1

In [88]:
df3.dtypes #现在'D' 'E'两列都是object类型


Out[88]:
A    float32
B    float64
C    float64
D     object
E     object
dtype: object

In [89]:
df3.convert_objects(convert_numeric=True).dtypes


c:\python27\lib\site-packages\ipykernel\__main__.py:1: FutureWarning: convert_objects is deprecated.  Use the data-type specific converters pd.to_datetime, pd.to_timedelta and pd.to_numeric.
  if __name__ == '__main__':
Out[89]:
A    float32
B    float64
C    float64
D    float64
E      int64
dtype: object

In [90]:
df3['D'] = df3['D'].astype('float16')

In [91]:
df3['E'] = df3['E'].astype('int32')

In [92]:
df3.dtypes


Out[92]:
A    float32
B    float64
C    float64
D    float16
E      int32
dtype: object

基于dtype 选择列

select_dtypes()方法实现了基于列dtype的构造子集方法。


In [93]:
df = pd.DataFrame({'string': list('abc'),
                    'int64': list(range(1, 4)),
                    'uint8': np.arange(3, 6).astype('u1'),
                    'float64': np.arange(4.0, 7.0),
                    'bool1': [True, False, True],
                    'bool2': [False, True, False],
                    'dates': pd.date_range('now', periods=3).values,
                    'category': pd.Series(list("ABC")).astype('category')})

In [94]:
df


Out[94]:
bool1 bool2 category dates float64 int64 string uint8
0 True False A 2016-04-20 10:26:18.089 4.0 1 a 3
1 False True B 2016-04-21 10:26:18.089 5.0 2 b 4
2 True False C 2016-04-22 10:26:18.089 6.0 3 c 5

In [95]:
df['tdeltas'] = df.dates.diff()

In [96]:
df['uint64'] = np.arange(3, 6).astype('u8')

In [97]:
df['other_dates'] = pd.date_range('20130101', periods=3).values

In [98]:
df['tz_aware_dates'] = pd.date_range('20130101', periods=3, tz='US/Eastern')

In [99]:
df


Out[99]:
bool1 bool2 category dates float64 int64 string uint8 tdeltas uint64 other_dates tz_aware_dates
0 True False A 2016-04-20 10:26:18.089 4.0 1 a 3 NaT 3 2013-01-01 2013-01-01 00:00:00-05:00
1 False True B 2016-04-21 10:26:18.089 5.0 2 b 4 1 days 4 2013-01-02 2013-01-02 00:00:00-05:00
2 True False C 2016-04-22 10:26:18.089 6.0 3 c 5 1 days 5 2013-01-03 2013-01-03 00:00:00-05:00

In [100]:
df.dtypes


Out[100]:
bool1                                   bool
bool2                                   bool
category                            category
dates                         datetime64[ns]
float64                              float64
int64                                  int64
string                                object
uint8                                  uint8
tdeltas                      timedelta64[ns]
uint64                                uint64
other_dates                   datetime64[ns]
tz_aware_dates    datetime64[ns, US/Eastern]
dtype: object

select_dtypes()有两个参数:include, exclude。含义是要选择的列的dtype和不选择列的dtype。


In [104]:
df.select_dtypes(include=[bool])


Out[104]:
bool1 bool2
0 True False
1 False True
2 True False

In [105]:
df.select_dtypes(include=['bool'])


Out[105]:
bool1 bool2
0 True False
1 False True
2 True False

In [107]:
df.dtypes


Out[107]:
bool1                                   bool
bool2                                   bool
category                            category
dates                         datetime64[ns]
float64                              float64
int64                                  int64
string                                object
uint8                                  uint8
tdeltas                      timedelta64[ns]
uint64                                uint64
other_dates                   datetime64[ns]
tz_aware_dates    datetime64[ns, US/Eastern]
dtype: object

In [108]:
df.select_dtypes(include=['number', 'bool'], exclude=['unsignedinteger'])


Out[108]:
bool1 bool2 float64 int64 tdeltas
0 True False 4.0 1 NaT
1 False True 5.0 2 1 days
2 True False 6.0 3 1 days

如果要选择字符串类型的列,必须使用object类型。


In [109]:
df.select_dtypes(include=['object'])


Out[109]:
string
0 a
1 b
2 c

如果想要知道某种数据类型的所有子类型,比如numpy.number类型,你可以定义如下的方法:


In [110]:
def subdtypes(dtype):
        subs = dtype.__subclasses__()
        if not subs:
            return dtype
        return [dtype, [subdtypes(dt) for dt in subs]]

In [111]:
subdtypes(np.generic)


Out[111]:
[numpy.generic,
 [[numpy.number,
   [[numpy.integer,
     [[numpy.signedinteger,
       [numpy.int8,
        numpy.int16,
        numpy.int32,
        numpy.int32,
        numpy.int64,
        numpy.timedelta64]],
      [numpy.unsignedinteger,
       [numpy.uint8,
        numpy.uint16,
        numpy.uint32,
        numpy.uint32,
        numpy.uint64]]]],
    [numpy.inexact,
     [[numpy.floating,
       [numpy.float16, numpy.float32, numpy.float64, numpy.float64]],
      [numpy.complexfloating,
       [numpy.complex64, numpy.complex128, numpy.complex128]]]]]],
  [numpy.flexible,
   [[numpy.character, [numpy.string_, numpy.unicode_]],
    [numpy.void, [numpy.record]]]],
  numpy.bool_,
  numpy.datetime64,
  numpy.object_]]

In [ ]: