基本功能

原文:http://pandas.pydata.org/pandas-docs/stable/basics.html

译者:飞龙 UsyiyiCN

校对:(虚位以待)

我们在这里讨论了很多pandas数据结构通用的基本功能。下面是如何创建一些对象,它们在上一节中的示例中使用:

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

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

In [3]: df = pd.DataFrame(np.random.randn(8, 3), index=index,
   ...:                   columns=['A', 'B', 'C'])
   ...: 

In [4]: 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 [5]: long_series = pd.Series(np.random.randn(1000))

In [6]: long_series.head()
Out[6]: 
0   -0.305384
1   -0.479195
2    0.095031
3   -0.270099
4   -0.707140
dtype: float64

In [7]: long_series.tail(3)
Out[7]: 
997    0.588446
998    0.026465
999   -1.728222
dtype: float64

属性和原始 ndarray(s)

pandas对象有一些属性,使您可以访问元数据

  • shape:提供对象的各维度的尺寸,与ndarray一致
  • 轴标签
    • Series:index(唯一的轴)
    • DataFrame:index(行)和columns(列)
    • Panel:items,major_axis和minor_axis

注意,这些属性可以安全地赋值!

In [8]: df[:2]
Out[8]: 
                   A         B         C
2000-01-01  0.187483 -1.933946  0.377312
2000-01-02  0.734122  2.141616 -0.011225

In [9]: df.columns = [x.lower() for x in df.columns]

In [10]: df
Out[10]: 
                   a         b         c
2000-01-01  0.187483 -1.933946  0.377312
2000-01-02  0.734122  2.141616 -0.011225
2000-01-03  0.048869 -1.360687 -0.479010
2000-01-04 -0.859661 -0.231595 -0.527750
2000-01-05 -1.296337  0.150680  0.123836
2000-01-06  0.571764  1.555563 -0.823761
2000-01-07  0.535420 -1.032853  1.469725
2000-01-08  1.304124  1.449735  0.203109

为了获取数据结构中的实际数据,只需访问values属性:

In [11]: s.values
Out[11]: array([ 0.1122,  0.8717, -0.8161, -0.7849,  1.0307])

In [12]: df.values
Out[12]: 
array([[ 0.1875, -1.9339,  0.3773],
       [ 0.7341,  2.1416, -0.0112],
       [ 0.0489, -1.3607, -0.479 ],
       [-0.8597, -0.2316, -0.5278],
       [-1.2963,  0.1507,  0.1238],
       [ 0.5718,  1.5556, -0.8238],
       [ 0.5354, -1.0329,  1.4697],
       [ 1.3041,  1.4497,  0.2031]])

In [13]: wp.values
Out[13]: 
array([[[-1.032 ,  0.9698, -0.9627,  1.3821],
        [-0.9388,  0.6691, -0.4336, -0.2736],
        [ 0.6804, -0.3084, -0.2761, -1.8212],
        [-1.9936, -1.9274, -2.0279,  1.625 ],
        [ 0.5511,  3.0593,  0.4553, -0.0307]],

       [[ 0.9357,  1.0612, -2.1079,  0.1999],
        [ 0.3236, -0.6416, -0.5875,  0.0539],
        [ 0.1949, -0.382 ,  0.3186,  2.0891],
        [-0.7283, -0.0903, -0.7482,  1.3189],
        [-2.0298,  0.7927,  0.461 , -0.5427]]])

如果DataFrame或Panel包含单一类型的数据,则ndarray实际上可以原地修改,并且更改将反映在数据结构中。对于异构数据(例如,某些DataFrame的列不具有全部相同的dtype),情况就不是这样。与轴标签不同,值属性本身不能赋值。

注意

处理异构数据时,会选取所得 ndarray 的 dtype 来适配所有涉及的数据。例如,如果涉及字符串,结果的dtype将是object。如果只有浮点数和整数,所得数组的dtype将是float 。

加速操作

pandas支持使用numexpr库(从0.11.0开始)和bottleneck库,来加速某些类型的二元数值和布尔运算。

这些库在处理大型数据集时非常有用,并提供可观的加速。numexpr使用智能分块,缓存和多核心。bottleneck是一组专用的cython例程,处理具有nans的数组时,它们特别快。

以下是一个示例(使用100列 x 100,000行的DataFrames):

操作 0.11.0(ms) 以前的版本(ms) 与以前的比率
df1 > df2 13.32 125.35 0.1063
df1 * df2 21.71 36.63 0.5928
df1 + df2 22.04 36.50 0.6039

强烈建议您安装这两个库。更多安装信息请参阅推荐的依赖项一节。

灵活的二元运算

使用pandas数据结构的二元运算,有两个要点:

  • 高维(例如DataFrame)和低维(例如系列)对象之间的广播行为。
  • 计算中的缺失数据

我们将演示如何独立处理这些问题,虽然他们可以同时处理。

匹配 / 广播行为

DataFrame具有add(),sub(),mul(),div()方法,和radd(),rsub(),...关系函数,用于执行二元操作。对于广播行为,系列输入是主要兴趣。使用这些函数,您可以通过axis关键字,匹配index或column:

In [14]: 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 [15]: df
Out[15]: 
        one     three       two
a -0.626544       NaN -0.351587
b -0.138894 -0.177289  1.136249
c  0.011617  0.462215 -0.448789
d       NaN  1.124472 -1.101558

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

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

In [18]: df.sub(row, axis='columns')
Out[18]: 
        one     three       two
a -0.487650       NaN -1.487837
b  0.000000  0.000000  0.000000
c  0.150512  0.639504 -1.585038
d       NaN  1.301762 -2.237808

In [19]: df.sub(row, axis=1)
Out[19]: 
        one     three       two
a -0.487650       NaN -1.487837
b  0.000000  0.000000  0.000000
c  0.150512  0.639504 -1.585038
d       NaN  1.301762 -2.237808

In [20]: df.sub(column, axis='index')
Out[20]: 
        one     three  two
a -0.274957       NaN  0.0
b -1.275144 -1.313539  0.0
c  0.460406  0.911003  0.0
d       NaN  2.226031  0.0

In [21]: df.sub(column, axis=0)
Out[21]: 
        one     three  two
a -0.274957       NaN  0.0
b -1.275144 -1.313539  0.0
c  0.460406  0.911003  0.0
d       NaN  2.226031  0.0

此外,您可以将多索引DataFrame的某个层级与 Series对齐。

In [22]: dfmi = df.copy()

In [23]: dfmi.index = pd.MultiIndex.from_tuples([(1,'a'),(1,'b'),(1,'c'),(2,'a')],
   ....:                                        names=['first','second'])
   ....: 

In [24]: dfmi.sub(column, axis=0, level='second')
Out[24]: 
                   one     three       two
first second                              
1     a      -0.274957       NaN  0.000000
      b      -1.275144 -1.313539  0.000000
      c       0.460406  0.911003  0.000000
2     a            NaN  1.476060 -0.749971

对于 Panel,描述匹配行为有点困难,因此改为使用算术方法(也许令人困惑?)您可以选择指定广播轴。例如,假设我们希望从数据中减去特定轴上的均值。这可以通过在一个轴上取平均值并在同一轴上广播来实现:

In [25]: major_mean = wp.mean(axis='major')

In [26]: major_mean
Out[26]: 
      Item1     Item2
A -0.546569 -0.260774
B  0.492478  0.147993
C -0.649010 -0.532794
D  0.176307  0.623812

In [27]: wp.sub(major_mean, axis='major')
Out[27]: 
<class 'pandas.core.panel.Panel'>
Dimensions: 2 (items) x 5 (major_axis) x 4 (minor_axis)
Items axis: Item1 to Item2
Major_axis axis: 2000-01-01 00:00:00 to 2000-01-05 00:00:00
Minor_axis axis: A to D

对于axis="items"和axis="minor"也是如此。

注意

我可以确保,使DataFrame方法中的axis参数符合Panel的广播行为。虽然它需要一个过渡期,以便用户可以更改他们的代码...

Series 和 Index 也支持内建的divmod()。该函数同时执行取底除法和模运算,同时返回一个二元组,类型与左边相同。例如:

In [28]: s = pd.Series(np.arange(10))

In [29]: s
Out[29]: 
0    0
1    1
2    2
3    3
4    4
5    5
6    6
7    7
8    8
9    9
dtype: int64

In [30]: div, rem = divmod(s, 3)

In [31]: div
Out[31]: 
0    0
1    0
2    0
3    1
4    1
5    1
6    2
7    2
8    2
9    3
dtype: int64

In [32]: rem
Out[32]: 
0    0
1    1
2    2
3    0
4    1
5    2
6    0
7    1
8    2
9    0
dtype: int64

In [33]: idx = pd.Index(np.arange(10))

In [34]: idx
Out[34]: Int64Index([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], dtype='int64')

In [35]: div, rem = divmod(idx, 3)

In [36]: div
Out[36]: Int64Index([0, 0, 0, 1, 1, 1, 2, 2, 2, 3], dtype='int64')

In [37]: rem
Out[37]: Int64Index([0, 1, 2, 0, 1, 2, 0, 1, 2, 0], dtype='int64')

divmod()也可以逐元素操作:

In [38]: div, rem = divmod(s, [2, 2, 3, 3, 4, 4, 5, 5, 6, 6])

In [39]: div
Out[39]: 
0    0
1    0
2    0
3    1
4    1
5    1
6    1
7    1
8    1
9    1
dtype: int64

In [40]: rem
Out[40]: 
0    0
1    1
2    2
3    0
4    0
5    1
6    1
7    2
8    2
9    3
dtype: int64

缺失数据 / 填充值的操作

在Series和DataFrame中(Panel不支持),算术函数拥有输入fill_value的选项,当某个位置上最多缺少一个值时,它是一个用于替换的值,例如,将两个DataFrame对象相加时,您可能希望将NaN视为0,除非两个DataFrames都缺少该值,在这种情况下,结果将是NaN(您可以稍后使用fillna)。

In [41]: df
Out[41]: 
        one     three       two
a -0.626544       NaN -0.351587
b -0.138894 -0.177289  1.136249
c  0.011617  0.462215 -0.448789
d       NaN  1.124472 -1.101558

