基本功能

原文: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一致
  • 轴标签
    • Seriesindex(唯一的轴)
    • DataFrameindex(行)和columns(列)
    • Panelitemsmajor_axisminor_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关键字,匹配indexcolumn

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对象。这些布尔对象可用于索引操作,请参阅这里

布尔归约

您可以应用归约:emptyany()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+dfdf*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

尝试比较不同长度的IndexSeries对象。将产生一个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

描述性统计量

大量方法用于计算SeriesDataFramePanel上的描述性统计量和其他相关操作。这些中的大多数是像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方法(如meanstdsum)将默认排除 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中,idxminidxmax称为argminargmax

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

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中的新功能。

DataFramesSeries当然可以传递到函数中。但是,如果函数需要链式调用,请考虑使用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的方法。

在上述示例中,函数fgh每个都期待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管道,以及最近的dplyrmagrittr的启发,它们将流行的(%>%)(管道读取)运算符引入了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

limittolerance参数在重建索引时提供对填充的额外控制。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

注意当在DatetimeIndexTimedeltaIndexPeriodIndex上使用时,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也具有nlargestnsmallest方法。

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 就地

  • 插入,删除或修改列
  • 分配到indexcolumns属性
  • 对于同质数据,通过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. 此外,这些类型具有项目大小,例如int64int32有关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位)的float64REGARDLESS以下都将导致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还定义类型categorydatetime64 [ns, tz] numpy层次结构,并且不会显示与上述函数。

注意

includeexclude参数必须是非字符串序列。