基本基本功能#
在这里,我们将讨论许多Pandas数据结构共有的基本功能。首先,让我们创建一些示例对象,就像 10 minutes to 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"])
头和尾#
若要查看Series或DataFrame对象的小示例,请使用 head()
和 tail()
方法:研究方法。要显示的元素的默认数量为五个,但您可以传递一个自定义数量。
In [4]: long_series = pd.Series(np.random.randn(1000))
In [5]: long_series.head()
Out[5]:
0 -1.157892
1 -1.344312
2 0.844885
3 1.075770
4 -0.109050
dtype: float64
In [6]: long_series.tail(3)
Out[6]:
997 -0.289388
998 -1.020544
999 0.589993
dtype: float64
属性和基础数据#
Pandas对象具有多个属性,使您可以访问元数据
形状 :提供对象的轴尺寸,与ndarray一致
- 轴标签
系列 : 索引 (仅轴)
DataFrame : 索引 (行)和 列
请注意, 可以安全地将这些属性分配给 好了!
In [7]: df[:2]
Out[7]:
A B C
2000-01-01 -0.173215 0.119209 -1.044236
2000-01-02 -0.861849 -2.104569 -0.494929
In [8]: df.columns = [x.lower() for x in df.columns]
In [9]: df
Out[9]:
a b c
2000-01-01 -0.173215 0.119209 -1.044236
2000-01-02 -0.861849 -2.104569 -0.494929
2000-01-03 1.071804 0.721555 -0.706771
2000-01-04 -1.039575 0.271860 -0.424972
2000-01-05 0.567020 0.276232 -1.087401
2000-01-06 -0.673690 0.113648 -1.478427
2000-01-07 0.524988 0.404705 0.577046
2000-01-08 -1.715002 -1.039268 -0.370647
Pandas物品 (Index
, Series
, DataFrame
)可以被视为数组的容器,它保存实际数据并进行实际计算。对于许多类型,基础数组是 numpy.ndarray
。但是,Pandas和第三方类库可能 延伸 NumPy的类型系统以添加对自定义数组的支持(请参见 数据类型 )。
若要在 Index
或 Series
,请使用 .array
财产性
In [10]: s.array
Out[10]:
<PandasArray>
[ 0.4691122999071863, -0.2828633443286633, -1.5090585031735124,
-1.1356323710171934, 1.2121120250208506]
Length: 5, dtype: float64
In [11]: s.index.array
Out[11]:
<PandasArray>
['a', 'b', 'c', 'd', 'e']
Length: 5, dtype: object
array
将永远是一个 ExtensionArray
。准确的细节是什么 ExtensionArray
Pandas使用它们的原因和原因有点超出了本文的介绍范围。看见 数据类型 想要更多。
如果您知道需要NumPy数组,请使用 to_numpy()
或 numpy.asarray()
。
In [12]: s.to_numpy()
Out[12]: array([ 0.4691, -0.2829, -1.5091, -1.1356, 1.2121])
In [13]: np.asarray(s)
Out[13]: array([ 0.4691, -0.2829, -1.5091, -1.1356, 1.2121])
当系列或索引由 ExtensionArray
, to_numpy()
可能涉及复制数据和强制取值。看见 数据类型 想要更多。
to_numpy()
在一定程度上控制了 dtype
由此产生的 numpy.ndarray
。例如,考虑使用时区的DateTime。NumPy没有数据类型来表示时区感知的日期时间,因此有两种可能有用的表示:
一种对象数据类型
numpy.ndarray
使用Timestamp
对象,每个对象都具有正确的tz
A
datetime64[ns]
-dtypenumpy.ndarray
,其中的值已转换为UTC并丢弃了时区
可以通过以下方式保留时区 dtype=object
In [14]: ser = pd.Series(pd.date_range("2000", periods=2, tz="CET"))
In [15]: ser.to_numpy(dtype=object)
Out[15]:
array([Timestamp('2000-01-01 00:00:00+0100', tz='CET'),
Timestamp('2000-01-02 00:00:00+0100', tz='CET')], dtype=object)
或随手扔掉 dtype='datetime64[ns]'
In [16]: ser.to_numpy(dtype="datetime64[ns]")
Out[16]:
array(['1999-12-31T23:00:00.000000000', '2000-01-01T23:00:00.000000000'],
dtype='datetime64[ns]')
获取“原始数据”。 DataFrame
可能会更复杂一些。当你的 DataFrame
对于所有列只有一种数据类型, DataFrame.to_numpy()
将返回底层数据:
In [17]: df.to_numpy()
Out[17]:
array([[-0.1732, 0.1192, -1.0442],
[-0.8618, -2.1046, -0.4949],
[ 1.0718, 0.7216, -0.7068],
[-1.0396, 0.2719, -0.425 ],
[ 0.567 , 0.2762, -1.0874],
[-0.6737, 0.1136, -1.4784],
[ 0.525 , 0.4047, 0.577 ],
[-1.715 , -1.0393, -0.3706]])
如果DataFrame包含同构类型的数据,则ndarray实际上可以被就地修改,并且更改将反映在数据结构中。对于异类数据(例如,DataFrame的一些列并不都是相同的数据类型),情况并非如此。与轴标签不同,不能将值属性本身指定给。
备注
在处理异类数据时,将选择结果ndarray的数据类型以容纳所有涉及的数据。例如,如果涉及字符串,则结果将是对象dtype。如果只有浮点数和整数,则结果数组将是浮点数类型。
在过去,Pandas建议 Series.values
或 DataFrame.values
用于从Series或DataFrame中提取数据。您仍然可以在旧的代码库和在线上找到对这些代码的引用。展望未来,我们建议避免 .values
并使用 .array
或 .to_numpy()
。 .values
有以下缺点:
当您的系列包含 extension type ,目前还不清楚
Series.values
返回NumPy数组或扩展数组。Series.array
将始终返回一个ExtensionArray
,并且永远不会复制数据。Series.to_numpy()
将始终返回NumPy数组,可能会以复制/强制取值为代价。当DataFrame包含混合数据类型时,
DataFrame.values
可能涉及复制数据并将值强制转换为公共数据类型,这是一种相对昂贵的操作。DataFrame.to_numpy()
作为一种方法,使得返回的NumPy数组不能是DataFrame中相同数据的视图。
加速运营#
类支持加速某些类型的二进制数值和布尔运算。 numexpr
库和 bottleneck
类库。
这些库在处理大型数据集时特别有用,并提供了很大的加速比。 numexpr
使用智能分块、缓存和多核。 bottleneck
是一组专门的cython例程,在处理具有 nans
。
以下是一个示例(使用100列x 100,000行 DataFrames
):
运营 |
0.11.0(毫秒) |
早期版本(毫秒) |
与之前的比率 |
---|---|---|---|
|
13.32 |
125.35 |
0.1063 |
|
21.71 |
36.63 |
0.5928 |
|
22.04 |
36.50 |
0.6039 |
强烈建议您同时安装这两个库。请参阅部分 Recommended Dependencies 获取更多安装信息。
默认情况下,这两个选项都已启用,您可以通过设置以下选项进行控制:
pd.set_option("compute.use_bottleneck", False)
pd.set_option("compute.use_numexpr", False)
灵活的二进制操作#
对于PANDA数据结构之间的二进制操作,有两个关键的兴趣点:
高维(如DataFrame)和低维(如系列)对象之间的广播行为。
计算中缺少数据。
我们将演示如何独立管理这些问题,尽管它们可以同时处理。
匹配/广播行为#
DataFrame有一些方法 add()
, sub()
, mul()
, div()
和相关功能 radd()
, rsub()
..用于执行二进制运算。对于广播行为,系列输入是最重要的。使用这些函数,您可以使用在 索引 或 列 通过 axis 关键词:
In [18]: 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 [19]: df
Out[19]:
one two three
a 1.394981 1.772517 NaN
b 0.343054 1.912123 -0.050390
c 0.695246 1.478369 1.227435
d NaN 0.279344 -0.613172
In [20]: row = df.iloc[1]
In [21]: column = df["two"]
In [22]: df.sub(row, axis="columns")
Out[22]:
one two three
a 1.051928 -0.139606 NaN
b 0.000000 0.000000 0.000000
c 0.352192 -0.433754 1.277825
d NaN -1.632779 -0.562782
In [23]: df.sub(row, axis=1)
Out[23]:
one two three
a 1.051928 -0.139606 NaN
b 0.000000 0.000000 0.000000
c 0.352192 -0.433754 1.277825
d NaN -1.632779 -0.562782
In [24]: df.sub(column, axis="index")
Out[24]:
one two three
a -0.377535 0.0 NaN
b -1.569069 0.0 -1.962513
c -0.783123 0.0 -0.250933
d NaN 0.0 -0.892516
In [25]: df.sub(column, axis=0)
Out[25]:
one two three
a -0.377535 0.0 NaN
b -1.569069 0.0 -1.962513
c -0.783123 0.0 -0.250933
d NaN 0.0 -0.892516
此外,您还可以将多索引DataFrame的某个级别与Series对齐。
In [26]: dfmi = df.copy()
In [27]: dfmi.index = pd.MultiIndex.from_tuples(
....: [(1, "a"), (1, "b"), (1, "c"), (2, "a")], names=["first", "second"]
....: )
....:
In [28]: dfmi.sub(column, axis=0, level="second")
Out[28]:
one two three
first second
1 a -0.377535 0.000000 NaN
b -1.569069 0.000000 -1.962513
c -0.783123 0.000000 -0.250933
2 a NaN -1.493173 -2.385688
系列和指数还支持 divmod()
内置式。此函数同时进行地板除法和模运算,返回与左侧类型相同的两个元组。例如:
In [29]: s = pd.Series(np.arange(10))
In [30]: s
Out[30]:
0 0
1 1
2 2
3 3
4 4
5 5
6 6
7 7
8 8
9 9
dtype: int64
In [31]: div, rem = divmod(s, 3)
In [32]: div
Out[32]:
0 0
1 0
2 0
3 1
4 1
5 1
6 2
7 2
8 2
9 3
dtype: int64
In [33]: rem
Out[33]:
0 0
1 1
2 2
3 0
4 1
5 2
6 0
7 1
8 2
9 0
dtype: int64
In [34]: idx = pd.Index(np.arange(10))
In [35]: idx
Out[35]: Int64Index([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], dtype='int64')
In [36]: div, rem = divmod(idx, 3)
In [37]: div
Out[37]: Int64Index([0, 0, 0, 1, 1, 1, 2, 2, 2, 3], dtype='int64')
In [38]: rem
Out[38]: Int64Index([0, 1, 2, 0, 1, 2, 0, 1, 2, 0], dtype='int64')
我们也可以以元素为基础 divmod()
:
In [39]: div, rem = divmod(s, [2, 2, 3, 3, 4, 4, 5, 5, 6, 6])
In [40]: div
Out[40]:
0 0
1 0
2 0
3 1
4 1
5 1
6 1
7 1
8 1
9 1
dtype: int64
In [41]: rem
Out[41]:
0 0
1 1
2 2
3 0
4 0
5 1
6 1
7 2
8 2
9 3
dtype: int64
缺少具有填充值的数据/操作#
在Series和DataFrame中,算术函数可以选择输入 fill_value ,即在某个位置最多缺少一个值时要替换的值。例如,在添加两个DataFrame对象时,您可能希望将NaN视为0,除非两个DataFrame都缺少该值,在这种情况下,结果将是NaN(以后可以使用以下命令将NaN替换为其他值 fillna
如果你愿意的话)。
In [42]: df
Out[42]:
one two three
a 1.394981 1.772517 NaN
b 0.343054 1.912123 -0.050390
c 0.695246 1.478369 1.227435
d NaN 0.279344 -0.613172
In [43]: df2
Out[43]:
one two three
a 1.394981 1.772517 1.000000
b 0.343054 1.912123 -0.050390
c 0.695246 1.478369 1.227435
d NaN 0.279344 -0.613172
In [44]: df + df2
Out[44]:
one two three
a 2.789963 3.545034 NaN
b 0.686107 3.824246 -0.100780
c 1.390491 2.956737 2.454870
d NaN 0.558688 -1.226343
In [45]: df.add(df2, fill_value=0)
Out[45]:
one two three
a 2.789963 3.545034 1.000000
b 0.686107 3.824246 -0.100780
c 1.390491 2.956737 2.454870
d NaN 0.558688 -1.226343
灵活的比较#
Series和DataFrame有二进制比较方法 eq
, ne
, lt
, gt
, le
,以及 ge
其行为类似于上述二进制算术运算:
In [46]: df.gt(df2)
Out[46]:
one two three
a False False False
b False False False
c False False False
d False False False
In [47]: df2.ne(df)
Out[47]:
one two three
a False False True
b False False False
c False False False
d True False False
这些操作将生成一个与左侧输入相同类型的Pandas对象,该输入类型为dtype bool
。这些 boolean
对象可以在索引操作中使用,请参阅 Boolean indexing 。
布尔约简#
您可以应用减值: empty
, any()
, all()
,以及 bool()
提供一种汇总布尔结果的方法。
In [48]: (df > 0).all()
Out[48]:
one False
two True
three False
dtype: bool
In [49]: (df > 0).any()
Out[49]:
one True
two True
three True
dtype: bool
您可以减少到最终的布尔值。
In [50]: (df > 0).any().any()
Out[50]: True
可以测试Pandas对象是否为空,方法是 empty
财产。
In [51]: df.empty
Out[51]: False
In [52]: pd.DataFrame(columns=list("ABC")).empty
Out[52]: True
要在布尔上下文中计算单个元素的Pandas对象,请使用方法 bool()
:
In [53]: pd.Series([True]).bool()
Out[53]: True
In [54]: pd.Series([False]).bool()
Out[54]: False
In [55]: pd.DataFrame([[True]]).bool()
Out[55]: True
In [56]: pd.DataFrame([[False]]).bool()
Out[56]: False
警告
您可能会尝试执行以下操作:
>>> if df:
... pass
或
>>> df and df2
当您尝试比较多个值时,这两种情况都会引发错误。::
ValueError: The truth value of an array is ambiguous. Use a.empty, a.any() or a.all().
看见 gotchas 以进行更详细的讨论。
比较对象是否等价#
通常,您可能会发现计算相同结果的方法不止一种。作为一个简单的例子,请考虑 df + df
和 df * 2
。要测试这两个计算是否产生相同的结果,给出上面显示的工具,您可以想象使用 (df + df == df * 2).all()
。但事实上,这句话是错误的:
In [57]: df + df == df * 2
Out[57]:
one two three
a True True False
b True True True
c True True True
d False True True
In [58]: (df + df == df * 2).all()
Out[58]:
one False
two True
three False
dtype: bool
请注意,布尔DataFrame df + df == df * 2
包含一些假值!这是因为NAN不能平等地比较:
In [59]: np.nan == np.nan
Out[59]: False
因此,NDFrames(如Series和DataFrames)具有 equals()
用于测试相等性的方法,相应位置中的NAN被视为相等。
In [60]: (df + df).equals(df * 2)
Out[60]: True
请注意,系列或DataFrame索引需要具有相同的顺序,才能使相等为True:
In [61]: df1 = pd.DataFrame({"col": ["foo", 0, np.nan]})
In [62]: df2 = pd.DataFrame({"col": [np.nan, 0, "foo"]}, index=[2, 1, 0])
In [63]: df1.equals(df2)
Out[63]: False
In [64]: df1.equals(df2.sort_index())
Out[64]: True
比较类似数组的对象#
在比较PANAS数据结构和标量值时,可以方便地执行逐个元素的比较:
In [65]: pd.Series(["foo", "bar", "baz"]) == "foo"
Out[65]:
0 True
1 False
2 False
dtype: bool
In [66]: pd.Index(["foo", "bar", "baz"]) == "foo"
Out[66]: array([ True, False, False])
Pandas还处理相同长度的不同阵列状物体之间的元素比较:
In [67]: pd.Series(["foo", "bar", "baz"]) == pd.Index(["foo", "bar", "qux"])
Out[67]:
0 True
1 True
2 False
dtype: bool
In [68]: pd.Series(["foo", "bar", "baz"]) == np.array(["foo", "bar", "qux"])
Out[68]:
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行为不同,在NumPy行为中可以广播比较:
In [69]: np.array([1, 2, 3]) == np.array([2])
Out[69]: array([False, True, False])
或者,如果无法播放,则返回FALSE:
In [70]: np.array([1, 2, 3]) == np.array([1, 2])
Out[70]: False
组合重叠数据集#
偶尔出现的一个问题是两个相似的数据集的组合,其中一个中的值优先于另一个中的值。一个例子是代表一个特定经济指标的两个数据系列,其中一个被认为是“较高质量的”。然而,较低质量的系列可能会进一步追溯到历史上,或者拥有更完整的数据覆盖范围。因此,我们希望合并两个DataFrame对象,其中一个DataFrame中缺少的值有条件地用另一个DataFrame中类似标签的值填充。实现此操作的函数为 combine_first()
,我们将对此进行说明:
In [71]: df1 = pd.DataFrame(
....: {"A": [1.0, np.nan, 3.0, 5.0, np.nan], "B": [np.nan, 2.0, 3.0, np.nan, 6.0]}
....: )
....:
In [72]: df2 = pd.DataFrame(
....: {
....: "A": [5.0, 2.0, 4.0, np.nan, 3.0, 7.0],
....: "B": [np.nan, np.nan, 3.0, 4.0, 6.0, 8.0],
....: }
....: )
....:
In [73]: df1
Out[73]:
A B
0 1.0 NaN
1 NaN 2.0
2 3.0 3.0
3 5.0 NaN
4 NaN 6.0
In [74]: df2
Out[74]:
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 [75]: df1.combine_first(df2)
Out[75]:
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 [76]: def combiner(x, y):
....: return np.where(pd.isna(x), y, x)
....:
In [77]: df1.combine(df2, combiner)
Out[77]:
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 。其中大多数是聚合(从而产生较低维度的结果),如 sum()
, mean()
,以及 quantile()
,但其中一些,比如 cumsum()
和 cumprod()
,生成相同大小的对象。一般来说,这些方法需要一个 axis 争论,就像 Ndarray。{{sum,std,...}} ,但轴可以按名称或整数指定:
系列 :不需要轴参数
DataFrame :“index”(轴=0,默认),“Columns”(轴=1)
例如:
In [78]: df
Out[78]:
one two three
a 1.394981 1.772517 NaN
b 0.343054 1.912123 -0.050390
c 0.695246 1.478369 1.227435
d NaN 0.279344 -0.613172
In [79]: df.mean(0)
Out[79]:
one 0.811094
two 1.360588
three 0.187958
dtype: float64
In [80]: df.mean(1)
Out[80]:
a 1.583749
b 0.734929
c 1.133683
d -0.166914
dtype: float64
所有这些方法都有一个 skipna
选项,指示是否排除丢失的数据 (True
默认情况下):
In [81]: df.sum(0, skipna=False)
Out[81]:
one NaN
two 5.442353
three NaN
dtype: float64
In [82]: df.sum(axis=1, skipna=True)
Out[82]:
a 3.167498
b 2.204786
c 3.401050
d -0.333828
dtype: float64
结合广播/算术行为,可以非常简洁地描述各种统计过程,如标准化(渲染数据的平均值为0和标准差为1):
In [83]: ts_stand = (df - df.mean()) / df.std()
In [84]: ts_stand.std()
Out[84]:
one 1.0
two 1.0
three 1.0
dtype: float64
In [85]: xs_stand = df.sub(df.mean(1), axis=0).div(df.std(1), axis=0)
In [86]: xs_stand.std(1)
Out[86]:
a 1.0
b 1.0
c 1.0
d 1.0
dtype: float64
请注意,像这样的方法 cumsum()
和 cumprod()
保留…的位置 NaN
价值观。这与以下情况有所不同 expanding()
和 rolling()
因为 NaN
行为还由 min_periods
参数。
In [87]: df.cumsum()
Out[87]:
one two three
a 1.394981 1.772517 NaN
b 1.738035 3.684640 -0.050390
c 2.433281 5.163008 1.177045
d NaN 5.442353 0.563873
以下是常用函数的快速参考汇总表。每一项也都需要一个可选的 level
参数,仅当对象具有 hierarchical index 。
功能 |
描述 |
---|---|
|
非北美观察值的数目 |
|
价值总和 |
|
价值平均数 |
|
平均绝对偏差 |
|
数值的算术中位数 |
|
最低要求 |
|
极大值 |
|
模 |
|
绝对值 |
|
价值的乘积 |
|
贝塞尔校正样本标准差 |
|
无偏方差 |
|
平均值的标准误差 |
|
样本偏斜度(3阶矩) |
|
样本峰度(第四个时刻) |
|
样本分位数(%处的值) |
|
累计和 |
|
累计乘积 |
|
累计最大值 |
|
累计最小值 |
请注意,一些NumPy方法,如 mean
, std
,以及 sum
默认情况下,将排除系列输入上的Nas:
In [88]: np.mean(df["one"])
Out[88]: 0.8110935116651192
In [89]: np.mean(df["one"].to_numpy())
Out[89]: nan
Series.nunique()
将返回系列中唯一的非NA值的数量:
In [90]: series = pd.Series(np.random.randn(500))
In [91]: series[20:500] = np.nan
In [92]: series[10:20] = 5
In [93]: series.nunique()
Out[93]: 11
汇总数据:描述#
有一个很方便的 describe()
计算有关数据帧的系列或列的各种汇总统计信息的函数(当然不包括Nas):
In [94]: series = pd.Series(np.random.randn(1000))
In [95]: series[::2] = np.nan
In [96]: series.describe()
Out[96]:
count 500.000000
mean -0.021292
std 1.015906
min -2.683763
25% -0.699070
50% -0.069718
75% 0.714483
max 3.160915
dtype: float64
In [97]: frame = pd.DataFrame(np.random.randn(1000, 5), columns=["a", "b", "c", "d", "e"])
In [98]: frame.iloc[::2] = np.nan
In [99]: frame.describe()
Out[99]:
a b c d e
count 500.000000 500.000000 500.000000 500.000000 500.000000
mean 0.033387 0.030045 -0.043719 -0.051686 0.005979
std 1.017152 0.978743 1.025270 1.015988 1.006695
min -3.000951 -2.637901 -3.303099 -3.159200 -3.188821
25% -0.647623 -0.576449 -0.712369 -0.691338 -0.691115
50% 0.047578 -0.021499 -0.023888 -0.032652 -0.025363
75% 0.729907 0.775880 0.618896 0.670047 0.649748
max 2.740139 2.752332 3.004229 2.728702 3.240991
您可以选择要包括在输出中的特定百分位数:
In [100]: series.describe(percentiles=[0.05, 0.25, 0.75, 0.95])
Out[100]:
count 500.000000
mean -0.021292
std 1.015906
min -2.683763
5% -1.645423
25% -0.699070
50% -0.069718
75% 0.714483
95% 1.711409
max 3.160915
dtype: float64
默认情况下,始终包含中位数。
对于非数字系列对象, describe()
将提供唯一值数量和出现频率最高的值的简单摘要:
In [101]: s = pd.Series(["a", "a", "b", "b", "a", "a", np.nan, "c", "d", "a"])
In [102]: s.describe()
Out[102]:
count 9
unique 4
top a
freq 5
dtype: object
请注意,在混合类型DataFrame对象上, describe()
将限制摘要仅包括数字列,或者如果没有数字列,则仅包括分类列:
In [103]: frame = pd.DataFrame({"a": ["Yes", "Yes", "No", "No"], "b": range(4)})
In [104]: frame.describe()
Out[104]:
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 [105]: frame.describe(include=["object"])
Out[105]:
a
count 4
unique 2
top Yes
freq 2
In [106]: frame.describe(include=["number"])
Out[106]:
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 [107]: frame.describe(include="all")
Out[107]:
a b
count 4 4.000000
unique 2 NaN
top Yes NaN
freq 2 NaN
mean NaN 1.500000
std NaN 1.290994
min NaN 0.000000
25% NaN 0.750000
50% NaN 1.500000
75% NaN 2.250000
max NaN 3.000000
该功能依赖于 select_dtypes 。有关接受的输入的详细信息,请参阅那里。
最小/最大值指标#
这个 idxmin()
和 idxmax()
Series和DataFrame上的函数计算具有最小和最大相应值的索引标签:
In [108]: s1 = pd.Series(np.random.randn(5))
In [109]: s1
Out[109]:
0 1.118076
1 -0.352051
2 -1.242883
3 -1.277155
4 -0.641184
dtype: float64
In [110]: s1.idxmin(), s1.idxmax()
Out[110]: (3, 0)
In [111]: df1 = pd.DataFrame(np.random.randn(5, 3), columns=["A", "B", "C"])
In [112]: df1
Out[112]:
A B C
0 -0.327863 -0.946180 -0.137570
1 -0.186235 -0.257213 -0.486567
2 -0.507027 -0.871259 -0.111110
3 2.000339 -2.430505 0.089759
4 -0.321434 -0.033695 0.096271
In [113]: df1.idxmin(axis=0)
Out[113]:
A 2
B 3
C 1
dtype: int64
In [114]: df1.idxmax(axis=1)
Out[114]:
0 C
1 A
2 C
3 A
4 C
dtype: object
当有多行(或多列)匹配最小或最大值时, idxmin()
和 idxmax()
返回第一个匹配的索引:
In [115]: df3 = pd.DataFrame([2, 1, 1, 3, np.nan], columns=["A"], index=list("edcba"))
In [116]: df3
Out[116]:
A
e 2.0
d 1.0
c 1.0
b 3.0
a NaN
In [117]: df3["A"].idxmin()
Out[117]: 'd'
备注
idxmin
和 idxmax
被称为 argmin
和 argmax
在NumPy。
值计数(直方图)/模式#
这个 value_counts()
序列方法和顶级函数计算一维值数组的直方图。它还可以用作规则数组上的函数:
In [118]: data = np.random.randint(0, 7, size=50)
In [119]: data
Out[119]:
array([6, 6, 2, 3, 5, 3, 2, 5, 4, 5, 4, 3, 4, 5, 0, 2, 0, 4, 2, 0, 3, 2,
2, 5, 6, 5, 3, 4, 6, 4, 3, 5, 6, 4, 3, 6, 2, 6, 6, 2, 3, 4, 2, 1,
6, 2, 6, 1, 5, 4])
In [120]: s = pd.Series(data)
In [121]: s.value_counts()
Out[121]:
6 10
2 10
4 9
3 8
5 8
0 3
1 2
dtype: int64
In [122]: pd.value_counts(data)
Out[122]:
6 10
2 10
4 9
3 8
5 8
0 3
1 2
dtype: int64
1.1.0 新版功能.
这个 value_counts()
方法可用于计算多列中的组合。默认情况下,使用所有列,但可以使用 subset
论点。
In [123]: data = {"a": [1, 2, 3, 4], "b": ["x", "x", "y", "y"]}
In [124]: frame = pd.DataFrame(data)
In [125]: frame.value_counts()
Out[125]:
a b
1 x 1
2 x 1
3 y 1
4 y 1
dtype: int64
类似地,您可以获得Series或DataFrame中的值的最频繁出现的值,即模式:
In [126]: s5 = pd.Series([1, 1, 3, 3, 3, 5, 5, 7, 7, 7])
In [127]: s5.mode()
Out[127]:
0 3
1 7
dtype: int64
In [128]: df5 = pd.DataFrame(
.....: {
.....: "A": np.random.randint(0, 7, size=50),
.....: "B": np.random.randint(-10, 15, size=50),
.....: }
.....: )
.....:
In [129]: df5.mode()
Out[129]:
A B
0 1.0 -9
1 NaN 10
2 NaN 13
离散化和量化#
连续值可以使用 cut()
(基于值的垃圾箱)和 qcut()
(基于样本分位数的仓位)函数:
In [130]: arr = np.random.randn(20)
In [131]: factor = pd.cut(arr, 4)
In [132]: factor
Out[132]:
[(-0.251, 0.464], (-0.968, -0.251], (0.464, 1.179], (-0.251, 0.464], (-0.968, -0.251], ..., (-0.251, 0.464], (-0.968, -0.251], (-0.968, -0.251], (-0.968, -0.251], (-0.968, -0.251]]
Length: 20
Categories (4, interval[float64, right]): [(-0.968, -0.251] < (-0.251, 0.464] < (0.464, 1.179] <
(1.179, 1.893]]
In [133]: factor = pd.cut(arr, [-5, -1, 0, 1, 5])
In [134]: factor
Out[134]:
[(0, 1], (-1, 0], (0, 1], (0, 1], (-1, 0], ..., (-1, 0], (-1, 0], (-1, 0], (-1, 0], (-1, 0]]
Length: 20
Categories (4, interval[int64, right]): [(-5, -1] < (-1, 0] < (0, 1] < (1, 5]]
qcut()
计算样本分位数。例如,我们可以将一些正态分布的数据分割成大小相等的四分位数,如下所示:
In [135]: arr = np.random.randn(30)
In [136]: factor = pd.qcut(arr, [0, 0.25, 0.5, 0.75, 1])
In [137]: factor
Out[137]:
[(0.569, 1.184], (-2.278, -0.301], (-2.278, -0.301], (0.569, 1.184], (0.569, 1.184], ..., (-0.301, 0.569], (1.184, 2.346], (1.184, 2.346], (-0.301, 0.569], (-2.278, -0.301]]
Length: 30
Categories (4, interval[float64, right]): [(-2.278, -0.301] < (-0.301, 0.569] < (0.569, 1.184] <
(1.184, 2.346]]
In [138]: pd.value_counts(factor)
Out[138]:
(-2.278, -0.301] 8
(1.184, 2.346] 8
(-0.301, 0.569] 7
(0.569, 1.184] 7
dtype: int64
我们还可以传递无限大的值来定义垃圾箱:
In [139]: arr = np.random.randn(20)
In [140]: factor = pd.cut(arr, [-np.inf, 0, np.inf])
In [141]: factor
Out[141]:
[(-inf, 0.0], (0.0, inf], (0.0, inf], (-inf, 0.0], (-inf, 0.0], ..., (-inf, 0.0], (-inf, 0.0], (-inf, 0.0], (0.0, inf], (0.0, inf]]
Length: 20
Categories (2, interval[float64, right]): [(-inf, 0.0] < (0.0, inf]]
功能应用#
要将您自己或其他库的函数应用于Pandas对象,您应该知道下面的三种方法。要使用的适当方法取决于您的函数是否期望对整个 DataFrame
或 Series
、行或列方式或元素方式。
逐表函数应用#
DataFrames
和 Series
可以传递到函数中。但是,如果需要在链中调用该函数,请考虑使用 pipe()
方法。
首先进行一些设置:
In [142]: def extract_city_name(df):
.....: """
.....: Chicago, IL -> Chicago for city_name column
.....: """
.....: df["city_name"] = df["city_and_code"].str.split(",").str.get(0)
.....: return df
.....:
In [143]: def add_country_name(df, country_name=None):
.....: """
.....: Chicago -> Chicago-US for city_name column
.....: """
.....: col = "city_name"
.....: df["city_and_country"] = df[col] + country_name
.....: return df
.....:
In [144]: df_p = pd.DataFrame({"city_and_code": ["Chicago, IL"]})
extract_city_name
和 add_country_name
函数是否接受和返回 DataFrames
。
现在比较以下内容:
In [145]: add_country_name(extract_city_name(df_p), country_name="US")
Out[145]:
city_and_code city_name city_and_country
0 Chicago, IL Chicago ChicagoUS
相当于:
In [146]: df_p.pipe(extract_city_name).pipe(add_country_name, country_name="US")
Out[146]:
city_and_code city_name city_and_country
0 Chicago, IL Chicago ChicagoUS
Pandas鼓励第二种风格,这被称为方法链。 pipe
使您可以轻松地在方法链中使用您自己或其他库的函数,以及Pandas的方法。
在上面的示例中,函数 extract_city_name
和 add_country_name
每个人都希望有一个 DataFrame
作为第一个位置论元。如果您希望应用的函数将其数据作为第二个参数,该怎么办?在这种情况下,请提供 pipe
具有一个元组的 (callable, data_keyword)
。 .pipe
将会将 DataFrame
添加到元组中指定的参数。
例如,我们可以使用统计模型来拟合回归。他们的API要求先有一个公式,然后 DataFrame
作为第二个论点, data
。我们传入函数、关键字对 (sm.ols, 'data')
至 pipe
:
In [147]: import statsmodels.formula.api as sm
---------------------------------------------------------------------------
ModuleNotFoundError Traceback (most recent call last)
Input In [147], in <cell line: 1>()
----> 1 import statsmodels.formula.api as sm
ModuleNotFoundError: No module named 'statsmodels'
In [148]: bb = pd.read_csv("data/baseball.csv", index_col="id")
In [149]: (
.....: bb.query("h > 0")
.....: .assign(ln_h=lambda df: np.log(df.h))
.....: .pipe((sm.ols, "data"), "hr ~ ln_h + year + g + C(lg)")
.....: .fit()
.....: .summary()
.....: )
.....:
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
Input In [149], in <cell line: 2>()
1 (
2 bb.query("h > 0")
3 .assign(ln_h=lambda df: np.log(df.h))
----> 4 .pipe((sm.ols, "data"), "hr ~ ln_h + year + g + C(lg)")
5 .fit()
6 .summary()
7 )
NameError: name 'sm' is not defined
管道方法的灵感来自于Unix管道和最近的 dplyr 和 magrittr, 推出了广受欢迎的 (%>%)
(读取管道)运算符 R. 该计划的实施 pipe
这里非常干净,在Python中有宾至如归的感觉。我们鼓励您查看 pipe()
。
行或列函数应用程序#
属性可以沿DataFrame的轴应用任意函数 apply()
方法,与描述性统计方法一样,该方法接受可选的 axis
论点:
In [150]: df.apply(np.mean)
Out[150]:
one 0.811094
two 1.360588
three 0.187958
dtype: float64
In [151]: df.apply(np.mean, axis=1)
Out[151]:
a 1.583749
b 0.734929
c 1.133683
d -0.166914
dtype: float64
In [152]: df.apply(lambda x: x.max() - x.min())
Out[152]:
one 1.051928
two 1.632779
three 1.840607
dtype: float64
In [153]: df.apply(np.cumsum)
Out[153]:
one two three
a 1.394981 1.772517 NaN
b 1.738035 3.684640 -0.050390
c 2.433281 5.163008 1.177045
d NaN 5.442353 0.563873
In [154]: df.apply(np.exp)
Out[154]:
one two three
a 4.034899 5.885648 NaN
b 1.409244 6.767440 0.950858
c 2.004201 4.385785 3.412466
d NaN 1.322262 0.541630
这个 apply()
方法还将对字符串方法名进行调度。
In [155]: df.apply("mean")
Out[155]:
one 0.811094
two 1.360588
three 0.187958
dtype: float64
In [156]: df.apply("mean", axis=1)
Out[156]:
a 1.583749
b 0.734929
c 1.133683
d -0.166914
dtype: float64
传递给的函数的返回类型 apply()
影响最终输出的类型。 DataFrame.apply
对于默认行为:
如果应用的函数返回
Series
,最终输出是一个DataFrame
。这些列与Series
由应用的函数返回。如果应用的函数返回任何其他类型,则最终输出为
Series
。
此默认行为可以使用 result_type
,它接受三个选项: reduce
, broadcast
,以及 expand
。这些将决定List-Like返回值如何扩展(或不扩展)为 DataFrame
。
apply()
结合一些智慧可以用来回答关于数据集的许多问题。例如,假设我们想要提取每列出现最大值的日期:
In [157]: tsdf = pd.DataFrame(
.....: np.random.randn(1000, 3),
.....: columns=["A", "B", "C"],
.....: index=pd.date_range("1/1/2000", periods=1000),
.....: )
.....:
In [158]: tsdf.apply(lambda x: x.idxmax())
Out[158]:
A 2000-08-06
B 2001-01-18
C 2001-07-18
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 [159]: tsdf
Out[159]:
A B C
2000-01-01 -0.158131 -0.232466 0.321604
2000-01-02 -1.810340 -3.105758 0.433834
2000-01-03 -1.209847 -1.156793 -0.136794
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.653602 0.178875 1.008298
2000-01-09 1.007996 0.462824 0.254472
2000-01-10 0.307473 0.600337 1.643950
In [160]: tsdf.apply(pd.Series.interpolate)
Out[160]:
A B C
2000-01-01 -0.158131 -0.232466 0.321604
2000-01-02 -1.810340 -3.105758 0.433834
2000-01-03 -1.209847 -1.156793 -0.136794
2000-01-04 -1.098598 -0.889659 0.092225
2000-01-05 -0.987349 -0.622526 0.321243
2000-01-06 -0.876100 -0.355392 0.550262
2000-01-07 -0.764851 -0.088259 0.779280
2000-01-08 -0.653602 0.178875 1.008298
2000-01-09 1.007996 0.462824 0.254472
2000-01-10 0.307473 0.600337 1.643950
最后, apply()
带着一个论点 raw
默认情况下为FALSE,即在应用该函数之前将每行或每列转换为Series。当设置为True时,传递的函数将改为接收ndarray对象,如果不需要索引功能,这会带来积极的性能影响。
聚合API#
Aggregation API允许以一种简洁的方式表达可能的多个聚合操作。此API在Pandas对象中类似,请参见 groupby API ,即 window API ,以及 resample API 。聚合的入口点是 DataFrame.aggregate()
,或别名 DataFrame.agg()
。
我们将使用与上面类似的起始帧:
In [161]: tsdf = pd.DataFrame(
.....: np.random.randn(10, 3),
.....: columns=["A", "B", "C"],
.....: index=pd.date_range("1/1/2000", periods=10),
.....: )
.....:
In [162]: tsdf.iloc[3:7] = np.nan
In [163]: tsdf
Out[163]:
A B C
2000-01-01 1.257606 1.004194 0.167574
2000-01-02 -0.749892 0.288112 -0.757304
2000-01-03 -0.207550 -0.298599 0.116018
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.814347 -0.257623 0.869226
2000-01-09 -0.250663 -1.206601 0.896839
2000-01-10 2.169758 -1.333363 0.283157
使用单个函数相当于 apply()
。您还可以将命名方法作为字符串传递。这些函数将返回一个 Series
合计产出的百分比:
In [164]: tsdf.agg(np.sum)
Out[164]:
A 3.033606
B -1.803879
C 1.575510
dtype: float64
In [165]: tsdf.agg("sum")
Out[165]:
A 3.033606
B -1.803879
C 1.575510
dtype: float64
# these are equivalent to a ``.sum()`` because we are aggregating
# on a single function
In [166]: tsdf.sum()
Out[166]:
A 3.033606
B -1.803879
C 1.575510
dtype: float64
上的单个聚合 Series
这将返回一个标量值:
In [167]: tsdf["A"].agg("sum")
Out[167]: 3.033606102414146
使用多个功能聚合#
您可以将多个聚合参数作为列表传递。每个传递的函数的结果都将是结果 DataFrame
。它们自然是从聚合函数中命名的。
In [168]: tsdf.agg(["sum"])
Out[168]:
A B C
sum 3.033606 -1.803879 1.57551
多个函数会产生多行:
In [169]: tsdf.agg(["sum", "mean"])
Out[169]:
A B C
sum 3.033606 -1.803879 1.575510
mean 0.505601 -0.300647 0.262585
vt.在.上 Series
,则多个函数返回一个 Series
,按函数名索引:
In [170]: tsdf["A"].agg(["sum", "mean"])
Out[170]:
sum 3.033606
mean 0.505601
Name: A, dtype: float64
传递一个 lambda
函数将产生一个 <lambda>
命名行:
In [171]: tsdf["A"].agg(["sum", lambda x: x.mean()])
Out[171]:
sum 3.033606
<lambda> 0.505601
Name: A, dtype: float64
传递命名函数将为该行生成该名称:
In [172]: def mymean(x):
.....: return x.mean()
.....:
In [173]: tsdf["A"].agg(["sum", mymean])
Out[173]:
sum 3.033606
mymean 0.505601
Name: A, dtype: float64
使用词典进行聚合#
将列名词典传递给标量或标量列表,以 DataFrame.agg
允许您自定义将哪些函数应用于哪些列。请注意,结果不是按任何特定顺序排列的,您可以使用 OrderedDict
取而代之的是保证有序。
In [174]: tsdf.agg({"A": "mean", "B": "sum"})
Out[174]:
A 0.505601
B -1.803879
dtype: float64
传递一个类似列表的函数将生成一个 DataFrame
输出。您将获得所有聚合器的类似于矩阵的输出。输出将由所有独特的函数组成。对于特定的列,未注明的将是 NaN
:
In [175]: tsdf.agg({"A": ["mean", "min"], "B": "sum"})
Out[175]:
A B
mean 0.505601 NaN
min -0.749892 NaN
sum NaN -1.803879
混合数据类型#
1.4.0 版后已移除: 不建议尝试确定哪些列无法聚合并从结果中静默删除它们,并将在将来的版本中删除这些列。如果提供的列或操作的任何部分失败,则调用 .agg
将会提高。
当呈现不能聚合的混合数据类型时, .agg
将只接受有效的聚合。这类似于如何 .groupby.agg
行得通。
In [176]: mdf = pd.DataFrame(
.....: {
.....: "A": [1, 2, 3],
.....: "B": [1.0, 2.0, 3.0],
.....: "C": ["foo", "bar", "baz"],
.....: "D": pd.date_range("20130101", periods=3),
.....: }
.....: )
.....:
In [177]: mdf.dtypes
Out[177]:
A int64
B float64
C object
D datetime64[ns]
dtype: object
In [178]: mdf.agg(["min", "sum"])
Out[178]:
A B C D
min 1 1.0 bar 2013-01-01
sum 6 6.0 foobarbaz NaT
自定义描述#
使用 .agg()
可以轻松创建一个定制的Describe函数,类似于内置的 describe function 。
In [179]: from functools import partial
In [180]: q_25 = partial(pd.Series.quantile, q=0.25)
In [181]: q_25.__name__ = "25%"
In [182]: q_75 = partial(pd.Series.quantile, q=0.75)
In [183]: q_75.__name__ = "75%"
In [184]: tsdf.agg(["count", "mean", "std", "min", q_25, "median", q_75, "max"])
Out[184]:
A B C
count 6.000000 6.000000 6.000000
mean 0.505601 -0.300647 0.262585
std 1.103362 0.887508 0.606860
min -0.749892 -1.333363 -0.757304
25% -0.239885 -0.979600 0.128907
median 0.303398 -0.278111 0.225365
75% 1.146791 0.151678 0.722709
max 2.169758 1.004194 0.896839
转换API#
这个 transform()
方法返回的对象的索引与原始对象相同(大小相同)。此接口允许您提供 多个 同时操作,而不是逐个操作。它的API非常类似于 .agg
原料药。
我们创建一个类似于上述部分中使用的框架。
In [185]: tsdf = pd.DataFrame(
.....: np.random.randn(10, 3),
.....: columns=["A", "B", "C"],
.....: index=pd.date_range("1/1/2000", periods=10),
.....: )
.....:
In [186]: tsdf.iloc[3:7] = np.nan
In [187]: tsdf
Out[187]:
A B C
2000-01-01 -0.428759 -0.864890 -0.675341
2000-01-02 -0.168731 1.338144 -1.279321
2000-01-03 -1.621034 0.438107 0.903794
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.254374 -1.240447 -0.201052
2000-01-09 -0.157795 0.791197 -1.144209
2000-01-10 -0.030876 0.371900 0.061932
变换整个帧。 .transform()
允许输入函数为:NumPy函数、字符串函数名或用户定义的函数。
In [188]: tsdf.transform(np.abs)
Out[188]:
A B C
2000-01-01 0.428759 0.864890 0.675341
2000-01-02 0.168731 1.338144 1.279321
2000-01-03 1.621034 0.438107 0.903794
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.254374 1.240447 0.201052
2000-01-09 0.157795 0.791197 1.144209
2000-01-10 0.030876 0.371900 0.061932
In [189]: tsdf.transform("abs")
Out[189]:
A B C
2000-01-01 0.428759 0.864890 0.675341
2000-01-02 0.168731 1.338144 1.279321
2000-01-03 1.621034 0.438107 0.903794
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.254374 1.240447 0.201052
2000-01-09 0.157795 0.791197 1.144209
2000-01-10 0.030876 0.371900 0.061932
In [190]: tsdf.transform(lambda x: x.abs())
Out[190]:
A B C
2000-01-01 0.428759 0.864890 0.675341
2000-01-02 0.168731 1.338144 1.279321
2000-01-03 1.621034 0.438107 0.903794
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.254374 1.240447 0.201052
2000-01-09 0.157795 0.791197 1.144209
2000-01-10 0.030876 0.371900 0.061932
这里 transform()
接收到单个函数;这等效于 ufunc 申请。
In [191]: np.abs(tsdf)
Out[191]:
A B C
2000-01-01 0.428759 0.864890 0.675341
2000-01-02 0.168731 1.338144 1.279321
2000-01-03 1.621034 0.438107 0.903794
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.254374 1.240447 0.201052
2000-01-09 0.157795 0.791197 1.144209
2000-01-10 0.030876 0.371900 0.061932
将单个函数传递给 .transform()
使用一个 Series
将产生一个单一的 Series
作为回报。
In [192]: tsdf["A"].transform(np.abs)
Out[192]:
2000-01-01 0.428759
2000-01-02 0.168731
2000-01-03 1.621034
2000-01-04 NaN
2000-01-05 NaN
2000-01-06 NaN
2000-01-07 NaN
2000-01-08 0.254374
2000-01-09 0.157795
2000-01-10 0.030876
Freq: D, Name: A, dtype: float64
多功能变换法#
传递多个函数将生成一列多索引DataFrame。第一级将是原始框架列名;第二级将是转换函数的名称。
In [193]: tsdf.transform([np.abs, lambda x: x + 1])
Out[193]:
A B C
absolute <lambda> absolute <lambda> absolute <lambda>
2000-01-01 0.428759 0.571241 0.864890 0.135110 0.675341 0.324659
2000-01-02 0.168731 0.831269 1.338144 2.338144 1.279321 -0.279321
2000-01-03 1.621034 -0.621034 0.438107 1.438107 0.903794 1.903794
2000-01-04 NaN NaN NaN NaN NaN NaN
2000-01-05 NaN NaN NaN NaN NaN NaN
2000-01-06 NaN NaN NaN NaN NaN NaN
2000-01-07 NaN NaN NaN NaN NaN NaN
2000-01-08 0.254374 1.254374 1.240447 -0.240447 0.201052 0.798948
2000-01-09 0.157795 0.842205 0.791197 1.791197 1.144209 -0.144209
2000-01-10 0.030876 0.969124 0.371900 1.371900 0.061932 1.061932
将多个函数传递给一个Series将生成一个DataFrame。得到的列名将是转换函数。
In [194]: tsdf["A"].transform([np.abs, lambda x: x + 1])
Out[194]:
absolute <lambda>
2000-01-01 0.428759 0.571241
2000-01-02 0.168731 0.831269
2000-01-03 1.621034 -0.621034
2000-01-04 NaN NaN
2000-01-05 NaN NaN
2000-01-06 NaN NaN
2000-01-07 NaN NaN
2000-01-08 0.254374 1.254374
2000-01-09 0.157795 0.842205
2000-01-10 0.030876 0.969124
用DICT改造#
传递一组函数将允许按列进行选择性转换。
In [195]: tsdf.transform({"A": np.abs, "B": lambda x: x + 1})
Out[195]:
A B
2000-01-01 0.428759 0.135110
2000-01-02 0.168731 2.338144
2000-01-03 1.621034 1.438107
2000-01-04 NaN NaN
2000-01-05 NaN NaN
2000-01-06 NaN NaN
2000-01-07 NaN NaN
2000-01-08 0.254374 -0.240447
2000-01-09 0.157795 1.791197
2000-01-10 0.030876 1.371900
传递列表的字典将生成带有这些选择性转换的多索引DataFrame。
In [196]: tsdf.transform({"A": np.abs, "B": [lambda x: x + 1, "sqrt"]})
Out[196]:
A B
absolute <lambda> sqrt
2000-01-01 0.428759 0.135110 NaN
2000-01-02 0.168731 2.338144 1.156782
2000-01-03 1.621034 1.438107 0.661897
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.254374 -0.240447 NaN
2000-01-09 0.157795 1.791197 0.889493
2000-01-10 0.030876 1.371900 0.609836
应用单元化函数#
由于并非所有函数都可以矢量化(接受NumPy数组并返回另一个数组或值),因此方法 applymap()
关于DataFrame和类比 map()
On Series接受任何接受单一值并返回单一值的Python函数。例如:
In [197]: df4
Out[197]:
one two three
a 1.394981 1.772517 NaN
b 0.343054 1.912123 -0.050390
c 0.695246 1.478369 1.227435
d NaN 0.279344 -0.613172
In [198]: def f(x):
.....: return len(str(x))
.....:
In [199]: df4["one"].map(f)
Out[199]:
a 18
b 19
c 18
d 3
Name: one, dtype: int64
In [200]: df4.applymap(f)
Out[200]:
one two three
a 18 17 3
b 19 18 20
c 18 18 16
d 3 19 19
Series.map()
具有一个附加功能;它可用于轻松地“链接”或“映射”由第二系列定义的值。这与以下因素密切相关 merging/joining functionality :
In [201]: s = pd.Series(
.....: ["six", "seven", "six", "seven", "six"], index=["a", "b", "c", "d", "e"]
.....: )
.....:
In [202]: t = pd.Series({"six": 6.0, "seven": 7.0})
In [203]: s
Out[203]:
a six
b seven
c six
d seven
e six
dtype: object
In [204]: s.map(t)
Out[204]:
a 6.0
b 7.0
c 6.0
d 7.0
e 6.0
dtype: float64
重建索引和更改标签#
reindex()
是Pandas的基本数据对齐方法。它用于实现几乎所有依赖于标签对齐功能的其他功能。至 重新编制索引 使数据与沿特定轴的给定标签集相匹配的手段。这可以实现以下几点:
重新排序现有数据以匹配一组新标注
在不存在该标签数据的标签位置插入缺失值(NA)标记
如果指定, fill 使用逻辑查找缺失标签的数据(与处理时间序列数据高度相关)
下面是一个简单的例子:
In [205]: s = pd.Series(np.random.randn(5), index=["a", "b", "c", "d", "e"])
In [206]: s
Out[206]:
a 1.695148
b 1.328614
c 1.234686
d -0.385845
e -1.326508
dtype: float64
In [207]: s.reindex(["e", "b", "f", "d"])
Out[207]:
e -1.326508
b 1.328614
f NaN
d -0.385845
dtype: float64
在这里, f
标签未包含在该系列中,因此显示为 NaN
在结果中。
使用DataFrame,您可以同时重新索引索引和列:
In [208]: df
Out[208]:
one two three
a 1.394981 1.772517 NaN
b 0.343054 1.912123 -0.050390
c 0.695246 1.478369 1.227435
d NaN 0.279344 -0.613172
In [209]: df.reindex(index=["c", "f", "b"], columns=["three", "two", "one"])
Out[209]:
three two one
c 1.227435 1.478369 0.695246
f NaN NaN NaN
b -0.050390 1.912123 0.343054
您也可以使用 reindex
vbl.用一种. axis
关键词:
In [210]: df.reindex(["c", "f", "b"], axis="index")
Out[210]:
one two three
c 0.695246 1.478369 1.227435
f NaN NaN NaN
b 0.343054 1.912123 -0.050390
请注意, Index
包含实际轴标签的对象可以是 共享 在对象之间。因此,如果我们有一个Series和一个DataFrame,则可以执行以下操作:
In [211]: rs = s.reindex(df.index)
In [212]: rs
Out[212]:
a 1.695148
b 1.328614
c 1.234686
d -0.385845
dtype: float64
In [213]: rs.index is df.index
Out[213]: True
这意味着重新编制索引的Series的索引与DataFrame的索引是同一个Python对象。
DataFrame.reindex()
还支持“轴式”调用约定,在该约定中指定单个 labels
论据和 axis
它适用于。
In [214]: df.reindex(["c", "f", "b"], axis="index")
Out[214]:
one two three
c 0.695246 1.478369 1.227435
f NaN NaN NaN
b 0.343054 1.912123 -0.050390
In [215]: df.reindex(["three", "two", "one"], axis="columns")
Out[215]:
three two one
a NaN 1.772517 1.394981
b -0.050390 1.912123 0.343054
c 1.227435 1.478369 0.695246
d -0.613172 0.279344 NaN
参见
MultiIndex / Advanced Indexing 是进行重新索引的一种更简洁的方式。
备注
在编写对性能敏感的代码时,有充分的理由花一些时间成为重新编制索引的忍者: many operations are faster on pre-aligned data 。在内部添加两个未对齐的DataFrame会触发重新索引步骤。对于探索性分析,您几乎不会注意到差异(因为 reindex
已经进行了大量优化),但当CPU周期很重要时,会显式地 reindex
这里和那里的通话可能会产生影响。
重新编制索引以与另一个对象对齐#
您可能希望获取一个对象并对其轴重新编制索引,以使其标签与另一个对象相同。虽然语法简单明了,但却很繁琐,这是一种非常常见的操作, reindex_like()
方法可以使这一过程变得更简单:
In [216]: df2
Out[216]:
one two
a 1.394981 1.772517
b 0.343054 1.912123
c 0.695246 1.478369
In [217]: df3
Out[217]:
one two
a 0.583888 0.051514
b -0.468040 0.191120
c -0.115848 -0.242634
In [218]: df.reindex_like(df2)
Out[218]:
one two
a 1.394981 1.772517
b 0.343054 1.912123
c 0.695246 1.478369
使用将对象彼此对齐 align
#
这个 align()
方法是同时对齐两个对象的最快方法。它支持一种 join
参数(与 joining and merging ):
join='outer'
:采用索引的并集(默认)
join='left'
:使用调用对象的索引
join='right'
:使用传递的对象的索引
join='inner'
:使索引相交
它返回一个包含两个已重新索引的Series的元组:
In [219]: s = pd.Series(np.random.randn(5), index=["a", "b", "c", "d", "e"])
In [220]: s1 = s[:4]
In [221]: s2 = s[1:]
In [222]: s1.align(s2)
Out[222]:
(a -0.186646
b -1.692424
c -0.303893
d -1.425662
e NaN
dtype: float64,
a NaN
b -1.692424
c -0.303893
d -1.425662
e 1.114285
dtype: float64)
In [223]: s1.align(s2, join="inner")
Out[223]:
(b -1.692424
c -0.303893
d -1.425662
dtype: float64,
b -1.692424
c -0.303893
d -1.425662
dtype: float64)
In [224]: s1.align(s2, join="left")
Out[224]:
(a -0.186646
b -1.692424
c -0.303893
d -1.425662
dtype: float64,
a NaN
b -1.692424
c -0.303893
d -1.425662
dtype: float64)
对于DataFrames,默认情况下,Join方法将同时应用于索引和列:
In [225]: df.align(df2, join="inner")
Out[225]:
( one two
a 1.394981 1.772517
b 0.343054 1.912123
c 0.695246 1.478369,
one two
a 1.394981 1.772517
b 0.343054 1.912123
c 0.695246 1.478369)
您还可以传递一个 axis
选项以仅与指定的轴对齐:
In [226]: df.align(df2, join="inner", axis=0)
Out[226]:
( one two three
a 1.394981 1.772517 NaN
b 0.343054 1.912123 -0.050390
c 0.695246 1.478369 1.227435,
one two
a 1.394981 1.772517
b 0.343054 1.912123
c 0.695246 1.478369)
如果将序列传递给 DataFrame.align()
属性,可以选择在DataFrame的索引或列上对齐这两个对象 axis
论点:
In [227]: df.align(df2.iloc[0], axis=1)
Out[227]:
( one three two
a 1.394981 NaN 1.772517
b 0.343054 -0.050390 1.912123
c 0.695246 1.227435 1.478369
d NaN -0.613172 0.279344,
one 1.394981
three NaN
two 1.772517
Name: a, dtype: float64)
重新编制索引时进行填充#
reindex()
接受可选参数 method
这是一种填充方法,选自下表:
方法 |
动作 |
---|---|
垫片/垫片 |
向前填充值 |
B填充/回填 |
向后填充值 |
最近的 |
从最接近的索引值填充 |
我们用一个简单的系列来说明这些填充方法:
In [228]: rng = pd.date_range("1/3/2000", periods=8)
In [229]: ts = pd.Series(np.random.randn(8), index=rng)
In [230]: ts2 = ts[[0, 3, 6]]
In [231]: ts
Out[231]:
2000-01-03 0.183051
2000-01-04 0.400528
2000-01-05 -0.015083
2000-01-06 2.395489
2000-01-07 1.414806
2000-01-08 0.118428
2000-01-09 0.733639
2000-01-10 -0.936077
Freq: D, dtype: float64
In [232]: ts2
Out[232]:
2000-01-03 0.183051
2000-01-06 2.395489
2000-01-09 0.733639
Freq: 3D, dtype: float64
In [233]: ts2.reindex(ts.index)
Out[233]:
2000-01-03 0.183051
2000-01-04 NaN
2000-01-05 NaN
2000-01-06 2.395489
2000-01-07 NaN
2000-01-08 NaN
2000-01-09 0.733639
2000-01-10 NaN
Freq: D, dtype: float64
In [234]: ts2.reindex(ts.index, method="ffill")
Out[234]:
2000-01-03 0.183051
2000-01-04 0.183051
2000-01-05 0.183051
2000-01-06 2.395489
2000-01-07 2.395489
2000-01-08 2.395489
2000-01-09 0.733639
2000-01-10 0.733639
Freq: D, dtype: float64
In [235]: ts2.reindex(ts.index, method="bfill")
Out[235]:
2000-01-03 0.183051
2000-01-04 2.395489
2000-01-05 2.395489
2000-01-06 2.395489
2000-01-07 0.733639
2000-01-08 0.733639
2000-01-09 0.733639
2000-01-10 NaN
Freq: D, dtype: float64
In [236]: ts2.reindex(ts.index, method="nearest")
Out[236]:
2000-01-03 0.183051
2000-01-04 0.183051
2000-01-05 2.395489
2000-01-06 2.395489
2000-01-07 2.395489
2000-01-08 0.733639
2000-01-09 0.733639
2000-01-10 0.733639
Freq: D, dtype: float64
这些方法要求索引是 有条不紊 增加的或减少的
请注意,同样的结果也可以通过使用 fillna (除 method='nearest'
)或 interpolate :
In [237]: ts2.reindex(ts.index).fillna(method="ffill")
Out[237]:
2000-01-03 0.183051
2000-01-04 0.183051
2000-01-05 0.183051
2000-01-06 2.395489
2000-01-07 2.395489
2000-01-08 2.395489
2000-01-09 0.733639
2000-01-10 0.733639
Freq: D, dtype: float64
reindex()
如果索引不是单调递增或递减,则将引发ValueError。 fillna()
和 interpolate()
不会对索引的顺序执行任何检查。
重建索引时对填充的限制#
这个 limit
和 tolerance
参数在重新编制索引时提供了对填充的额外控制。限制指定连续匹配的最大计数:
In [238]: ts2.reindex(ts.index, method="ffill", limit=1)
Out[238]:
2000-01-03 0.183051
2000-01-04 0.183051
2000-01-05 NaN
2000-01-06 2.395489
2000-01-07 2.395489
2000-01-08 NaN
2000-01-09 0.733639
2000-01-10 0.733639
Freq: D, dtype: float64
相比之下,公差指定了索引值和索引器值之间的最大距离:
In [239]: ts2.reindex(ts.index, method="ffill", tolerance="1 day")
Out[239]:
2000-01-03 0.183051
2000-01-04 0.183051
2000-01-05 NaN
2000-01-06 2.395489
2000-01-07 2.395489
2000-01-08 NaN
2000-01-09 0.733639
2000-01-10 0.733639
Freq: D, dtype: float64
请注意,当在 DatetimeIndex
, TimedeltaIndex
或 PeriodIndex
, tolerance
将被迫成为一名 Timedelta
如果可能的话。这允许您使用适当的字符串指定公差。
从轴上丢弃标签#
一种与之密切相关的方法 reindex
是不是 drop()
功能。它从轴上删除一组标签:
In [240]: df
Out[240]:
one two three
a 1.394981 1.772517 NaN
b 0.343054 1.912123 -0.050390
c 0.695246 1.478369 1.227435
d NaN 0.279344 -0.613172
In [241]: df.drop(["a", "d"], axis=0)
Out[241]:
one two three
b 0.343054 1.912123 -0.050390
c 0.695246 1.478369 1.227435
In [242]: df.drop(["one"], axis=1)
Out[242]:
two three
a 1.772517 NaN
b 1.912123 -0.050390
c 1.478369 1.227435
d 0.279344 -0.613172
请注意,以下方法也适用,但不太明显/干净:
In [243]: df.reindex(df.index.difference(["a", "d"]))
Out[243]:
one two three
b 0.343054 1.912123 -0.050390
c 0.695246 1.478369 1.227435
重命名/映射标签#
这个 rename()
方法允许您基于某些映射(DICT或系列)或任意函数重新标记轴。
In [244]: s
Out[244]:
a -0.186646
b -1.692424
c -0.303893
d -1.425662
e 1.114285
dtype: float64
In [245]: s.rename(str.upper)
Out[245]:
A -0.186646
B -1.692424
C -0.303893
D -1.425662
E 1.114285
dtype: float64
如果传递函数,则在使用任何标签调用该函数时,该函数必须返回值(并且必须生成一组唯一值)。也可以使用Dict或Series:
In [246]: df.rename(
.....: columns={"one": "foo", "two": "bar"},
.....: index={"a": "apple", "b": "banana", "d": "durian"},
.....: )
.....:
Out[246]:
foo bar three
apple 1.394981 1.772517 NaN
banana 0.343054 1.912123 -0.050390
c 0.695246 1.478369 1.227435
durian NaN 0.279344 -0.613172
如果映射不包括列/索引标签,则不会重命名。请注意,映射中的额外标签不会抛出错误。
DataFrame.rename()
还支持“轴式”调用约定,在该约定中指定单个 mapper
以及 axis
要将该映射应用于。
In [247]: df.rename({"one": "foo", "two": "bar"}, axis="columns")
Out[247]:
foo bar three
a 1.394981 1.772517 NaN
b 0.343054 1.912123 -0.050390
c 0.695246 1.478369 1.227435
d NaN 0.279344 -0.613172
In [248]: df.rename({"a": "apple", "b": "banana", "d": "durian"}, axis="index")
Out[248]:
one two three
apple 1.394981 1.772517 NaN
banana 0.343054 1.912123 -0.050390
c 0.695246 1.478369 1.227435
durian NaN 0.279344 -0.613172
这个 rename()
方法还提供了一个 inplace
默认情况下为的命名参数 False
并复制底层数据。经过 inplace=True
以就地重命名数据。
最后, rename()
还接受标量或类似列表的类型来更改 Series.name
属性。
In [249]: s.rename("scalar-name")
Out[249]:
a -0.186646
b -1.692424
c -0.303893
d -1.425662
e 1.114285
Name: scalar-name, dtype: float64
这些方法 DataFrame.rename_axis()
和 Series.rename_axis()
允许特定名称的 MultiIndex
要更改的(与标签相反)。
In [250]: df = pd.DataFrame(
.....: {"x": [1, 2, 3, 4, 5, 6], "y": [10, 20, 30, 40, 50, 60]},
.....: index=pd.MultiIndex.from_product(
.....: [["a", "b", "c"], [1, 2]], names=["let", "num"]
.....: ),
.....: )
.....:
In [251]: df
Out[251]:
x y
let num
a 1 1 10
2 2 20
b 1 3 30
2 4 40
c 1 5 50
2 6 60
In [252]: df.rename_axis(index={"let": "abc"})
Out[252]:
x y
abc num
a 1 1 10
2 2 20
b 1 3 30
2 4 40
c 1 5 50
2 6 60
In [253]: df.rename_axis(index=str.upper)
Out[253]:
x y
LET NUM
a 1 1 10
2 2 20
b 1 3 30
2 4 40
c 1 5 50
2 6 60
迭代法#
Pandas对象上的基本迭代的行为取决于类型。当迭代一个级数时,它被认为是类似数组的,基本迭代产生值。DataFrame遵循类似于字典的约定,迭代对象的“键”。
简而言之,基本迭代 (for i in object
)产生:
系列 :价值观
DataFrame :列标签
因此,例如,在DataFrame上迭代会得到列名:
In [254]: df = pd.DataFrame(
.....: {"col1": np.random.randn(3), "col2": np.random.randn(3)}, index=["a", "b", "c"]
.....: )
.....:
In [255]: for col in df:
.....: print(col)
.....:
col1
col2
Pandas的物体也有像字典一样的 items()
方法遍历(键、值)对。
要循环访问DataFrame的各行,可以使用以下方法:
iterrows()
:将DataFrame的各行作为(index,Series)对进行迭代。这会将行转换为Series对象,这可能会更改数据类型并影响一些性能。itertuples()
:作为值的命名元组迭代DataFrame的各行。这比以前快多了iterrows()
在大多数情况下,最好使用它来迭代DataFrame的值。
警告
循环访问Pandas对象通常是 slow 。在许多情况下,不需要手动迭代行,可以使用以下方法之一来避免:
寻找一个 矢量化 解决方案:许多操作可以使用内置方法或NumPy函数、(布尔)索引、...
当您的函数不能同时处理完整的DataFrame/Series时,最好使用
apply()
而不是遍历这些值。请参阅上的文档 function application 。如果您需要对值进行迭代操作,但性能很重要,请考虑使用cython或Numba编写内部循环。请参阅 enhancing performance 一节中提供了这种方法的一些示例。
警告
你应该 切勿修改 你正在迭代的东西。这并不能保证在所有情况下都有效。根据数据类型的不同,迭代器返回的是副本而不是视图,向其写入数据将没有任何效果!
例如,在以下情况下,设置该值不起作用:
In [256]: df = pd.DataFrame({"a": [1, 2, 3], "b": ["a", "b", "c"]})
In [257]: for index, row in df.iterrows():
.....: row["a"] = 10
.....:
In [258]: df
Out[258]:
a b
0 1 a
1 2 b
2 3 c
项目#
与字典一样的界面一致, items()
遍历键-值对:
系列 :(索引,标量值)对
DataFrame :(列,系列)对
例如:
In [259]: for label, ser in df.items():
.....: print(label)
.....: print(ser)
.....:
a
0 1
1 2
2 3
Name: a, dtype: int64
b
0 a
1 b
2 c
Name: b, dtype: object
迭代行#
iterrows()
允许您将DataFrame的各行作为Series对象进行迭代。它返回一个迭代器,该迭代器生成每个索引值以及包含每行数据的Series:
In [260]: for row_index, row in df.iterrows():
.....: print(row_index, row, sep="\n")
.....:
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()
为每一行返回一个系列, not 跨行保留数据类型(为DataFrame保留跨列的数据类型)。例如,
In [261]: df_orig = pd.DataFrame([[1, 1.5]], columns=["int", "float"])
In [262]: df_orig.dtypes
Out[262]:
int int64
float float64
dtype: object
In [263]: row = next(df_orig.iterrows())[1]
In [264]: row
Out[264]:
int 1.0
float 1.5
Name: 0, dtype: float64
中的所有值 row
,作为Series返回,现在向上转换为浮点数,也是Column中的原始整数值 x
:
In [265]: row["int"].dtype
Out[265]: dtype('float64')
In [266]: df_orig["int"].dtype
Out[266]: dtype('int64')
要在迭代行时保留数据类型,最好使用 itertuples()
它返回值的命名元组,并且通常比 iterrows()
。
例如,一种人为的转置DataFrame的方法是:
In [267]: df2 = pd.DataFrame({"x": [1, 2, 3], "y": [4, 5, 6]})
In [268]: print(df2)
x y
0 1 4
1 2 5
2 3 6
In [269]: print(df2.T)
0 1 2
x 1 2 3
y 4 5 6
In [270]: df2_t = pd.DataFrame({idx: values for idx, values in df2.iterrows()})
In [271]: print(df2_t)
0 1 2
x 1 2 3
y 4 5 6
迭代组#
这个 itertuples()
方法将返回一个迭代器,该迭代器为DataFrame中的每一行生成一个命名元组。元组的第一个元素将是该行的相应索引值,其余的值是行值。
例如:
In [272]: 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对象;它只返回命名元组中的值。所以呢, itertuples()
保留值的数据类型,通常更快,因为 iterrows()
。
备注
如果列名称是无效的、重复的或以下划线开头的,则列名称将重命名为位置名称。如果有大量的列(>255),则返回常规元组。
.dt访问器#
Series
具有一个访问器,用于简洁地返回 值 如果它是类似于系列的日期时间/期间,则返回。这将返回一个系列,其索引方式与现有系列相同。
# datetime
In [273]: s = pd.Series(pd.date_range("20130101 09:10:12", periods=4))
In [274]: s
Out[274]:
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 [275]: s.dt.hour
Out[275]:
0 9
1 9
2 9
3 9
dtype: int64
In [276]: s.dt.second
Out[276]:
0 12
1 12
2 12
3 12
dtype: int64
In [277]: s.dt.day
Out[277]:
0 1
1 2
2 3
3 4
dtype: int64
这样就可以使用下面这样的漂亮表达:
In [278]: s[s.dt.day == 2]
Out[278]:
1 2013-01-02 09:10:12
dtype: datetime64[ns]
您可以轻松地生成TZ感知的转换:
In [279]: stz = s.dt.tz_localize("US/Eastern")
In [280]: stz
Out[280]:
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 [281]: stz.dt.tz
Out[281]: <DstTzInfo 'US/Eastern' LMT-1 day, 19:04:00 STD>
您还可以链接以下类型的操作:
In [282]: s.dt.tz_localize("UTC").dt.tz_convert("US/Eastern")
Out[282]:
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]
还可以将日期时间值格式化为字符串 Series.dt.strftime()
支持与标准的格式相同的 strftime()
。
# DatetimeIndex
In [283]: s = pd.Series(pd.date_range("20130101", periods=4))
In [284]: s
Out[284]:
0 2013-01-01
1 2013-01-02
2 2013-01-03
3 2013-01-04
dtype: datetime64[ns]
In [285]: s.dt.strftime("%Y/%m/%d")
Out[285]:
0 2013/01/01
1 2013/01/02
2 2013/01/03
3 2013/01/04
dtype: object
# PeriodIndex
In [286]: s = pd.Series(pd.period_range("20130101", periods=4))
In [287]: s
Out[287]:
0 2013-01-01
1 2013-01-02
2 2013-01-03
3 2013-01-04
dtype: period[D]
In [288]: s.dt.strftime("%Y/%m/%d")
Out[288]:
0 2013/01/01
1 2013/01/02
2 2013/01/03
3 2013/01/04
dtype: object
这个 .dt
存取器适用于Period和TimeDelta数据类型。
# period
In [289]: s = pd.Series(pd.period_range("20130101", periods=4, freq="D"))
In [290]: s
Out[290]:
0 2013-01-01
1 2013-01-02
2 2013-01-03
3 2013-01-04
dtype: period[D]
In [291]: s.dt.year
Out[291]:
0 2013
1 2013
2 2013
3 2013
dtype: int64
In [292]: s.dt.day
Out[292]:
0 1
1 2
2 3
3 4
dtype: int64
# timedelta
In [293]: s = pd.Series(pd.timedelta_range("1 day 00:00:05", periods=4, freq="s"))
In [294]: s
Out[294]:
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 [295]: s.dt.days
Out[295]:
0 1
1 1
2 1
3 1
dtype: int64
In [296]: s.dt.seconds
Out[296]:
0 5
1 6
2 7
3 8
dtype: int64
In [297]: s.dt.components
Out[297]:
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
将引发一个 TypeError
如果您使用非类似DATETIME的值访问。
矢量化的字符串方法#
Series配备了一组字符串处理方法,使您可以轻松地对数组的每个元素进行操作。也许最重要的是,这些方法会自动排除丢失的/NA值。可通过该系列的 str
属性,并且通常具有与等效(标量)内置字符串方法匹配的名称。例如:
In [298]: s = pd.Series( .....: ["A", "B", "C", "Aaba", "Baca", np.nan, "CABA", "dog", "cat"], dtype="string" .....: ) .....: In [299]: s.str.lower() Out[299]: 0 a 1 b 2 c 3 aaba 4 baca 5 <NA> 6 caba 7 dog 8 cat dtype: string
还提供了强大的模式匹配方法,但请注意,模式匹配通常使用 regular expressions 默认情况下(在某些情况下总是使用它们)。
备注
在Pandas 1.0之前,字符串方法仅在 object
-dtype Series
。Pandas1.0增加了 StringDtype
它是专门用于字符串的。看见 文本数据类型 想要更多。
请看 Vectorized String Methods 获取完整的描述。
分选#
Pandas支持三种排序:按索引标签排序、按列值排序和按两者的组合排序。
按索引#
这个 Series.sort_index()
和 DataFrame.sort_index()
方法用于根据Pandas对象的索引级别对其进行排序。
In [300]: 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 [301]: unsorted_df = df.reindex(
.....: index=["a", "d", "c", "b"], columns=["three", "two", "one"]
.....: )
.....:
In [302]: unsorted_df
Out[302]:
three two one
a NaN -1.152244 0.562973
d -0.252916 -0.109597 NaN
c 1.273388 -0.167123 0.640382
b -0.098217 0.009797 -1.299504
# DataFrame
In [303]: unsorted_df.sort_index()
Out[303]:
three two one
a NaN -1.152244 0.562973
b -0.098217 0.009797 -1.299504
c 1.273388 -0.167123 0.640382
d -0.252916 -0.109597 NaN
In [304]: unsorted_df.sort_index(ascending=False)
Out[304]:
three two one
d -0.252916 -0.109597 NaN
c 1.273388 -0.167123 0.640382
b -0.098217 0.009797 -1.299504
a NaN -1.152244 0.562973
In [305]: unsorted_df.sort_index(axis=1)
Out[305]:
one three two
a 0.562973 NaN -1.152244
d NaN -0.252916 -0.109597
c 0.640382 1.273388 -0.167123
b -1.299504 -0.098217 0.009797
# Series
In [306]: unsorted_df["three"].sort_index()
Out[306]:
a NaN
b -0.098217
c 1.273388
d -0.252916
Name: three, dtype: float64
1.1.0 新版功能.
按索引排序还支持 key
参数,该参数接受要应用于要排序的索引的可调用函数。为 MultiIndex
对象,则按级别将该键应用于由 level
。
In [307]: s1 = pd.DataFrame({"a": ["B", "a", "C"], "b": [1, 2, 3], "c": [2, 3, 4]}).set_index(
.....: list("ab")
.....: )
.....:
In [308]: s1
Out[308]:
c
a b
B 1 2
a 2 3
C 3 4
In [309]: s1.sort_index(level="a")
Out[309]:
c
a b
B 1 2
C 3 4
a 2 3
In [310]: s1.sort_index(level="a", key=lambda idx: idx.str.lower())
Out[310]:
c
a b
a 2 3
B 1 2
C 3 4
有关按值进行键排序的信息,请参见 value sorting 。
按价值#
这个 Series.sort_values()
方法用于对 Series
通过它的价值。这个 DataFrame.sort_values()
方法用于对 DataFrame
按其列或行值。任选 by
参数设置为 DataFrame.sort_values()
可用于指定用于确定排序顺序的一个或多个列。
In [311]: df1 = pd.DataFrame(
.....: {"one": [2, 1, 1, 1], "two": [1, 3, 2, 4], "three": [5, 4, 3, 2]}
.....: )
.....:
In [312]: df1.sort_values(by="two")
Out[312]:
one two three
0 2 1 5
2 1 2 3
1 1 3 4
3 1 4 2
这个 by
参数可以接受列名的列表,例如:
In [313]: df1[["one", "two", "three"]].sort_values(by=["one", "two"])
Out[313]:
one two three
2 1 2 3
1 1 3 4
3 1 4 2
0 2 1 5
这些方法对NA值有特殊处理,通过 na_position
论点:
In [314]: s[2] = np.nan
In [315]: s.sort_values()
Out[315]:
0 A
3 Aaba
1 B
4 Baca
6 CABA
8 cat
7 dog
2 <NA>
5 <NA>
dtype: string
In [316]: s.sort_values(na_position="first")
Out[316]:
2 <NA>
5 <NA>
0 A
3 Aaba
1 B
4 Baca
6 CABA
8 cat
7 dog
dtype: string
1.1.0 新版功能.
排序还支持 key
参数,该参数接受要应用于正在排序的值的可调用函数。
In [317]: s1 = pd.Series(["B", "a", "C"])
In [318]: s1.sort_values()
Out[318]:
0 B
2 C
1 a
dtype: object
In [319]: s1.sort_values(key=lambda x: x.str.lower())
Out[319]:
1 a
0 B
2 C
dtype: object
key
将会被给予 Series
值的值,并应返回 Series
或具有转换后的值的相同形状的数组。为 DataFrame
对象,则键按列应用,因此键仍应为Series并返回Series,例如
In [320]: df = pd.DataFrame({"a": ["B", "a", "C"], "b": [1, 2, 3]})
In [321]: df.sort_values(by="a")
Out[321]:
a b
0 B 1
2 C 3
1 a 2
In [322]: df.sort_values(by="a", key=lambda col: col.str.lower())
Out[322]:
a b
1 a 2
0 B 1
2 C 3
每列的名称或类型可用于将不同的功能应用于不同的列。
按索引和值#
字符串作为 by
参数设置为 DataFrame.sort_values()
可以引用列或索引级名称。
# Build MultiIndex
In [323]: idx = pd.MultiIndex.from_tuples(
.....: [("a", 1), ("a", 2), ("a", 2), ("b", 2), ("b", 1), ("b", 1)]
.....: )
.....:
In [324]: idx.names = ["first", "second"]
# Build DataFrame
In [325]: df_multi = pd.DataFrame({"A": np.arange(6, 0, -1)}, index=idx)
In [326]: df_multi
Out[326]:
A
first second
a 1 6
2 5
2 4
b 2 3
1 2
1 1
按‘Second’(索引)和‘A’(列)排序
In [327]: df_multi.sort_values(by=["second", "A"])
Out[327]:
A
first second
b 1 1
1 2
a 1 6
b 2 3
a 2 4
2 5
备注
如果字符串同时匹配列名和索引级名称,则会发出警告,并且该列优先。这将在将来的版本中导致歧义错误。
搜索排序#
该系列拥有 searchsorted()
方法,其工作方式类似于 numpy.ndarray.searchsorted()
。
In [328]: ser = pd.Series([1, 2, 3])
In [329]: ser.searchsorted([0, 3])
Out[329]: array([0, 2])
In [330]: ser.searchsorted([0, 4])
Out[330]: array([0, 3])
In [331]: ser.searchsorted([1, 3], side="right")
Out[331]: array([1, 3])
In [332]: ser.searchsorted([1, 3], side="left")
Out[332]: array([0, 2])
In [333]: ser = pd.Series([3, 1, 2])
In [334]: ser.searchsorted([0, 3], sorter=np.argsort(ser))
Out[334]: array([0, 2])
最小/最大值#
Series
有没有 nsmallest()
和 nlargest()
方法返回最小或最大的 \(n\) 价值观。对于一个大的 Series
这比对整个系列进行排序并调用 head(n)
在结果上。
In [335]: s = pd.Series(np.random.permutation(10))
In [336]: s
Out[336]:
0 2
1 0
2 3
3 7
4 1
5 5
6 9
7 6
8 8
9 4
dtype: int64
In [337]: s.sort_values()
Out[337]:
1 0
4 1
0 2
2 3
9 4
5 5
7 6
3 7
8 8
6 9
dtype: int64
In [338]: s.nsmallest(3)
Out[338]:
1 0
4 1
0 2
dtype: int64
In [339]: s.nlargest(3)
Out[339]:
6 9
8 8
3 7
dtype: int64
DataFrame
也有 nlargest
和 nsmallest
方法。
In [340]: 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 [341]: df.nlargest(3, "a")
Out[341]:
a b c
5 11 f 3.0
3 10 c 3.2
4 8 e NaN
In [342]: df.nlargest(5, ["a", "c"])
Out[342]:
a b c
5 11 f 3.0
3 10 c 3.2
4 8 e NaN
2 1 d 4.0
6 -1 f 4.0
In [343]: df.nsmallest(3, "a")
Out[343]:
a b c
0 -2 a 1.0
1 -1 b 2.0
6 -1 f 4.0
In [344]: df.nsmallest(5, ["a", "c"])
Out[344]:
a b c
0 -2 a 1.0
1 -1 b 2.0
6 -1 f 4.0
2 1 d 4.0
4 8 e NaN
按多索引列排序#
当列是多索引时,必须明确进行排序,并充分指定所有级别以 by
。
In [345]: df1.columns = pd.MultiIndex.from_tuples(
.....: [("a", "one"), ("a", "two"), ("b", "three")]
.....: )
.....:
In [346]: df1.sort_values(by=("a", "two"))
Out[346]:
a b
one two three
0 2 1 5
2 1 2 3
1 1 3 4
3 1 4 2
临摹#
这个 copy()
方法复制底层数据(但不是轴索引,因为它们是不可变的)并返回一个新对象。请注意 很少需要复制对象 。例如,更改DataFrame的方法屈指可数 in-place :
插入、删除或修改列。
分配给
index
或columns
属性。对于同类数据,直接通过
values
属性或高级索引。
需要明确的是,任何PANDA方法都不会有修改数据的副作用;几乎每个方法都返回一个新对象,保持原始对象不变。如果数据被修改,那是因为您明确地这样做了。
数据类型#
在大多数情况下,Pandas对DataFrame的系列或单个列使用NumPy数组和数据类型。NumPy为 float
, int
, bool
, timedelta64[ns]
和 datetime64[ns]
(请注意,NumPy不支持时区感知的日期时间)。
Pandas和第三方类库 延伸 NumPy的类型系统在几个地方。这一部分描述了Pandas在内部所做的扩展。看见 扩展类型 关于如何编写您自己的与Pandas一起工作的扩展。看见 扩展模块数据类型 以获取已实现扩展的第三方库的列表。
下表列出了Pandas的所有扩展类型。对于需要 dtype
参数、字符串可以按指示指定。有关每种类型的更多信息,请参阅相应的文档部分。
数据类型 |
数据类型 |
标量 |
阵列 |
字符串别名 |
||
---|---|---|---|---|---|---|
|
||||||
(无) |
|
|||||
|
|
|||||
(无) |
|
|||||
|
||||||
|
(无) |
|
||||
|
||||||
|
Pandas有两种存储字符串的方法。
object
Dtype,它可以保存任何Python对象,包括字符串。StringDtype
,它专门用于字符串。
通常,我们建议使用 StringDtype
。看见 文本数据类型 想要更多。
最后,可以使用 object
Dtype,但应尽可能避免(为了性能和与其他库和方法的互操作性)。看见 对象转换 )。
一个方便的 dtypes
属性返回具有每列数据类型的Series。
In [347]: dft = pd.DataFrame(
.....: {
.....: "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 [348]: dft
Out[348]:
A B C D E F G
0 0.035962 1 foo 2001-01-02 1.0 False 1
1 0.701379 1 foo 2001-01-02 1.0 False 1
2 0.281885 1 foo 2001-01-02 1.0 False 1
In [349]: dft.dtypes
Out[349]:
A float64
B int64
C object
D datetime64[ns]
E float32
F bool
G int8
dtype: object
vt.在.上 Series
对象,请使用 dtype
属性。
In [350]: dft["A"].dtype
Out[350]: dtype('float64')
如果Pandas对象包含具有多种数据类型的数据 在单列中 ,将选择列的数据类型以适应所有数据类型 (object
是最普遍的)。
# these ints are coerced to floats
In [351]: pd.Series([1, 2, 3, 4, 5, 6.0])
Out[351]:
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 [352]: pd.Series([1, 2, 3, 6.0, "foo"])
Out[352]:
0 1
1 2
2 3
3 6.0
4 foo
dtype: object
中每种类型的列数。 DataFrame
可以通过调用 DataFrame.dtypes.value_counts()
。
In [353]: dft.dtypes.value_counts()
Out[353]:
float64 1
int64 1
object 1
datetime64[ns] 1
float32 1
bool 1
int8 1
dtype: int64
数值数据类型将传播并可以在DataFrame中共存。如果传递数据类型(直接通过 dtype
关键字,传递的 ndarray
,或及格 Series
),则它将在DataFrame操作中保留。此外,不同的数字数据类型将 NOT 结合在一起。下面的例子会让你尝一尝。
In [354]: df1 = pd.DataFrame(np.random.randn(8, 1), columns=["A"], dtype="float32")
In [355]: df1
Out[355]:
A
0 0.224364
1 1.890546
2 0.182879
3 0.787847
4 -0.188449
5 0.667715
6 -0.011736
7 -0.399073
In [356]: df1.dtypes
Out[356]:
A float32
dtype: object
In [357]: df2 = pd.DataFrame(
.....: {
.....: "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 [358]: df2
Out[358]:
A B C
0 0.823242 0.256090 0
1 1.607422 1.426469 0
2 -0.333740 -0.416203 255
3 -0.063477 1.139976 0
4 -1.014648 -1.193477 0
5 0.678711 0.096706 0
6 -0.040863 -1.956850 1
7 -0.357422 -0.714337 0
In [359]: df2.dtypes
Out[359]:
A float16
B float64
C uint8
dtype: object
默认值#
默认情况下,整数类型为 int64
和浮点类型为 float64
, 不管怎样 平台(32位或64位)。以下所有结果都将导致 int64
数据类型。
In [360]: pd.DataFrame([1, 2], columns=["a"]).dtypes
Out[360]:
a int64
dtype: object
In [361]: pd.DataFrame({"a": [1, 2]}).dtypes
Out[361]:
a int64
dtype: object
In [362]: pd.DataFrame({"a": 1}, index=list(range(2))).dtypes
Out[362]:
a int64
dtype: object
请注意,Numpy将选择 platform-dependent 创建数组时的类型。以下是 WILL 结果 int32
在32位平台上。
In [363]: frame = pd.DataFrame(np.array([1, 2]))
向上投射#
类型可能是 升级 当与其他类型组合时,意味着它们从当前类型升级(例如 int
至 float
)。
In [364]: df3 = df1.reindex_like(df2).fillna(value=0.0) + df2
In [365]: df3
Out[365]:
A B C
0 1.047606 0.256090 0.0
1 3.497968 1.426469 0.0
2 -0.150862 -0.416203 255.0
3 0.724370 1.139976 0.0
4 -1.203098 -1.193477 0.0
5 1.346426 0.096706 0.0
6 -0.052599 -1.956850 1.0
7 -0.756495 -0.714337 0.0
In [366]: df3.dtypes
Out[366]:
A float32
B float64
C float64
dtype: object
DataFrame.to_numpy()
将返回 lower-common-denominator 数据类型中的一种,这意味着可以容纳 ALL 生成的同构dtype NumPy数组中的类型的。这可能会迫使一些人 向上投射 。
In [367]: df3.to_numpy().dtype
Out[367]: dtype('float64')
Astype#
您可以使用 astype()
方法将数据类型从一种显式转换为另一种。默认情况下,即使数据类型未更改(PASS),它们也会返回一个副本 copy=False
来改变这一行为)。此外,如果astype操作无效,它们将引发异常。
向上投射总是根据 NumPy 规矩。如果一个操作涉及两种不同的数据类型,则越多 一般 其中一个将用作操作的结果。
In [368]: df3
Out[368]:
A B C
0 1.047606 0.256090 0.0
1 3.497968 1.426469 0.0
2 -0.150862 -0.416203 255.0
3 0.724370 1.139976 0.0
4 -1.203098 -1.193477 0.0
5 1.346426 0.096706 0.0
6 -0.052599 -1.956850 1.0
7 -0.756495 -0.714337 0.0
In [369]: df3.dtypes
Out[369]:
A float32
B float64
C float64
dtype: object
# conversion of dtypes
In [370]: df3.astype("float32").dtypes
Out[370]:
A float32
B float32
C float32
dtype: object
使用将列的子集转换为指定类型 astype()
。
In [371]: dft = pd.DataFrame({"a": [1, 2, 3], "b": [4, 5, 6], "c": [7, 8, 9]})
In [372]: dft[["a", "b"]] = dft[["a", "b"]].astype(np.uint8)
In [373]: dft
Out[373]:
a b c
0 1 4 7
1 2 5 8
2 3 6 9
In [374]: dft.dtypes
Out[374]:
a uint8
b uint8
c int64
dtype: object
通过将dict传递给 astype()
。
In [375]: dft1 = pd.DataFrame({"a": [1, 0, 1], "b": [4, 5, 6], "c": [7, 8, 9]})
In [376]: dft1 = dft1.astype({"a": np.bool_, "c": np.float64})
In [377]: dft1
Out[377]:
a b c
0 True 4 7.0
1 False 5 8.0
2 True 6 9.0
In [378]: dft1.dtypes
Out[378]:
a bool
b int64
c float64
dtype: object
备注
在尝试将列的子集转换为指定类型时 astype()
和 loc()
,则会发生向上预测。
loc()
尝试适应我们分配给当前dtype的内容,而 []
将覆盖它们,从右侧获取数据类型。因此,下面的代码会产生意想不到的结果。
In [379]: dft = pd.DataFrame({"a": [1, 2, 3], "b": [4, 5, 6], "c": [7, 8, 9]})
In [380]: dft.loc[:, ["a", "b"]].astype(np.uint8).dtypes
Out[380]:
a uint8
b uint8
dtype: object
In [381]: dft.loc[:, ["a", "b"]] = dft.loc[:, ["a", "b"]].astype(np.uint8)
In [382]: dft.dtypes
Out[382]:
a int64
b int64
c int64
dtype: object
对象转换#
Pandas提供了各种函数,以尝试强制从 object
数据类型转换为其他类型。如果数据已经是正确类型,但存储在 object
数组,则 DataFrame.infer_objects()
和 Series.infer_objects()
方法可用于软转换为正确的类型。
In [383]: import datetime In [384]: df = pd.DataFrame( .....: [ .....: [1, 2], .....: ["a", "b"], .....: [datetime.datetime(2016, 3, 2), datetime.datetime(2016, 3, 2)], .....: ] .....: ) .....: In [385]: df = df.T In [386]: df Out[386]: 0 1 2 0 1 a 2016-03-02 1 2 b 2016-03-02 In [387]: df.dtypes Out[387]: 0 object 1 object 2 datetime64[ns] dtype: object
因为数据被调换,所以原始推理将所有列存储为对象,该对象 infer_objects
会改正的。
In [388]: df.infer_objects().dtypes Out[388]: 0 int64 1 object 2 datetime64[ns] dtype: object
以下函数可用于一维对象数组或标量,以执行对象到指定类型的硬转换:
to_numeric()
(转换为数字数据类型)In [389]: m = ["1.1", 2, 3] In [390]: pd.to_numeric(m) Out[390]: array([1.1, 2. , 3. ])
to_datetime()
(转换为DateTime对象)In [391]: import datetime In [392]: m = ["2016-07-09", datetime.datetime(2016, 3, 2)] In [393]: pd.to_datetime(m) Out[393]: DatetimeIndex(['2016-07-09', '2016-03-02'], dtype='datetime64[ns]', freq=None)
to_timedelta()
(转换为时间增量对象)In [394]: m = ["5us", pd.Timedelta("1day")] In [395]: pd.to_timedelta(m) Out[395]: TimedeltaIndex(['0 days 00:00:00.000005', '1 days 00:00:00'], dtype='timedelta64[ns]', freq=None)
要强制转换,我们可以传入一个 errors
参数,该参数指定Pandas应如何处理无法转换为所需数据类型或对象的元素。默认情况下, errors='raise'
这意味着在转换过程中将引发遇到的任何错误。但是,如果 errors='coerce'
,这些错误将被忽略,Pandas会将有问题的元素转换为 pd.NaT
(用于日期时间和时间增量)或 np.nan
(表示数字)。如果您正在读取的数据主要是所需的数据类型(例如,NUMERIC、DATETIME),但偶尔会有不一致的元素混合在一起,您希望将其表示为缺失,则这可能很有用:
In [396]: import datetime
In [397]: m = ["apple", datetime.datetime(2016, 3, 2)]
In [398]: pd.to_datetime(m, errors="coerce")
Out[398]: DatetimeIndex(['NaT', '2016-03-02'], dtype='datetime64[ns]', freq=None)
In [399]: m = ["apple", 2, 3]
In [400]: pd.to_numeric(m, errors="coerce")
Out[400]: array([nan, 2., 3.])
In [401]: m = ["apple", pd.Timedelta("1day")]
In [402]: pd.to_timedelta(m, errors="coerce")
Out[402]: TimedeltaIndex([NaT, '1 days'], dtype='timedelta64[ns]', freq=None)
这个 errors
参数有第三个选项,即 errors='ignore'
,如果在转换为所需的数据类型时遇到任何错误,它将只返回传入的数据:
In [403]: import datetime
In [404]: m = ["apple", datetime.datetime(2016, 3, 2)]
In [405]: pd.to_datetime(m, errors="ignore")
Out[405]: Index(['apple', 2016-03-02 00:00:00], dtype='object')
In [406]: m = ["apple", 2, 3]
In [407]: pd.to_numeric(m, errors="ignore")
Out[407]: array(['apple', 2, 3], dtype=object)
In [408]: m = ["apple", pd.Timedelta("1day")]
In [409]: pd.to_timedelta(m, errors="ignore")
Out[409]: array(['apple', Timedelta('1 days 00:00:00')], dtype=object)
除了对象转换之外, to_numeric()
提供了另一个论点 downcast
,这提供了将新的(或已经)的数字数据向下转换为更小的数据类型的选项,这可以节省内存:
In [410]: m = ["1", 2, 3]
In [411]: pd.to_numeric(m, downcast="integer") # smallest signed int dtype
Out[411]: array([1, 2, 3], dtype=int8)
In [412]: pd.to_numeric(m, downcast="signed") # same as 'integer'
Out[412]: array([1, 2, 3], dtype=int8)
In [413]: pd.to_numeric(m, downcast="unsigned") # smallest unsigned int dtype
Out[413]: array([1, 2, 3], dtype=uint8)
In [414]: pd.to_numeric(m, downcast="float") # smallest float dtype
Out[414]: array([1., 2., 3.], dtype=float32)
由于这些方法仅适用于一维数组、列表或标量,因此它们不能直接用于多维对象(如DataFrame)。但是,有了 apply()
,我们可以在每一列上高效地“应用”该函数:
In [415]: import datetime
In [416]: df = pd.DataFrame([["2016-07-09", datetime.datetime(2016, 3, 2)]] * 2, dtype="O")
In [417]: df
Out[417]:
0 1
0 2016-07-09 2016-03-02 00:00:00
1 2016-07-09 2016-03-02 00:00:00
In [418]: df.apply(pd.to_datetime)
Out[418]:
0 1
0 2016-07-09 2016-03-02
1 2016-07-09 2016-03-02
In [419]: df = pd.DataFrame([["1.1", 2, 3]] * 2, dtype="O")
In [420]: df
Out[420]:
0 1 2
0 1.1 2 3
1 1.1 2 3
In [421]: df.apply(pd.to_numeric)
Out[421]:
0 1 2
0 1.1 2 3
1 1.1 2 3
In [422]: df = pd.DataFrame([["5us", pd.Timedelta("1day")]] * 2, dtype="O")
In [423]: df
Out[423]:
0 1
0 5us 1 days 00:00:00
1 5us 1 days 00:00:00
In [424]: df.apply(pd.to_timedelta)
Out[424]:
0 1
0 0 days 00:00:00.000005 1 days
1 0 days 00:00:00.000005 1 days
我明白了#
在上执行选择操作 integer
类型数据可以很容易地将数据向上转换为 floating
。在以下情况下,将保留输入数据的数据类型 nans
都没有被介绍。另请参阅 Support for integer NA 。
In [425]: dfi = df3.astype("int32")
In [426]: dfi["E"] = 1
In [427]: dfi
Out[427]:
A B C E
0 1 0 0 1
1 3 1 0 1
2 0 0 255 1
3 0 1 0 1
4 -1 -1 0 1
5 1 0 0 1
6 0 -1 1 1
7 0 0 0 1
In [428]: dfi.dtypes
Out[428]:
A int32
B int32
C int32
E int64
dtype: object
In [429]: casted = dfi[dfi > 0]
In [430]: casted
Out[430]:
A B C E
0 1.0 NaN NaN 1
1 3.0 1.0 NaN 1
2 NaN NaN 255.0 1
3 NaN 1.0 NaN 1
4 NaN NaN NaN 1
5 1.0 NaN NaN 1
6 NaN NaN 1.0 1
7 NaN NaN NaN 1
In [431]: casted.dtypes
Out[431]:
A float64
B float64
C float64
E int64
dtype: object
而浮点数据类型保持不变。
In [432]: dfa = df3.copy()
In [433]: dfa["A"] = dfa["A"].astype("float32")
In [434]: dfa.dtypes
Out[434]:
A float32
B float64
C float64
dtype: object
In [435]: casted = dfa[df2 > 0]
In [436]: casted
Out[436]:
A B C
0 1.047606 0.256090 NaN
1 3.497968 1.426469 NaN
2 NaN NaN 255.0
3 NaN 1.139976 NaN
4 NaN NaN NaN
5 1.346426 0.096706 NaN
6 NaN NaN 1.0
7 NaN NaN NaN
In [437]: casted.dtypes
Out[437]:
A float32
B float64
C float64
dtype: object
根据以下条件选择列 dtype
#
这个 select_dtypes()
方法实现列的子集。 dtype
。
首先,让我们创建一个 DataFrame
具有多种不同的数据类型:
In [438]: 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),
.....: "category": pd.Series(list("ABC")).astype("category"),
.....: }
.....: )
.....:
In [439]: df["tdeltas"] = df.dates.diff()
In [440]: df["uint64"] = np.arange(3, 6).astype("u8")
In [441]: df["other_dates"] = pd.date_range("20130101", periods=3)
In [442]: df["tz_aware_dates"] = pd.date_range("20130101", periods=3, tz="US/Eastern")
In [443]: df
Out[443]:
string int64 uint8 float64 bool1 bool2 dates category tdeltas uint64 other_dates tz_aware_dates
0 a 1 3 4.0 True False 2022-05-08 15:37:19.561532 A NaT 3 2013-01-01 2013-01-01 00:00:00-05:00
1 b 2 4 5.0 False True 2022-05-09 15:37:19.561532 B 1 days 4 2013-01-02 2013-01-02 00:00:00-05:00
2 c 3 5 6.0 True False 2022-05-10 15:37:19.561532 C 1 days 5 2013-01-03 2013-01-03 00:00:00-05:00
和数据类型:
In [444]: df.dtypes
Out[444]:
string object
int64 int64
uint8 uint8
float64 float64
bool1 bool
bool2 bool
dates datetime64[ns]
category category
tdeltas timedelta64[ns]
uint64 uint64
other_dates datetime64[ns]
tz_aware_dates datetime64[ns, US/Eastern]
dtype: object
select_dtypes()
有两个参数 include
和 exclude
让你说“把柱子给我” with 这些数据类型“ (include
)和/或“将栏目 没有 这些数据类型“ (exclude
)。
例如,要选择 bool
列:
In [445]: df.select_dtypes(include=[bool])
Out[445]:
bool1 bool2
0 True False
1 False True
2 True False
方法中传递数据类型的名称。 NumPy dtype hierarchy :
In [446]: df.select_dtypes(include=["bool"])
Out[446]:
bool1 bool2
0 True False
1 False True
2 True False
select_dtypes()
也可以与泛型数据类型一起使用。
例如,要选择所有数值列和布尔列,但不包括无符号整数:
In [447]: df.select_dtypes(include=["number", "bool"], exclude=["unsignedinteger"])
Out[447]:
int64 float64 bool1 bool2 tdeltas
0 1 4.0 True False NaT
1 2 5.0 False True 1 days
2 3 6.0 True False 1 days
若要选择字符串列,必须使用 object
数据类型:
In [448]: df.select_dtypes(include=["object"])
Out[448]:
string
0 a
1 b
2 c
查看泛型的所有子数据类型 dtype
喜欢 numpy.number
您可以定义返回子数据类型树的函数:
In [449]: def subdtypes(dtype):
.....: subs = dtype.__subclasses__()
.....: if not subs:
.....: return dtype
.....: return [dtype, [subdtypes(dt) for dt in subs]]
.....:
所有NumPy数据类型都是 numpy.generic
:
In [450]: subdtypes(np.generic)
Out[450]:
[numpy.generic,
[[numpy.number,
[[numpy.integer,
[[numpy.signedinteger,
[numpy.int8,
numpy.int16,
numpy.int32,
numpy.int64,
numpy.longlong,
numpy.timedelta64]],
[numpy.unsignedinteger,
[numpy.uint8,
numpy.uint16,
numpy.uint32,
numpy.uint64,
numpy.ulonglong]]]],
[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.bytes_, numpy.str_]],
[numpy.void, [numpy.record]]]],
numpy.bool_,
numpy.datetime64,
numpy.object_]]
备注
Pandas也定义了这些类型 category
,以及 datetime64[ns, tz]
,它们没有集成到正常的NumPy层次结构中,并且不会显示在上面的函数中。