In [42]: df2
Out[42]: 
        one     three       two
a -0.626544  1.000000 -0.351587
b -0.138894 -0.177289  1.136249
c  0.011617  0.462215 -0.448789
d       NaN  1.124472 -1.101558

In [43]: df + df2
Out[43]: 
        one     three       two
a -1.253088       NaN -0.703174
b -0.277789 -0.354579  2.272499
c  0.023235  0.924429 -0.897577
d       NaN  2.248945 -2.203116

In [44]: df.add(df2, fill_value=0)
Out[44]: 
        one     three       two
a -1.253088  1.000000 -0.703174
b -0.277789 -0.354579  2.272499
c  0.023235  0.924429 -0.897577
d       NaN  2.248945 -2.203116

灵活的比较

从v0.8开始,pandas将二元比较方法eq,ne,lt,gt,le和ge引入Series和DataFrame,其行为类似于上述二元算术运算:

In [45]: df.gt(df2)
Out[45]: 
     one  three    two
a  False  False  False
b  False  False  False
c  False  False  False
d  False  False  False

In [46]: df2.ne(df)
Out[46]: 
     one  three    two
a  False   True  False
b  False  False  False
c  False  False  False
d   True  False  False

这些操作产生dtype为bool的pandas对象。这些布尔对象可用于索引操作,请参阅这里

布尔归约

您可以应用归约:empty,any(),all()和bool()

In [47]: (df > 0).all()
Out[47]: 
one      False
three    False
two      False
dtype: bool

In [48]: (df > 0).any()
Out[48]: 
one      True
three    True
two      True
dtype: bool

您可以最终归约为布尔值。

In [49]: (df > 0).any().any()
Out[49]: True

您可以通过empty属性测试一个pandas对象是否为空。

In [50]: df.empty
Out[50]: False

In [51]: pd.DataFrame(columns=list('ABC')).empty
Out[51]: True

为了在布尔上下文中求解单元素的pandas对象,请使用方法bool():

In [52]: pd.Series([True]).bool()
Out[52]: True

In [53]: pd.Series([False]).bool()
Out[53]: False

In [54]: pd.DataFrame([[True]]).bool()
Out[54]: True

In [55]: pd.DataFrame([[False]]).bool()
Out[55]: False

警告

您可能会试图执行以下操作:

>>> if df:
     ...

或者

>>> df and df2

上面两个操作都会导致下面的错误

ValueError: The truth value of an array is ambiguous. Use a.empty, a.any() or a.all().

详细讨论请参阅陷阱。

比较对象是否相等

通常,您可能会发现有多种方法来计算相同的结果。作为一个简单的例子,考虑df+df和df*2。为了测试这两个计算产生相同的结果,给定上面所示的工具,你可以想象使用(df + df == df * 2).all()。但实际上,这个表达式是False:

In [56]: df+df == df*2
Out[56]: 
     one  three   two
a   True  False  True
b   True   True  True
c   True   True  True
d  False   True  True

In [57]: (df+df == df*2).all()
Out[57]: 
one      False
three    False
two       True
dtype: bool

请注意,布尔值的 DataFrame df + df == df * 2包含一些False值!这是因为NaN不等于自身:

In [58]: np.nan == np.nan
Out[58]: False

因此,从v0.13.1开始,NDFrames(如Series,DataFrames和Panels)拥有用于测试等性的equals()方法,其中相应位置的NaN被视为相等。

In [59]: (df+df).equals(df*2)
Out[59]: True

请注意,Series或DataFrame索引需要按相同的顺序,才能等于True:

In [60]: df1 = pd.DataFrame({'col':['foo', 0, np.nan]})

In [61]: df2 = pd.DataFrame({'col':[np.nan, 0, 'foo']}, index=[2,1,0])

In [62]: df1.equals(df2)
Out[62]: False

In [63]: df1.equals(df2.sort_index())
Out[63]: True

比较类似于数组的对象

将pandas数据结构与标量值进行比较时,进行逐个元素的比较会很方便:

In [64]: pd.Series(['foo', 'bar', 'baz']) == 'foo'
Out[64]: 
0     True
1    False
2    False
dtype: bool

In [65]: pd.Index(['foo', 'bar', 'baz']) == 'foo'
Out[65]: array([ True, False, False], dtype=bool)

Pandas还处理相同长度的不同类数组的对象之间的,逐元素的比较:

In [66]: pd.Series(['foo', 'bar', 'baz']) == pd.Index(['foo', 'bar', 'qux'])
Out[66]: 
0     True
1     True
2    False
dtype: bool

In [67]: pd.Series(['foo', 'bar', 'baz']) == np.array(['foo', 'bar', 'qux'])
Out[67]: 
0     True
1     True
2    False
dtype: bool

尝试比较不同长度的Index或Series对象。将产生一个ValueError:

In [55]: pd.Series(['foo', 'bar', 'baz']) == pd.Series(['foo', 'bar'])
ValueError: Series lengths must match to compare

In [56]: pd.Series(['foo', 'bar', 'baz']) == pd.Series(['foo'])
ValueError: Series lengths must match to compare

请注意,这不同于比较可被广播的numpy行为:

In [68]: np.array([1, 2, 3]) == np.array([2])
Out[68]: array([False,  True, False], dtype=bool)

或者如果广播不能完成,它可以返回False:

In [69]: np.array([1, 2, 3]) == np.array([1, 2])
Out[69]: False

组合重叠的数据集

当拥有两个DataFrame,其中一个的数据质量优于另一个时,那么这两个DataFrame的组合可能会有些问题。一个示例如下:两个表示特定经济指标的 Series,其中一个具有“更高的质量”。然而,较低质量的 Series 可能有更久的历史,或覆盖更完整的数据。因此,我们希望组合两个DataFrame对象,其中一个DataFrame中的缺失值按照条件,填充为来自其他DataFrame的类似标签的值。实现此操作的函数是combine_first(),就像这样:

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

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

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

In [73]: df2
Out[73]: 
     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 [74]: df1.combine_first(df2)
Out[74]: 
     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

DataFrame 的通用组合

上面的combine_first()方法调用更通用的DataFrame方法combine()。此方法接受另一个DataFrame和组合器函数,对齐输入的DataFrame,然后向 Series 偶对(即名称相同的列)传递组合器函数。

因此,例如,像上面一样再次实现combine_first():

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

In [76]: df1.combine(df2, combiner)
Out[76]: 
     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()会生成相同大小的对象。通常,这些方法接受axis(轴)参数,就像ndarray.{sum, std, ...},但轴可以通过名称或整数指定:

  • Series:无需轴参数
  • DataFrame:"index"(axis=0,默认值),"columns"(axis=1)
  • Panel:"items"(axis=0),"major"(axis=1,默认),"minor"(axis=2)

例如:

In [77]: df
Out[77]: 
        one     three       two
a -0.626544       NaN -0.351587
b -0.138894 -0.177289  1.136249
c  0.011617  0.462215 -0.448789
d       NaN  1.124472 -1.101558

In [78]: df.mean(0)
Out[78]: 
one     -0.251274
three    0.469799
two     -0.191421
dtype: float64

In [79]: df.mean(1)
Out[79]: 
a   -0.489066
b    0.273355
c    0.008348
d    0.011457
dtype: float64

所有这些方法都有skipna选项,指示是否排除缺失的数据(默认情况下为True):

In [80]: df.sum(0, skipna=False)
Out[80]: 
one           NaN
three         NaN
two     -0.765684
dtype: float64

In [81]: df.sum(axis=1, skipna=True)
Out[81]: 
a   -0.978131
b    0.820066
c    0.025044
d    0.022914
dtype: float64

结合广播/算术行为,可以非常简明地描述各种统计过程,如标准化(使数据均值为0,标准差为1):

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

In [83]: ts_stand.std()
Out[83]: 
one      1.0
three    1.0
two      1.0
dtype: float64

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

In [85]: xs_stand.std(1)
Out[85]: 
a    1.0
b    1.0
c    1.0
d    1.0
dtype: float64

注意,像cumsum()和cumprod()的方法保留NA值的位置:

In [86]: df.cumsum()
Out[86]: 
        one     three       two
a -0.626544       NaN -0.351587
b -0.765438 -0.177289  0.784662
c -0.753821  0.284925  0.335874
d       NaN  1.409398 -0.765684

这里是一个常用功能的快速参考汇总表。每个还接受可选的level参数,只有对象拥有层次索引时,该参数才适用。

功能 描述
count 非空观测值数量
sum 值的总和
mean 值的平均值
mad 平均绝对偏差
median 值的算术中值
min 最小值
max 最大值
mode 模
abs 绝对值
prod 值的乘积
std 贝塞尔修正样本标准差
var 无偏方差
sem 平均值的标准误差
skew 样品偏斜度(三阶矩)
kurt 样品峰度(四阶矩)
quantile 样本分位数(百分位上的值)
cumsum 累积总和
cumprod 累积乘积
cummax 累积最大值
cummin 累积最小值

请注意,有时一些NumPy方法(如mean,std和sum)将默认排除 Series 输入上的NA:

In [87]: np.mean(df['one'])
Out[87]: -0.2512736517583951

In [88]: np.mean(df['one'].values)
Out[88]: nan

Series也有nunique()方法,它将返回唯一的非空值的数量:

In [89]: series = pd.Series(np.random.randn(500))

In [90]: series[20:500] = np.nan

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

In [92]: series.nunique()
Out[92]: 11

数据汇总:describe(描述)

有一个方便的describe()函数,用于计算关于 DataFrame 的一个或多个 Series 的各种汇总统计量(当然不包括NAs):

In [93]: series = pd.Series(np.random.randn(1000))

In [94]: series[::2] = np.nan

In [95]: series.describe()
Out[95]: 
count    500.000000
mean      -0.039663
std        1.069371
min       -3.463789
25%       -0.731101
50%       -0.058918
75%        0.672758
max        3.120271
dtype: float64

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

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

In [98]: frame.describe()
Out[98]: 
                a           b           c           d           e
