原文:http://pandas.pydata.org/pandas-docs/stable/basics.html
校对:(虚位以待)
我们在这里讨论了很多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'])
...:
为了查看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
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
上面的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()
函数,用于计算关于 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
,按行或列或者元素进行操作。
版本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等。
由于并非所有函数都可以向量化(接受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
会将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
调用时, 。
您可能希望获取一个对象,并将其轴重命名为与另一个对象相同的标签。虽然这种语法很简单,尽管很详细,但它是一个常见的操作,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
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)
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()
不会对索引的顺序进行任何检查。
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
这允许您使用适当的字符串指定公差。
与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
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()
类,可以重命名其三个轴中的任何一个。
对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的行,可以使用以下方法:
iterrows()
:将DataFrame的行迭代为(index,Series)对。这将行转换为Series对象,这可以更改dtypes并具有一些性能影响。itertuples()
:将DataFrame的行迭代为值的namedtuples。这比iterrows()
快得多,在大多数情况下,最好使用它来遍历DataFrame的值。警告
通过pandas对象进行迭代通常是慢。在许多情况下,不需要对行进行手动迭代,可以使用以下方法之一来避免:
apply()
而不是对所有值进行迭代。请参阅function application上的文档。警告
您应该不要修改您要迭代的内容。这不能保证在所有情况下都可用。根据数据类型,迭代器返回一个副本而不是一个视图,并且写入它将没有效果!
例如,在以下情况下,设置值不起作用:
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
与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()
允许您将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()
方法将返回一个迭代器,为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)的情况下,返回常规元组。
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
系列配备了一组字符串处理方法,使其易于对数组的每个元素进行操作。也许最重要的是,这些方法自动排除丢失/ 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。
警告
排序API在0.17.0中基本上改变,对于这些改变,参见here。特别地,默认情况下,所有排序方法都返回一个新对象,并且DO NOT就地运行(除非传递inplace=True
)。
您可能感兴趣的有两种显而易见的排序:按标签排序和按实际值排序。
排序轴标签(索引)的主要方法是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
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
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])
版本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
当列为多索引时,必须明确排序,并且通过完全指定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
pandas对象上的copy()
方法复制基础数据(虽然不是轴索引,因为它们是不可变的),并返回一个新对象。请注意,很少需要复制对象。例如,只有很少的方法来改变DataFrame 就地:
- 插入,删除或修改列
- 分配到
index
或columns
属性- 对于同质数据,通过
values
属性或高级索引直接修改值
要清楚,pandas方法一般不对原始对象进行修改;几乎所有的方法都返回新的对象,保持原来的对象不变。如果数据被修改,那是因为你明确这样做了。
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
默认整数类型为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]))
当与其他类型组合时,类型可以被向上转换,这意味着它们从当前类型(例如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()
方法将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
pandas提供了各种函数来尝试强制将类型从object
dtype转换为其他类型。以下函数可用于一维对象数组或标量:
to_numeric()
(转换为数字dtypes)
In [326]: m = ['1.1', 2, 3]
In [327]: pd.to_numeric(m)
Out[327]: array([ 1.1, 2. , 3. ])
to_datetime()
(转换为datetime对象)
In [328]: import datetime
In [329]: m = ['2016-07-09', datetime.datetime(2016, 3, 2)]
In [330]: pd.to_datetime(m)
Out[330]: DatetimeIndex(['2016-07-09', '2016-03-02'], dtype='datetime64[ns]', freq=None)
to_timedelta()
(转换为timedelta对象)
In [331]: m = ['5us', pd.Timedelta('1day')]
In [332]: pd.to_timedelta(m)
Out[332]: TimedeltaIndex(['0 days 00:00:00.000005', '1 days 00:00:00'], dtype='timedelta64[ns]', freq=None)
要强制执行转换,我们可以传递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
在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
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
参数必须是非字符串序列。