count  500.000000  500.000000  500.000000  500.000000  500.000000
mean     0.000954   -0.044014    0.075936   -0.003679    0.020751
std      1.005133    0.974882    0.967432    1.004732    0.963812
min     -3.010899   -2.782760   -3.401252   -2.944925   -3.794127
25%     -0.682900   -0.681161   -0.528190   -0.663503   -0.615717
50%     -0.001651   -0.006279    0.040098   -0.003378    0.006282
75%      0.656439    0.632852    0.717919    0.687214    0.653423
max      3.007143    2.627688    2.702490    2.850852    3.072117

您可以选择包含在输出中的特定百分位数:

In [99]: series.describe(percentiles=[.05, .25, .75, .95])
Out[99]: 
count    500.000000
mean      -0.039663
std        1.069371
min       -3.463789
5%        -1.741334
25%       -0.731101
50%       -0.058918
75%        0.672758
95%        1.854383
max        3.120271
dtype: float64

默认情况下,始终包括中位数。

对于非数值 Series 对象,describe()将给出唯一值数量,和最常出现的值的简单摘要:

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

In [101]: s.describe()
Out[101]: 
count     9
unique    4
top       a
freq      5
dtype: object

请注意,在混合类型DataFrame对象上,describe()将摘要限制为仅包含数字列,如果没有,则只包含类别列:

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

In [103]: frame.describe()
Out[103]: 
              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

可以通过提供类型列表,作为include / exclude参数,来控制此行为。也可以使用特殊值all:

In [104]: frame.describe(include=['object'])
Out[104]: 
         a
count    4
unique   2
top     No
freq     2

In [105]: frame.describe(include=['number'])
Out[105]: 
              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 [106]: frame.describe(include='all')
Out[106]: 
          a         b
count     4  4.000000
unique    2       NaN
top      No       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

该功能依赖于select_dtypes。有关接受的输入的详细信息,请参阅此处。

最大/最小值的索引

Series和DataFrame上的idxmin()和idxmax()函数计算最大值和最小值的索引标签:

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

In [108]: s1
Out[108]: 
0   -0.872725
1    1.522411
2    0.080594
3   -1.676067
4    0.435804
dtype: float64

In [109]: s1.idxmin(), s1.idxmax()
Out[109]: (3, 1)

In [110]: df1 = pd.DataFrame(np.random.randn(5,3), columns=['A','B','C'])

In [111]: df1
Out[111]: 
          A         B         C
0  0.445734 -1.649461  0.169660
1  1.246181  0.131682 -2.001988
2 -1.273023  0.870502  0.214583
3  0.088452 -0.173364  1.207466
4  0.546121  0.409515 -0.310515

In [112]: df1.idxmin(axis=0)
Out[112]: 
A    2
B    0
C    1
dtype: int64

In [113]: df1.idxmax(axis=1)
Out[113]: 
0    A
1    A
2    B
3    C
4    A
dtype: object

当有多个行(或列)匹配最小值或最大值时,idxmin()和idxmax()返回第一个匹配的索引:

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

In [115]: df3
Out[115]: 
     A
e  2.0
d  1.0
c  1.0
b  3.0
a  NaN

In [116]: df3['A'].idxmin()
Out[116]: 'd'

注意

在NumPy中,idxmin和idxmax称为argmin和argmax。

值的计数(直方图)/模式

Series 的value_counts()方法和同名的顶级函数计算一维数组值的直方图。它也可以用作常规数组上的函数:

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

In [118]: data
Out[118]: 
array([5, 3, 2, 2, 1, 4, 0, 4, 0, 2, 0, 6, 4, 1, 6, 3, 3, 0, 2, 1, 0, 5, 5,
       3, 6, 1, 5, 6, 2, 0, 0, 6, 3, 3, 5, 0, 4, 3, 3, 3, 0, 6, 1, 3, 5, 5,
       0, 4, 0, 6])

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

In [120]: s.value_counts()
Out[120]: 
0    11
3    10
6     7
5     7
4     5
2     5
1     5
dtype: int64

In [121]: pd.value_counts(data)
Out[121]: 
0    11
3    10
6     7
5     7
4     5
2     5
1     5
dtype: int64

与之类似,您可以在Series或DataFrame中。获取最频繁出现的值(模式):

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

In [123]: s5.mode()
Out[123]: 
0    3
1    7
dtype: int64

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

In [125]: df5.mode()
Out[125]: 
   A  B
0  1 -5

离散化和量化

可以使用cut()(基于值的分桶)和qcut()(基于样本分位数的分桶)函数将连续值变离散:

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

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

In [128]: factor
Out[128]: 
[(-0.645, 0.336], (-2.61, -1.626], (-1.626, -0.645], (-1.626, -0.645], (-1.626, -0.645], ..., (0.336, 1.316], (0.336, 1.316], (0.336, 1.316], (0.336, 1.316], (-2.61, -1.626]]
Length: 20
Categories (4, object): [(-2.61, -1.626] < (-1.626, -0.645] < (-0.645, 0.336] < (0.336, 1.316]]

In [129]: factor = pd.cut(arr, [-5, -1, 0, 1, 5])

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

qcut()计算样本分位数。例如,我们可以将一些正态分布的数据分割成等大小的四部分,如下所示:

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

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

In [133]: factor
Out[133]: 
[(-0.139, 1.00736], (1.00736, 1.976], (1.00736, 1.976], [-1.0705, -0.439], [-1.0705, -0.439], ..., (1.00736, 1.976], [-1.0705, -0.439], (-0.439, -0.139], (-0.439, -0.139], (-0.439, -0.139]]
Length: 30
Categories (4, object): [[-1.0705, -0.439] < (-0.439, -0.139] < (-0.139, 1.00736] < (1.00736, 1.976]]

In [134]: pd.value_counts(factor)
Out[134]: 
(1.00736, 1.976]     8
[-1.0705, -0.439]    8
(-0.139, 1.00736]    7
(-0.439, -0.139]     7
dtype: int64

我们还可以传递无限值来定义bin:

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

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

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

函数应用

要将自己的或另一个库的函数应用于pandas对象,您应该注意以下三个方法。使用的适当方法取决于您的函数是否希望对整个DataFrame还是Series,按行或列或者元素进行操作。

  1. 按表格的函数应用:pipe()
  2. 按行或列的函数应用:apply()
  3. 按元素的函数应用:applymap()

按表格的函数应用

版本0.16.2中的新功能。

DataFrames和Series当然可以传递到函数中。但是,如果函数需要链式调用,请考虑使用pipe()方法。比较以下内容

# f, g, and h are functions taking and returning ``DataFrames``
>>> f(g(h(df), arg1=1), arg2=2, arg3=3)

与等效

>>> (df.pipe(h)
       .pipe(g, arg1=1)
       .pipe(f, arg2=2, arg3=3)
    )

pandas 鼓励第二种风格,这被称为方法链。pipe可以方便地在方法链中调用你自己的或另一个库的函数,以及pandas的方法。

在上述示例中,函数f,g和h每个都期待DataFrame为第一个参数。如果你希望应用的函数把它的数据接受为第二个参数怎么办?在这种情况下,将元组(callable, data_keyword)提供给pipe。.pipe会将DataFrame赋给元组中指定的参数。

例如,我们可以使用statsmodels拟合回归。他们的API首先接受公式,并且将DataFrame作为第二个参数,data。我们将关键字偶对(sm.poisson, 'data')传递给pipe

In [138]: import statsmodels.formula.api as sm

In [139]: bb = pd.read_csv('data/baseball.csv', index_col='id')

In [140]: (bb.query('h > 0')
   .....:    .assign(ln_h = lambda df: np.log(df.h))
   .....:    .pipe((sm.poisson, 'data'), 'hr ~ ln_h + year + g + C(lg)')
   .....:    .fit()
   .....:    .summary()
   .....: )
   .....: 
Optimization terminated successfully.
         Current function value: 2.116284
         Iterations 24
Out[140]: 
<class 'statsmodels.iolib.summary.Summary'>
"""
                          Poisson Regression Results                          
==============================================================================
Dep. Variable:                     hr   No. Observations:                   68
Model:                        Poisson   Df Residuals:                       63
Method:                           MLE   Df Model:                            4
Date:                Sat, 24 Dec 2016   Pseudo R-squ.:                  0.6878
Time:                        18:31:33   Log-Likelihood:                -143.91
converged:                       True   LL-Null:                       -460.91
                                        LLR p-value:                6.774e-136
===============================================================================
                  coef    std err          z      P>|z|      [95.0% Conf. Int.]
-------------------------------------------------------------------------------
Intercept   -1267.3636    457.867     -2.768      0.006     -2164.767  -369.960
C(lg)[T.NL]    -0.2057      0.101     -2.044      0.041        -0.403    -0.008
ln_h            0.9280      0.191      4.866      0.000         0.554     1.302
year            0.6301      0.228      2.762      0.006         0.183     1.077
g               0.0099      0.004      2.754      0.006         0.003     0.017
===============================================================================
"""

pipe方法受unix管道,以及最近的dplyr和magrittr的启发,它们将流行的(%>%)(管道读取)运算符引入了R。 这里的pipe相当干净,在python 中感觉很舒服。我们建议您查看源代码(IPython 中执行pd.DataFrame.pipe??)。

逐行或逐列的函数应用

可以使用apply()方法,沿着DataFrame或Panel的轴应用任意函数,与描述性统计方法一样,它采用可选的axis参数:

In [141]: df.apply(np.mean)
Out[141]: 
one     -0.251274
three    0.469799
two     -0.191421
dtype: float64

In [142]: df.apply(np.mean, axis=1)
Out[142]: 
a   -0.489066
b    0.273355
c    0.008348
d    0.011457
dtype: float64

In [143]: df.apply(lambda x: x.max() - x.min())
Out[143]: 
one      0.638161
three    1.301762
two      2.237808
dtype: float64

In [144]: df.apply(np.cumsum)
Out[144]: 
        one     three       two
a -0.626544       NaN -0.351587
b -0.765438 -0.177289  0.784662
c -0.753821  0.284925  0.335874
d       NaN  1.409398 -0.765684

In [145]: df.apply(np.exp)
Out[145]: 
        one     three       two
a  0.534436       NaN  0.703570
b  0.870320  0.837537  3.115063
c  1.011685  1.587586  0.638401
d       NaN  3.078592  0.332353

根据传递给apply()的函数的返回类型,结果将是较低维或相同维的。

apply()结合一些机智的用法,可以用来回答关于数据集的许多问题。例如,假设我们要提取每一列的最大值出现处的日期:

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

In [147]: tsdf.apply(lambda x: x.idxmax())
Out[147]: 
A   2001-04-27
B   2002-06-02
C   2000-04-02
dtype: datetime64[ns]

您还可以向apply()方法传递其他参数和关键字参数。例如,考虑以下您要应用的函数:

def subtract_and_divide(x, sub, divide=1):
    return (x - sub) / divide

然后,您可以应用这个函数,如下所示:

df.apply(subtract_and_divide, args=(5,), divide=3)

另一个有用的功能是,传递Series方法对每一列或行执行一些Series操作:

In [148]: tsdf
Out[148]: 
                   A         B         C
2000-01-01  1.796883 -0.930690  3.542846
2000-01-02 -1.242888 -0.695279 -1.000884
2000-01-03 -0.720299  0.546303 -0.082042
2000-01-04       NaN       NaN       NaN
2000-01-05       NaN       NaN       NaN
2000-01-06       NaN       NaN       NaN
2000-01-07       NaN       NaN       NaN
2000-01-08 -0.527402  0.933507  0.129646
2000-01-09 -0.338903 -1.265452 -1.969004
2000-01-10  0.532566  0.341548  0.150493

In [149]: tsdf.apply(pd.Series.interpolate)
Out[149]: 
                   A         B         C
2000-01-01  1.796883 -0.930690  3.542846
2000-01-02 -1.242888 -0.695279 -1.000884
2000-01-03 -0.720299  0.546303 -0.082042
2000-01-04 -0.681720  0.623743 -0.039704
2000-01-05 -0.643140  0.701184  0.002633
2000-01-06 -0.604561  0.778625  0.044971
2000-01-07 -0.565982  0.856066  0.087309
2000-01-08 -0.527402  0.933507  0.129646
2000-01-09 -0.338903 -1.265452 -1.969004
2000-01-10  0.532566  0.341548  0.150493

最后,apply()接受参数raw,它默认为False,它在应用函数之前将每一行或列转换为一个Series。当设置为True时,传递的函数将接收一个ndarray对象,如果您不需要索引功能,这会有正面的性能影响。

另见

GroupBy章节演示了相关的灵活功能,用于按照某些标准进行分组,应用结果并将结果组合为Series,DataFrame等。

应用逐元素的 Python 函数

由于并非所有函数都可以向量化(接受NumPy数组并返回另一个数组或值),DataFrame上的applymap()方法和类似的 Series 上的map()方法,接受任何这样的 Python 函数,它接受单个参数并返回单个值。例如:

In [150]: df4
Out[150]: 
        one     three       two
a -0.626544       NaN -0.351587
b -0.138894 -0.177289  1.136249
c  0.011617  0.462215 -0.448789
d       NaN  1.124472 -1.101558

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

In [152]: df4['one'].map(f)
Out[152]: 
a    14
b    15
c    15
d     3
Name: one, dtype: int64

In [153]: df4.applymap(f)
Out[153]: 
   one  three  two
a   14      3   15
b   15     15   11
c   15     14   15
d    3     13   14

Series.map()有一个附加功能,它可以用于轻松地“链接”或“映射”由辅助 Series 定义的值。这与合并/连接功能密切相关:

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

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

In [156]: s
Out[156]: 
a      six
b    seven
c      six
d    seven
e      six
dtype: object

In [157]: s.map(t)
Out[157]: 
a    6.0
b    7.0
c    6.0
d    7.0
e    6.0
dtype: float64

应用于 Panel

应用于Panel会将Series传递给应用的函数。如果应用函数返回Series,应用程序的结果将是Panel。如果应用函数归约为标量,应用的结果将是DataFrame。

注意

0.13.1 之前, Panel 上的 apply 仅仅能够处理 ufuncs (例如 np.sum/np.max)。

In [158]: import pandas.util.testing as tm

In [159]: panel = tm.makePanel(5)

In [160]: panel
Out[160]: 
<class 'pandas.core.panel.Panel'>
Dimensions: 3 (items) x 5 (major_axis) x 4 (minor_axis)
Items axis: ItemA to ItemC
Major_axis axis: 2000-01-03 00:00:00 to 2000-01-07 00:00:00
Minor_axis axis: A to D

In [161]: panel['ItemA']
Out[161]: 
                   A         B         C         D
2000-01-03  0.330418  1.893177  0.801111  0.528154
2000-01-04  1.761200  0.170247  0.445614 -0.029371
2000-01-05  0.567133 -0.916844  1.453046 -0.631117
2000-01-06 -0.251020  0.835024  2.430373 -0.172441
2000-01-07  1.020099  1.259919  0.653093 -1.020485

转换性的应用

In [162]: result = panel.apply(lambda x: x*2, axis='items')

In [163]: result
Out[163]: 
<class 'pandas.core.panel.Panel'>
Dimensions: 3 (items) x 5 (major_axis) x 4 (minor_axis)
Items axis: ItemA to ItemC
Major_axis axis: 2000-01-03 00:00:00 to 2000-01-07 00:00:00
Minor_axis axis: A to D

In [164]: result['ItemA']
Out[164]: 
                   A         B         C         D
2000-01-03  0.660836  3.786354  1.602222  1.056308
2000-01-04  3.522400  0.340494  0.891228 -0.058742
2000-01-05  1.134266 -1.833689  2.906092 -1.262234
2000-01-06 -0.502039  1.670047  4.860747 -0.344882
2000-01-07  2.040199  2.519838  1.306185 -2.040969

归约操作

In [165]: panel.apply(lambda x: x.dtype, axis='items')
Out[165]: 
                  A        B        C        D
2000-01-03  float64  float64  float64  float64
2000-01-04  float64  float64  float64  float64
2000-01-05  float64  float64  float64  float64
2000-01-06  float64  float64  float64  float64
2000-01-07  float64  float64  float64  float64

类似的归约类型操作

In [166]: panel.apply(lambda x: x.sum(), axis='major_axis')
Out[166]: 
      ItemA     ItemB     ItemC
A  3.427831 -2.581431  0.840809
B  3.241522 -1.409935 -1.114512
C  5.783237  0.319672 -0.431906
D -1.325260 -2.914834  0.857043

最后的归约等同于

In [167]: panel.sum('major_axis')
Out[167]: 
      ItemA     ItemB     ItemC
A  3.427831 -2.581431  0.840809
B  3.241522 -1.409935 -1.114512
C  5.783237  0.319672 -0.431906
D -1.325260 -2.914834  0.857043

转换操作返回Panel,但沿着major_axis计算z-score。

In [168]: result = panel.apply(
   .....:            lambda x: (x-x.mean())/x.std(),
   .....:            axis='major_axis')
   .....: 

In [169]: result
Out[169]: 
<class 'pandas.core.panel.Panel'>
Dimensions: 3 (items) x 5 (major_axis) x 4 (minor_axis)
Items axis: ItemA to ItemC
Major_axis axis: 2000-01-03 00:00:00 to 2000-01-07 00:00:00
Minor_axis axis: A to D

In [170]: result['ItemA']
Out[170]: 
                   A         B         C         D
2000-01-03 -0.469761  1.156225 -0.441347  1.341731
2000-01-04  1.422763 -0.444015 -0.882647  0.398661
2000-01-05 -0.156654 -1.453694  0.367936 -0.619210
2000-01-06 -1.238841  0.173423  1.581149  0.156654
2000-01-07  0.442494  0.568061 -0.625091 -1.277837

apply 也可以在axis参数中接受多个轴。这会将截面的DataFrame传递给应用函数。

In [171]: f = lambda x: ((x.T-x.mean(1))/x.std(1)).T

In [172]: result = panel.apply(f, axis = ['items','major_axis'])

In [173]: result
Out[173]: 
<class 'pandas.core.panel.Panel'>
Dimensions: 4 (items) x 5 (major_axis) x 3 (minor_axis)
Items axis: A to D
Major_axis axis: 2000-01-03 00:00:00 to 2000-01-07 00:00:00
Minor_axis axis: ItemA to ItemC

In [174]: result.loc[:,:,'ItemA']
Out[174]: 
                   A         B         C         D
2000-01-03  0.864236  1.132969  0.557316  0.575106
2000-01-04  0.795745  0.652527  0.534808 -0.070674
2000-01-05 -0.310864  0.558627  1.086688 -1.051477
2000-01-06 -0.001065  0.832460  0.846006  0.043602
2000-01-07  1.128946  1.152469 -0.218186 -0.891680

这相当于下面:

In [175]: result = pd.Panel(dict([ (ax, f(panel.loc[:,:,ax]))
   .....:                         for ax in panel.minor_axis ]))
   .....: 

In [176]: result
Out[176]: 
<class 'pandas.core.panel.Panel'>
Dimensions: 4 (items) x 5 (major_axis) x 3 (minor_axis)
Items axis: A to D
Major_axis axis: 2000-01-03 00:00:00 to 2000-01-07 00:00:00
Minor_axis axis: ItemA to ItemC

In [177]: result.loc[:,:,'ItemA']
Out[177]: 
                   A         B         C         D
2000-01-03  0.864236  1.132969  0.557316  0.575106
2000-01-04  0.795745  0.652527  0.534808 -0.070674
2000-01-05 -0.310864  0.558627  1.086688 -1.051477
2000-01-06 -0.001065  0.832460  0.846006  0.043602
2000-01-07  1.128946  1.152469 -0.218186 -0.891680

重索引和改变标签

reindex()是pandas中的基本数据对齐方法。它用于实现几乎所有依赖于标签对齐功能的其他功能。reindex通过指定的索引来匹配值有以下几个功能:

  • 重新排序现有数据以匹配一组新标签
  • 在没有该标签的数据的标签位置插入缺少值(NA)标记
  • 如果指定,使用逻辑(与使用时间序列数据非常相关),缺少标签的填充

这里有一个简单的例子:

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

In [179]: s
Out[179]: 
a   -1.010924
b   -0.672504
c   -1.139222
d    0.354653
e    0.563622
dtype: float64

In [180]: s.reindex(['e', 'b', 'f', 'd'])
Out[180]: 
e    0.563622
b   -0.672504
f         NaN
d    0.354653
dtype: float64

这里,f标签不包含在系列中,因此在结果中显示为NaN。

使用DataFrame,您可以同时重新索引索引和列:

In [181]: df
Out[181]: 
        one     three       two
a -0.626544       NaN -0.351587
b -0.138894 -0.177289  1.136249
c  0.011617  0.462215 -0.448789
d       NaN  1.124472 -1.101558

In [182]: df.reindex(index=['c', 'f', 'b'], columns=['three', 'two', 'one'])
Out[182]: 
      three       two       one
c  0.462215 -0.448789  0.011617
f       NaN       NaN       NaN
b -0.177289  1.136249 -0.138894

为方便起见,您可以使用reindex_axis()方法,该方法使用标签和关键字axis参数。

请注意,包含实际轴标签的Index对象可以在对象之间共享。因此,如果我们有一个Series和一个DataFrame,可以做到以下几点:

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

In [184]: rs
Out[184]: 
a   -1.010924
b   -0.672504
c   -1.139222
d    0.354653
dtype: float64

In [185]: rs.index is df.index
Out[185]: True

这意味着重建索引系列的索引与DataFrame的索引是相同的Python对象。

也可以看看

MultiIndex / Advanced Indexing是一种更简洁的执行重建索引的方法。

注意

当编写性能敏感的代码时,有一个很好的理由花一些时间成为重建索引忍者:许多操作在预先对齐的数据上更快。在内部添加两个未对齐的DataFrames会触发重建索引步骤。对于探索性分析,您几乎不会注意到差异(因为reindex已被大量优化),但是当CPU周期在这里显示一些显式的reindex调用时, 。

Reindexing to align with another object

您可能希望获取一个对象,并将其轴重命名为与另一个对象相同的标签。虽然这种语法很简单,尽管很详细,但它是一个常见的操作,reindex_like()方法可以使这更简单:

In [186]: df2
Out[186]: 
        one       two
a -0.626544 -0.351587
b -0.138894  1.136249
c  0.011617 -0.448789

In [187]: df3
Out[187]: 
        one       two
a -0.375270 -0.463545
b  0.112379  1.024292
c  0.262891 -0.560746

In [188]: df.reindex_like(df2)
Out[188]: 
        one       two
a -0.626544 -0.351587
b -0.138894  1.136249
c  0.011617 -0.448789

Aligning objects with each other with align

align()方法是同时对齐两个对象的最快方法。它支持join参数(与joining and merging相关):

  • join='outer':获取索引的并集(默认)
  • join='left':使用调用对象的索引
  • join='right':使用传递的对象的索引
  • join='inner':与索引相交

它返回一个带有两个重建索引系列的元组:

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

In [190]: s1 = s[:4]

In [191]: s2 = s[1:]

In [192]: s1.align(s2)
Out[192]: 
(a   -0.365106
 b    1.092702
 c   -1.481449
 d    1.781190
 e         NaN
 dtype: float64, a         NaN
 b    1.092702
 c   -1.481449
 d    1.781190
 e   -0.031543
 dtype: float64)

In [193]: s1.align(s2, join='inner')
Out[193]: 
(b    1.092702
 c   -1.481449
 d    1.781190
 dtype: float64, b    1.092702
 c   -1.481449
 d    1.781190
 dtype: float64)

In [194]: s1.align(s2, join='left')
Out[194]: 
(a   -0.365106
 b    1.092702
 c   -1.481449
 d    1.781190
 dtype: float64, a         NaN
 b    1.092702
 c   -1.481449
 d    1.781190
 dtype: float64)

对于DataFrames,默认情况下,连接方法将应用于索引和列:

In [195]: df.align(df2, join='inner')
Out[195]: 
(        one       two
 a -0.626544 -0.351587
 b -0.138894  1.136249
 c  0.011617 -0.448789,         one       two
 a -0.626544 -0.351587
 b -0.138894  1.136249
 c  0.011617 -0.448789)

您也可以传递axis选项,仅在指定轴上对齐:

In [196]: df.align(df2, join='inner', axis=0)
Out[196]: 
(        one     three       two
 a -0.626544       NaN -0.351587
 b -0.138894 -0.177289  1.136249
 c  0.011617  0.462215 -0.448789,         one       two
 a -0.626544 -0.351587
 b -0.138894  1.136249
 c  0.011617 -0.448789)

如果将Series传递到DataFrame.align(),则可以选择使用axis参数在DataFrame的索引或列上对齐两个对象:

In [197]: df.align(df2.ix[0], axis=1)
Out[197]: 
(        one     three       two
 a -0.626544       NaN -0.351587
 b -0.138894 -0.177289  1.136249
 c  0.011617  0.462215 -0.448789
 d       NaN  1.124472 -1.101558, one     -0.626544
 three         NaN
 two     -0.351587
 Name: a, dtype: float64)

Filling while reindexing

reindex()采用可选参数method,它是从下表中选择的填充方法:

方法 行动
pad / ffill 向前填充值
bfill / backfill 向后填充值
最近 从最近的索引值填充

我们在一个简单的系列上说明这些填充方法:

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

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

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

In [201]: ts
Out[201]: 
2000-01-03    0.480993
2000-01-04    0.604244
2000-01-05   -0.487265
2000-01-06    1.990533
2000-01-07    0.327007
2000-01-08    1.053639
2000-01-09   -2.927808
2000-01-10    0.082065
Freq: D, dtype: float64

In [202]: ts2
Out[202]: 
2000-01-03    0.480993
2000-01-06    1.990533
2000-01-09   -2.927808
dtype: float64

In [203]: ts2.reindex(ts.index)
Out[203]: 
2000-01-03    0.480993
2000-01-04         NaN
2000-01-05         NaN
2000-01-06    1.990533
2000-01-07         NaN
2000-01-08         NaN
2000-01-09   -2.927808
2000-01-10         NaN
Freq: D, dtype: float64

In [204]: ts2.reindex(ts.index, method='ffill')
Out[204]: 
2000-01-03    0.480993
2000-01-04    0.480993
2000-01-05    0.480993
2000-01-06    1.990533
2000-01-07    1.990533
2000-01-08    1.990533
2000-01-09   -2.927808
2000-01-10   -2.927808
Freq: D, dtype: float64

In [205]: ts2.reindex(ts.index, method='bfill')
Out[205]: 
2000-01-03    0.480993
2000-01-04    1.990533
2000-01-05    1.990533
2000-01-06    1.990533
2000-01-07   -2.927808
2000-01-08   -2.927808
2000-01-09   -2.927808
2000-01-10         NaN
Freq: D, dtype: float64

In [206]: ts2.reindex(ts.index, method='nearest')
Out[206]: 
2000-01-03    0.480993
2000-01-04    0.480993
2000-01-05    1.990533
2000-01-06    1.990533
2000-01-07    1.990533
2000-01-08   -2.927808
2000-01-09   -2.927808
2000-01-10   -2.927808
Freq: D, dtype: float64

这些方法要求索引有序增加或减少。

请注意,使用fillna(除了method='nearest')或interpolate可以实现相同的结果:

In [207]: ts2.reindex(ts.index).fillna(method='ffill')
Out[207]: 
2000-01-03    0.480993
2000-01-04    0.480993
2000-01-05    0.480993
2000-01-06    1.990533
2000-01-07    1.990533
2000-01-08    1.990533
2000-01-09   -2.927808
2000-01-10   -2.927808
Freq: D, dtype: float64

如果索引不是单调递增或递减,reindex()将引发ValueError。fillna()和interpolate()不会对索引的顺序进行任何检查。

Limits on filling while reindexing

limit和tolerance参数在重建索引时提供对填充的额外控制。Limit指定连续匹配的最大计数:

In [208]: ts2.reindex(ts.index, method='ffill', limit=1)
Out[208]: 
2000-01-03    0.480993
2000-01-04    0.480993
2000-01-05         NaN
2000-01-06    1.990533
2000-01-07    1.990533
2000-01-08         NaN
2000-01-09   -2.927808
2000-01-10   -2.927808
Freq: D, dtype: float64

相反,公差指定索引和索引器值之间的最大距离:

In [209]: ts2.reindex(ts.index, method='ffill', tolerance='1 day')
Out[209]: 
2000-01-03    0.480993
2000-01-04    0.480993
2000-01-05         NaN
2000-01-06    1.990533
2000-01-07    1.990533
2000-01-08         NaN
2000-01-09   -2.927808
2000-01-10   -2.927808
Freq: D, dtype: float64

注意当在DatetimeIndex,TimedeltaIndex或PeriodIndex上使用时,tolerance将强制为Timedelta这允许您使用适当的字符串指定公差。

Dropping labels from an axis

与reindex密切相关的方法是drop()函数。它从轴删除一组标签:

In [210]: df
Out[210]: 
        one     three       two
a -0.626544       NaN -0.351587
b -0.138894 -0.177289  1.136249
c  0.011617  0.462215 -0.448789
d       NaN  1.124472 -1.101558

In [211]: df.drop(['a', 'd'], axis=0)
Out[211]: 
        one     three       two
b -0.138894 -0.177289  1.136249
c  0.011617  0.462215 -0.448789

In [212]: df.drop(['one'], axis=1)
Out[212]: 
      three       two
a       NaN -0.351587
b -0.177289  1.136249
c  0.462215 -0.448789
d  1.124472 -1.101558

注意下面的也可以,但是不太明显/干净:

In [213]: df.reindex(df.index.difference(['a', 'd']))
Out[213]: 
        one     three       two
b -0.138894 -0.177289  1.136249
c  0.011617  0.462215 -0.448789

Renaming / mapping labels

rename()方法允许您根据某些映射(字典或系列)或任意函数重新标记轴。

In [214]: s
Out[214]: 
a   -0.365106
b    1.092702
c   -1.481449
d    1.781190
e   -0.031543
dtype: float64

In [215]: s.rename(str.upper)
Out[215]: 
A   -0.365106
B    1.092702
C   -1.481449
D    1.781190
E   -0.031543
dtype: float64

如果传递一个函数,它必须在使用任何标签调用时返回一个值(并且必须生成一组唯一值)。也可以使用dict或系列:

In [216]: df.rename(columns={'one' : 'foo', 'two' : 'bar'},
   .....:           index={'a' : 'apple', 'b' : 'banana', 'd' : 'durian'})
   .....: 
Out[216]: 
             foo     three       bar
apple  -0.626544       NaN -0.351587
banana -0.138894 -0.177289  1.136249
c       0.011617  0.462215 -0.448789
durian       NaN  1.124472 -1.101558

如果映射不包括列/索引标签,则不会重命名。此外,映射中的额外标签不会抛出错误。

rename()方法还提供了一个inplace命名参数,默认为False并复制基础数据。传递inplace=True可重新命名数据。

版本0.18.0中的新功能。

最后,rename()也接受一个标量或列表,用于更改Series.name属性。

In [217]: s.rename("scalar-name")
Out[217]: 
a   -0.365106
b    1.092702
c   -1.481449
d    1.781190
e   -0.031543
Name: scalar-name, dtype: float64

Panel类具有相关的rename_axis()类,可以重命名其三个轴中的任何一个。

Iteration

对pandas对象基本迭代的行为取决于类型。当对一个Series迭代时,它被认为是数组类,并且基本迭代产生值。其他数据结构,如DataFrame和Panel,遵循类似于对象的“键”的迭代惯例。

简而言之,基本迭代(for i in object)会产生:

因此,例如,对DataFrame进行迭代可以得到列名:

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

In [219]: for col in df:
   .....:     print(col)
   .....: 
col1
col2

Pandas对象也有像dict一样的iteritems()方法来遍历(key,value)对。

要遍历DataFrame的行,可以使用以下方法:

警告

通过pandas对象进行迭代通常是慢。在许多情况下,不需要对行进行手动迭代,可以使用以下方法之一来避免:

警告

您应该不要修改您要迭代的内容。这不能保证在所有情况下都可用。根据数据类型,迭代器返回一个副本而不是一个视图,并且写入它将没有效果!

例如,在以下情况下,设置值不起作用:

In [220]: df = pd.DataFrame({'a': [1, 2, 3], 'b': ['a', 'b', 'c']})

In [221]: for index, row in df.iterrows():
   .....:     row['a'] = 10
   .....: 

In [222]: df
Out[222]: 
   a  b
0  1  a
1  2  b
2  3  c

iteritems

与dict类似接口一致,iteritems()通过键值对进行迭代:

例如:

In [223]: for item, frame in wp.iteritems():
   .....:     print(item)
   .....:     print(frame)
   .....: 
Item1
                   A         B         C         D
2000-01-01 -1.032011  0.969818 -0.962723  1.382083
2000-01-02 -0.938794  0.669142 -0.433567 -0.273610
2000-01-03  0.680433 -0.308450 -0.276099 -1.821168
2000-01-04 -1.993606 -1.927385 -2.027924  1.624972
2000-01-05  0.551135  3.059267  0.455264 -0.030740
Item2
                   A         B         C         D
2000-01-01  0.935716  1.061192 -2.107852  0.199905
2000-01-02  0.323586 -0.641630 -0.587514  0.053897
2000-01-03  0.194889 -0.381994  0.318587  2.089075
2000-01-04 -0.728293 -0.090255 -0.748199  1.318931
2000-01-05 -2.029766  0.792652  0.461007 -0.542749

iterrows

iterrows()允许您将DataFrame的行作为Series对象进行迭代。它返回一个迭代器,产生每个索引值以及包含每行中数据的Series:

In [224]: for row_index, row in df.iterrows():
   .....:     print('%s\n%s' % (row_index, row))
   .....: 
0
a    1
b    a
Name: 0, dtype: object
1
a    2
b    b
Name: 1, dtype: object
2
a    3
b    c
Name: 2, dtype: object

注意

因为iterrows()为每一行返回一个Series,所以它不保留跨行的Dtypes(对于DataFrames,Dtypes保留在列之间)。例如,

In [225]: df_orig = pd.DataFrame([[1, 1.5]], columns=['int', 'float'])

In [226]: df_orig.dtypes
Out[226]: 
int        int64
float    float64
dtype: object

In [227]: row = next(df_orig.iterrows())[1]

In [228]: row
Out[228]: 
int      1.0
float    1.5
Name: 0, dtype: float64

以系列形式返回的row中的所有值现在都转换为浮动,也是列x中的原始整数值:

In [229]: row['int'].dtype
Out[229]: dtype('float64')

In [230]: df_orig['int'].dtype
Out[230]: dtype('int64')

要在遍历行时保留dtypes,最好使用itertuples(),它返回值的namedtuples,通常比iterrows快得多。

例如,一个设计的方式来转置DataFrame将是:

In [231]: df2 = pd.DataFrame({'x': [1, 2, 3], 'y': [4, 5, 6]})

In [232]: print(df2)
   x  y
0  1  4
1  2  5
2  3  6

In [233]: print(df2.T)
   0  1  2
x  1  2  3
y  4  5  6

In [234]: df2_t = pd.DataFrame(dict((idx,values) for idx, values in df2.iterrows()))

In [235]: print(df2_t)
   0  1  2
x  1  2  3
y  4  5  6

itertuples

itertuples()方法将返回一个迭代器,为DataFrame中的每一行生成一个namedtuple。元组的第一个元素将是行的对应索引值,而剩余的值是行值。

例如,

In [236]: for row in df.itertuples():
   .....:     print(row)
   .....: 
Pandas(Index=0, a=1, b='a')
Pandas(Index=1, a=2, b='b')
Pandas(Index=2, a=3, b='c')

此方法不会将该行转换为Series对象,而只返回namedtuple中的值。因此,itertuples()保留值的数据类型,通常比iterrows()更快。

注意

如果列名称是无效的Python标识符,重复,或以下划线开头,则列名称将重命名为位置名称。在大量列(> 255)的情况下,返回常规元组。

.dt accessor

Series具有访问器,以简洁地返回类似于系列的值的datetime属性,如果它是类似于系列的日期时间/期间。这将返回一个系列,索引像现有的系列。

# datetime
In [237]: s = pd.Series(pd.date_range('20130101 09:10:12', periods=4))

In [238]: s
Out[238]: 
0   2013-01-01 09:10:12
1   2013-01-02 09:10:12
2   2013-01-03 09:10:12
3   2013-01-04 09:10:12
dtype: datetime64[ns]

In [239]: s.dt.hour
Out[239]: 
0    9
1    9
2    9
3    9
dtype: int64

In [240]: s.dt.second
Out[240]: 
0    12
1    12
2    12
3    12
dtype: int64

In [241]: s.dt.day
Out[241]: 
0    1
1    2
2    3
3    4
dtype: int64

这使得很好的表达式像这样:

In [242]: s[s.dt.day==2]
Out[242]: 
1   2013-01-02 09:10:12
dtype: datetime64[ns]

你可以使用tz_localize轻松转换时区

In [243]: stz = s.dt.tz_localize('US/Eastern')

In [244]: stz
Out[244]: 
0   2013-01-01 09:10:12-05:00
1   2013-01-02 09:10:12-05:00
2   2013-01-03 09:10:12-05:00
3   2013-01-04 09:10:12-05:00
dtype: datetime64[ns, US/Eastern]

In [245]: stz.dt.tz
Out[245]: <DstTzInfo 'US/Eastern' LMT-1 day, 19:04:00 STD>

您还可以链接这些类型的操作:

In [246]: s.dt.tz_localize('UTC').dt.tz_convert('US/Eastern')
Out[246]: 
0   2013-01-01 04:10:12-05:00
1   2013-01-02 04:10:12-05:00
2   2013-01-03 04:10:12-05:00
3   2013-01-04 04:10:12-05:00
dtype: datetime64[ns, US/Eastern]

您还可以将datetime值格式化为字符串Series.dt.strftime(),该格式支持与标准strftime()相同的格式。

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

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

In [249]: s.dt.strftime('%Y/%m/%d')
Out[249]: 
0    2013/01/01
1    2013/01/02
2    2013/01/03
3    2013/01/04
dtype: object
# PeriodIndex
In [250]: s = pd.Series(pd.period_range('20130101', periods=4))

In [251]: s
Out[251]: 
0   2013-01-01
1   2013-01-02
2   2013-01-03
3   2013-01-04
dtype: object

In [252]: s.dt.strftime('%Y/%m/%d')
Out[252]: 
0    2013/01/01
1    2013/01/02
2    2013/01/03
3    2013/01/04
dtype: object

.dt存取器适用于period和timedelta类型。

# period
In [253]: s = pd.Series(pd.period_range('20130101', periods=4, freq='D'))

In [254]: s
Out[254]: 
0   2013-01-01
1   2013-01-02
2   2013-01-03
3   2013-01-04
dtype: object

In [255]: s.dt.year
Out[255]: 
0    2013
1    2013
2    2013
3    2013
dtype: int64

In [256]: s.dt.day
Out[256]: 
0    1
1    2
2    3
3    4
dtype: int64
# timedelta
In [257]: s = pd.Series(pd.timedelta_range('1 day 00:00:05', periods=4, freq='s'))

In [258]: s
Out[258]: 
0   1 days 00:00:05
1   1 days 00:00:06
2   1 days 00:00:07
3   1 days 00:00:08
dtype: timedelta64[ns]

In [259]: s.dt.days
Out[259]: 
0    1
1    1
2    1
3    1
dtype: int64

In [260]: s.dt.seconds
Out[260]: 
0    5
1    6
2    7
3    8
dtype: int64

In [261]: s.dt.components
Out[261]: 
   days  hours  minutes  seconds  milliseconds  microseconds  nanoseconds
0     1      0        0        5             0             0            0
1     1      0        0        6             0             0            0
2     1      0        0        7             0             0            0
3     1      0        0        8             0             0            0

注意

Series.dt如果您使用非datetimelike值访问,则会引发TypeError

Vectorized string methods

系列配备了一组字符串处理方法,使其易于对数组的每个元素进行操作。也许最重要的是,这些方法自动排除丢失/ NA值。这些通过系列的str属性访问,通常具有与等效(标量)内置字符串方法匹配的名称。例如:

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

In [263]: s.str.lower()
Out[263]: 
0       a
1       b
2       c
3    aaba
4    baca
5     NaN
6    caba
7     dog
8     cat
dtype: object

还提供了强大的模式匹配方法,但请注意,模式匹配通常默认使用正则表达式(在某些情况下总是使用它们)。

有关完整的说明,请参阅Vectorized String Methods。

Sorting

警告

排序API在0.17.0中基本上改变,对于这些改变,参见here。特别地,默认情况下,所有排序方法都返回一个新对象,并且DO NOT就地运行(除非传递inplace=True)。

您可能感兴趣的有两种显而易见的排序:按标签排序和按实际值排序。

By Index

排序轴标签(索引)的主要方法是Series.sort_index()和DataFrame.sort_index()方法。

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

# DataFrame
In [265]: unsorted_df.sort_index()
Out[265]: 
   three  two  one
a    NaN  NaN  NaN
b    NaN  NaN  NaN
c    NaN  NaN  NaN
d    NaN  NaN  NaN

In [266]: unsorted_df.sort_index(ascending=False)
Out[266]: 
   three  two  one
d    NaN  NaN  NaN
c    NaN  NaN  NaN
b    NaN  NaN  NaN
a    NaN  NaN  NaN

In [267]: unsorted_df.sort_index(axis=1)
Out[267]: 
   one  three  two
a  NaN    NaN  NaN
d  NaN    NaN  NaN
c  NaN    NaN  NaN
b  NaN    NaN  NaN

# Series
In [268]: unsorted_df['three'].sort_index()
Out[268]: 
a   NaN
b   NaN
c   NaN
d   NaN
Name: three, dtype: float64

By Values

Series.sort_values()和DataFrame.sort_values()是value排序的入口点(即列或行中的值)。DataFrame.sort_values()可以为axis=0接受可选的by参数,它将使用任意向量或DataFrame的列名称确定排序顺序:

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

In [270]: df1.sort_values(by='two')
Out[270]: 
   one  three  two
0    2      5    1
2    1      3    2
1    1      4    3
3    1      2    4

by参数可以获取列名称列表,例如:

In [271]: df1[['one', 'two', 'three']].sort_values(by=['one','two'])
Out[271]: 
   one  two  three
2    1    2      3
1    1    3      4
3    1    4      2
0    2    1      5

这些方法通过na_position参数对NA值进行了特殊处理:

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

In [273]: s.sort_values()
Out[273]: 
0       A
3    Aaba
1       B
4    Baca
6    CABA
8     cat
7     dog
2     NaN
5     NaN
dtype: object

In [274]: s.sort_values(na_position='first')
Out[274]: 
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 [275]: ser = pd.Series([1, 2, 3])

In [276]: ser.searchsorted([0, 3])
Out[276]: array([0, 2])

In [277]: ser.searchsorted([0, 4])
Out[277]: array([0, 3])

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

In [279]: ser.searchsorted([1, 3], side='left')
Out[279]: array([0, 2])

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

In [281]: ser.searchsorted([0, 3], sorter=np.argsort(ser))
Out[281]: array([0, 2])

smallest / largest values

版本0.14.0中的新功能。

Series具有返回最小或最大的n值的nsmallest()和nlargest()对于大的Series,这可以比排序整个系列并在结果上调用head(n)更快。

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

In [283]: s
Out[283]: 
0    9
1    8
2    5
3    3
4    6
5    7
6    0
7    2
8    4
9    1
dtype: int64

In [284]: s.sort_values()
Out[284]: 
6    0
9    1
7    2
3    3
8    4
2    5
4    6
5    7
1    8
0    9
dtype: int64

In [285]: s.nsmallest(3)
Out[285]: 
6    0
9    1
7    2
dtype: int64

In [286]: s.nlargest(3)
Out[286]: 
0    9
1    8
5    7
dtype: int64

版本0.17.0中的新功能。

DataFrame也具有nlargest和nsmallest方法。

In [287]: 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 [288]: df.nlargest(3, 'a')
Out[288]: 
    a  b    c
5  11  f  3.0
3  10  c  3.2
4   8  e  NaN

In [289]: df.nlargest(5, ['a', 'c'])
Out[289]: 
    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
6  -1  f  4.0

In [290]: df.nsmallest(3, 'a')
Out[290]: 
   a  b    c
0 -2  a  1.0
1 -1  b  2.0
6 -1  f  4.0
1 -1  b  2.0
6 -1  f  4.0

In [291]: df.nsmallest(5, ['a', 'c'])
Out[291]: 
   a  b    c
0 -2  a  1.0
1 -1  b  2.0
6 -1  f  4.0
1 -1  b  2.0
6 -1  f  4.0
2  1  d  4.0
4  8  e  NaN

Sorting by a multi-index column

当列为多索引时,必须明确排序,并且通过完全指定by

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

In [293]: df1.sort_values(by=('a','two'))
Out[293]: 
    a         b
  one two three
3   1   2     4
2   1   3     2
1   1   4     3
0   2   5     1

Copying

pandas对象上的copy()方法复制基础数据(虽然不是轴索引,因为它们是不可变的),并返回一个新对象。请注意,很少需要复制对象。例如,只有很少的方法来改变DataFrame 就地:

  • 插入,删除或修改列
  • 分配到index或columns属性
  • 对于同质数据,通过values属性或高级索引直接修改值

要清楚,pandas方法一般不对原始对象进行修改;几乎所有的方法都返回新的对象,保持原来的对象不变。如果数据被修改,那是因为你明确这样做了。

dtypes

The main types stored in pandas objects are float, int, bool, datetime64[ns] and datetime64[ns, tz] (in >= 0.17.0), timedelta[ns], category (in >= 0.15.0), and object. 此外,这些类型具有项目大小,例如int64和int32。有关datetime64 [ns, tz] dtypes的更多详细信息,请参见Series with TZ

DataFrames的一个方便的dtypes属性返回具有每列数据类型的Series。

In [294]: dft = 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 [295]: dft
Out[295]: 
          A  B    C          D    E      F  G
0  0.954940  1  foo 2001-01-02  1.0  False  1
1  0.318163  1  foo 2001-01-02  1.0  False  1
2  0.985803  1  foo 2001-01-02  1.0  False  1

In [296]: dft.dtypes
Out[296]: 
A           float64
B             int64
C            object
D    datetime64[ns]
E           float32
F              bool
G              int8
dtype: object

在Series上使用dtype属性。

In [297]: dft['A'].dtype
Out[297]: dtype('float64')

如果pandas对象包含多个数据类型IN A SINGLE COLUMN,则将选择列的dtype以适应所有数据类型(object是最常见的)。

# these ints are coerced to floats
In [298]: pd.Series([1, 2, 3, 4, 5, 6.])
Out[298]: 
0    1.0
1    2.0
2    3.0
3    4.0
4    5.0
5    6.0
dtype: float64

# string data forces an ``object`` dtype
In [299]: pd.Series([1, 2, 3, 6., 'foo'])
Out[299]: 
0      1
1      2
2      3
3      6
4    foo
dtype: object

方法get_dtype_counts()将返回DataFrame中每种类型的列数:

In [300]: dft.get_dtype_counts()
Out[300]: 
bool              1
datetime64[ns]    1
float32           1
float64           1
int64             1
int8              1
object            1
dtype: int64

数字类型将传播并且可以在DataFrames中共存(从v0.11.0开始)。如果传递一个dtype(直接通过dtype关键字,传递ndarray或传递Series,它将被保留在DataFrame操作。此外,不同的数字类型将NOT组合。下面的例子会给你一个味道。

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

In [302]: df1
Out[302]: 
          A
0  0.647650
1  0.822993
2  1.778703
3 -1.543048
4 -0.123256
5  2.239740
6 -0.143778
7 -2.885090

In [303]: df1.dtypes
Out[303]: 
A    float32
dtype: object

In [304]: 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')) ))
   .....: 

In [305]: df2
Out[305]: 
          A         B    C
0  0.027588  0.296947    0
1 -1.150391  0.007045  255
2  0.246460  0.707877    1
3 -0.455078  0.950661    0
4 -1.507812  0.087527    0
5 -0.502441 -0.339212    0
6  0.528809 -0.278698    0
7  0.590332  1.775379    0

In [306]: df2.dtypes
Out[306]: 
A    float16
B    float64
C      uint8
dtype: object

defaults

默认整数类型为int64,float类型为平台(32位或64位)的float64,REGARDLESS。以下都将导致int64 dtypes。

In [307]: pd.DataFrame([1, 2], columns=['a']).dtypes
Out[307]: 
a    int64
dtype: object

In [308]: pd.DataFrame({'a': [1, 2]}).dtypes
Out[308]: 
a    int64
dtype: object

In [309]: pd.DataFrame({'a': 1 }, index=list(range(2))).dtypes
Out[309]: 
a    int64
dtype: object

Numpy,但是会在创建数组时选择平台相关类型。以下WILL会导致32位平台上的int32。

In [310]: frame = pd.DataFrame(np.array([1, 2]))

upcasting

当与其他类型组合时,类型可以被向上转换,这意味着它们从当前类型(例如int提升到float)

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

In [312]: df3
Out[312]: 
          A         B      C
0  0.675238  0.296947    0.0
1 -0.327398  0.007045  255.0
2  2.025163  0.707877    1.0
3 -1.998126  0.950661    0.0
4 -1.631068  0.087527    0.0
5  1.737299 -0.339212    0.0
6  0.385030 -0.278698    0.0
7 -2.294758  1.775379    0.0

In [313]: df3.dtypes
Out[313]: 
A    float32
B    float64
C    float64
dtype: object

DataFrame上的values属性返回dtypes的低共同分母,表示可以适应所有类型的dtype得到均匀的数字numpy数组。这可能会强制某些向上转换。

In [314]: df3.values.dtype
Out[314]: dtype('float64')

astype

您可以使用astype()方法将dtypes从一个显式转换为另一个。这些将默认返回一个副本,即使dtype没有改变(通过copy=False来改变这种行为)。此外,如果astype操作无效,它们将引发异常。

向上转换总是根据numpy规则。如果在操作中涉及两个不同的类型,则更多的一般将被用作操作的结果。

In [315]: df3
Out[315]: 
          A         B      C
0  0.675238  0.296947    0.0
1 -0.327398  0.007045  255.0
2  2.025163  0.707877    1.0
3 -1.998126  0.950661    0.0
4 -1.631068  0.087527    0.0
5  1.737299 -0.339212    0.0
6  0.385030 -0.278698    0.0
7 -2.294758  1.775379    0.0

In [316]: df3.dtypes
Out[316]: 
A    float32
B    float64
C    float64
dtype: object

# conversion of dtypes
In [317]: df3.astype('float32').dtypes
Out[317]: 
A    float32
B    float32
C    float32
dtype: object

使用astype()将列的一个子集转换为指定的类型

In [318]: dft = pd.DataFrame({'a': [1,2,3], 'b': [4,5,6], 'c': [7, 8, 9]})

In [319]: dft[['a','b']] = dft[['a','b']].astype(np.uint8)

In [320]: dft
Out[320]: 
   a  b  c
0  1  4  7
1  2  5  8
2  3  6  9

In [321]: dft.dtypes
Out[321]: 
a    uint8
b    uint8
c    int64
dtype: object

注意

当尝试使用astype()和loc()将列子集转换为指定类型时,将发生向上转换。

loc()尝试适合我们分配给当前的dtypes,而[]将从右侧覆盖它们。因此,下面的代码段会产生非预期的结果。

In [322]: dft = pd.DataFrame({'a': [1,2,3], 'b': [4,5,6], 'c': [7, 8, 9]})

In [323]: dft.loc[:, ['a', 'b']].astype(np.uint8).dtypes
Out[323]: 
a    uint8
b    uint8
dtype: object

In [324]: dft.loc[:, ['a', 'b']] = dft.loc[:, ['a', 'b']].astype(np.uint8)

In [325]: dft.dtypes
Out[325]: 
a    int64
b    int64
c    int64
dtype: object

object conversion

pandas提供了各种函数来尝试强制将类型从object dtype转换为其他类型。以下函数可用于一维对象数组或标量:

要强制执行转换,我们可以传递errors参数,它指定了pandas应该如何处理无法转换为所需dtype或对象的元素。默认情况下,errors='raise',表示在转换过程中会遇到任何错误。但是,如果errors='coerce',这些错误将被忽略,pandas会将有问题的元素转换为pd.NaT(datetime和timedelta)或np.nan(用于数字)。这可能是有用的,如果你在读取大多数所需的dtype(例如,数字,datetime)的数据,但偶尔有不合格的元素混合,你想表示为丢失:

In [333]: import datetime

In [334]: m = ['apple', datetime.datetime(2016, 3, 2)]

In [335]: pd.to_datetime(m, errors='coerce')
Out[335]: DatetimeIndex(['NaT', '2016-03-02'], dtype='datetime64[ns]', freq=None)

In [336]: m = ['apple', 2, 3]

In [337]: pd.to_numeric(m, errors='coerce')
Out[337]: array([ nan,   2.,   3.])

In [338]: m = ['apple', pd.Timedelta('1day')]

In [339]: pd.to_timedelta(m, errors='coerce')
Out[339]: TimedeltaIndex([NaT, '1 days'], dtype='timedelta64[ns]', freq=None)

errors参数有第三个选项errors='ignore',如果遇到转换为所需数据类型的任何错误,它将简单地返回传入的数据:

In [340]: import datetime

In [341]: m = ['apple', datetime.datetime(2016, 3, 2)]

In [342]: pd.to_datetime(m, errors='ignore')
Out[342]: array(['apple', datetime.datetime(2016, 3, 2, 0, 0)], dtype=object)

In [343]: m = ['apple', 2, 3]

In [344]: pd.to_numeric(m, errors='ignore')
Out[344]: array(['apple', 2, 3], dtype=object)

In [345]: m = ['apple', pd.Timedelta('1day')]

In [346]: pd.to_timedelta(m, errors='ignore')
Out[346]: array(['apple', Timedelta('1 days 00:00:00')], dtype=object)

除了对象转换,to_numeric()提供了另一个参数downcast,它提供了将新(或已经)数字数据下转换为较小的dtype的选项,记忆:

In [347]: m = ['1', 2, 3]

In [348]: pd.to_numeric(m, downcast='integer')   # smallest signed int dtype
Out[348]: array([1, 2, 3], dtype=int8)

In [349]: pd.to_numeric(m, downcast='signed')    # same as 'integer'
Out[349]: array([1, 2, 3], dtype=int8)

In [350]: pd.to_numeric(m, downcast='unsigned')  # smallest unsigned int dtype
Out[350]: array([1, 2, 3], dtype=uint8)

In [351]: pd.to_numeric(m, downcast='float')     # smallest float dtype
Out[351]: array([ 1.,  2.,  3.], dtype=float32)

因为这些方法仅适用于一维数组,列表或标量;它们不能直接用于多维对象,如DataFrames。然而,使用apply(),我们可以有效地“应用”每个列上的函数:

In [352]: import datetime

In [353]: df = pd.DataFrame([['2016-07-09', datetime.datetime(2016, 3, 2)]] * 2, dtype='O')

In [354]: df
Out[354]: 
            0                    1
0  2016-07-09  2016-03-02 00:00:00
1  2016-07-09  2016-03-02 00:00:00

In [355]: df.apply(pd.to_datetime)
Out[355]: 
           0          1
0 2016-07-09 2016-03-02
1 2016-07-09 2016-03-02

In [356]: df = pd.DataFrame([['1.1', 2, 3]] * 2, dtype='O')

In [357]: df
Out[357]: 
     0  1  2
0  1.1  2  3
1  1.1  2  3

In [358]: df.apply(pd.to_numeric)
Out[358]: 
     0  1  2
0  1.1  2  3
1  1.1  2  3

In [359]: df = pd.DataFrame([['5us', pd.Timedelta('1day')]] * 2, dtype='O')

In [360]: df
Out[360]: 
     0                1
0  5us  1 days 00:00:00
1  5us  1 days 00:00:00

In [361]: df.apply(pd.to_timedelta)
Out[361]: 
                0      1
0 00:00:00.000005 1 days
1 00:00:00.000005 1 days

gotchas

在integer类型数据上执行选择操作可以轻松地将数据上传到floating。在未引入nans(从0.11.0开始)的情况下,输入数据的dtype将被保留。参见integer na gotchas

In [362]: dfi = df3.astype('int32')

In [363]: dfi['E'] = 1

In [364]: dfi
Out[364]: 
   A  B    C  E
0  0  0    0  1
1  0  0  255  1
2  2  0    1  1
3 -1  0    0  1
4 -1  0    0  1
5  1  0    0  1
6  0  0    0  1
7 -2  1    0  1

In [365]: dfi.dtypes
Out[365]: 
A    int32
B    int32
C    int32
E    int64
dtype: object

In [366]: casted = dfi[dfi>0]

In [367]: casted
Out[367]: 
     A    B      C  E
0  NaN  NaN    NaN  1
1  NaN  NaN  255.0  1
2  2.0  NaN    1.0  1
3  NaN  NaN    NaN  1
4  NaN  NaN    NaN  1
5  1.0  NaN    NaN  1
6  NaN  NaN    NaN  1
7  NaN  1.0    NaN  1

In [368]: casted.dtypes
Out[368]: 
A    float64
B    float64
C    float64
E      int64
dtype: object

而float dtypes不变。

In [369]: dfa = df3.copy()

In [370]: dfa['A'] = dfa['A'].astype('float32')

In [371]: dfa.dtypes
Out[371]: 
A    float32
B    float64
C    float64
dtype: object

In [372]: casted = dfa[df2>0]

In [373]: casted
Out[373]: 
          A         B      C
0  0.675238  0.296947    NaN
1       NaN  0.007045  255.0
2  2.025163  0.707877    1.0
3       NaN  0.950661    NaN
4       NaN  0.087527    NaN
5       NaN       NaN    NaN
6  0.385030       NaN    NaN
7 -2.294758  1.775379    NaN

In [374]: casted.dtypes
Out[374]: 
A    float32
B    float64
C    float64
dtype: object

Selecting columns based on dtype

版本0.14.1中的新功能。

select_dtypes()方法基于其dtype实现列的子集。

首先,让我们创建一个具有不同dtypes的DataFrame:

In [375]: 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 [376]: df['tdeltas'] = df.dates.diff()

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

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

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

In [380]: df
Out[380]: 
   bool1  bool2 category                      dates  float64  int64 string  \
0   True  False        A 2016-12-24 18:31:36.297875      4.0      1      a   
1  False   True        B 2016-12-25 18:31:36.297875      5.0      2      b   
2   True  False        C 2016-12-26 18:31:36.297875      6.0      3      c   

   uint8  tdeltas  uint64 other_dates            tz_aware_dates  
0      3      NaT       3  2013-01-01 2013-01-01 00:00:00-05:00  
1      4   1 days       4  2013-01-02 2013-01-02 00:00:00-05:00  
2      5   1 days       5  2013-01-03 2013-01-03 00:00:00-05:00  

和dtypes

In [381]: df.dtypes
Out[381]: 
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() has two parameters include and exclude that allow you to say “give me the columns WITH these dtypes” (include) and/or “give the columns WITHOUT these dtypes” (exclude).

例如,要选择bool列

In [382]: df.select_dtypes(include=[bool])
Out[382]: 
   bool1  bool2
0   True  False
1  False   True
2   True  False

您还可以在numpy dtype层次结构中传递dtype的名称:

In [383]: df.select_dtypes(include=['bool'])
Out[383]: 
   bool1  bool2
0   True  False
1  False   True
2   True  False

select_dtypes()也适用于通用dtypes。

例如,要选择所有数字和布尔列,同时排除无符号整数

In [384]: df.select_dtypes(include=['number', 'bool'], exclude=['unsignedinteger'])
Out[384]: 
   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 dtype:

In [385]: df.select_dtypes(include=['object'])
Out[385]: 
  string
0      a
1      b
2      c

要查看像numpy.number这样的通用dtype的所有子类型,您可以定义一个函数,返回子类型的树:

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

所有numpy类型都是numpy.generic的子类:

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

注意

Pandas还定义类型category和datetime64 [ns, tz] numpy层次结构,并且不会显示与上述函数。

注意

include和exclude参数必须是非字符串序列。