基本基本功能#

在这里,我们将讨论许多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物品 (IndexSeriesDataFrame )可以被视为数组的容器,它保存实际数据并进行实际计算。对于许多类型,基础数组是 numpy.ndarray 。但是,Pandas和第三方类库可能 延伸 NumPy的类型系统以添加对自定义数组的支持(请参见 数据类型 )。

若要在 IndexSeries ,请使用 .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])

当系列或索引由 ExtensionArrayto_numpy() 可能涉及复制数据和强制取值。看见 数据类型 想要更多。

to_numpy() 在一定程度上控制了 dtype 由此产生的 numpy.ndarray 。例如,考虑使用时区的DateTime。NumPy没有数据类型来表示时区感知的日期时间,因此有两种可能有用的表示:

  1. 一种对象数据类型 numpy.ndarray 使用 Timestamp 对象,每个对象都具有正确的 tz

  2. A datetime64[ns] -dtype numpy.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.valuesDataFrame.values 用于从Series或DataFrame中提取数据。您仍然可以在旧的代码库和在线上找到对这些代码的引用。展望未来,我们建议避免 .values 并使用 .array.to_numpy().values 有以下缺点:

  1. 当您的系列包含 extension type ,目前还不清楚 Series.values 返回NumPy数组或扩展数组。 Series.array 将始终返回一个 ExtensionArray ,并且永远不会复制数据。 Series.to_numpy() 将始终返回NumPy数组,可能会以复制/强制取值为代价。

  2. 当DataFrame包含混合数据类型时, DataFrame.values 可能涉及复制数据并将值强制转换为公共数据类型,这是一种相对昂贵的操作。 DataFrame.to_numpy() 作为一种方法,使得返回的NumPy数组不能是DataFrame中相同数据的视图。

加速运营#

类支持加速某些类型的二进制数值和布尔运算。 numexpr 库和 bottleneck 类库。

这些库在处理大型数据集时特别有用,并提供了很大的加速比。 numexpr 使用智能分块、缓存和多核。 bottleneck 是一组专门的cython例程,在处理具有 nans

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

运营

0.11.0(毫秒)

早期版本(毫秒)

与之前的比率

df1 > df2

13.32

125.35

0.1063

df1 * df2

21.71

36.63

0.5928

df1 + df2

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有二进制比较方法 eqneltgtle ,以及 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

布尔约简#

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

试着比较 IndexSeries 不同长度的对象将引发ValueError:

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

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

请注意,这与NumPy行为不同,在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

描述性统计#

存在大量用于计算描述性统计和其他相关操作的方法 SeriesDataFrame 。其中大多数是聚合(从而产生较低维度的结果),如 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

功能

描述

count

非北美观察值的数目

sum

价值总和

mean

价值平均数

mad

平均绝对偏差

median

数值的算术中位数

min

最低要求

max

极大值

mode

abs

绝对值

prod

价值的乘积

std

贝塞尔校正样本标准差

var

无偏方差

sem

平均值的标准误差

skew

样本偏斜度(3阶矩)

kurt

样本峰度(第四个时刻)

quantile

样本分位数(%处的值)

cumsum

累计和

cumprod

累计乘积

cummax

累计最大值

cummin

累计最小值

请注意,一些NumPy方法,如 meanstd ,以及 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'

备注

idxminidxmax 被称为 argminargmax 在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对象,您应该知道下面的三种方法。要使用的适当方法取决于您的函数是否期望对整个 DataFrameSeries 、行或列方式或元素方式。

  1. Tablewise Function Application: pipe()

  2. Row or Column-wise Function Application: apply()

  3. Aggregation API: agg() and transform()

  4. Applying Elementwise Functions: applymap()

逐表函数应用#

DataFramesSeries 可以传递到函数中。但是,如果需要在链中调用该函数,请考虑使用 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_nameadd_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_nameadd_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管道和最近的 dplyrmagrittr, 推出了广受欢迎的 (%>%) (读取管道)运算符 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 ,它接受三个选项: reducebroadcast ,以及 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() 不会对索引的顺序执行任何检查。

重建索引时对填充的限制#

这个 limittolerance 参数在重新编制索引时提供了对填充的额外控制。限制指定连续匹配的最大计数:

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

请注意,当在 DatetimeIndexTimedeltaIndexPeriodIndextolerance 将被迫成为一名 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 也有 nlargestnsmallest 方法。

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

  • 插入、删除或修改列。

  • 分配给 indexcolumns 属性。

  • 对于同类数据,直接通过 values 属性或高级索引。

需要明确的是,任何PANDA方法都不会有修改数据的副作用;几乎每个方法都返回一个新对象,保持原始对象不变。如果数据被修改,那是因为您明确地这样做了。

数据类型#

在大多数情况下,Pandas对DataFrame的系列或单个列使用NumPy数组和数据类型。NumPy为 floatintbooltimedelta64[ns]datetime64[ns] (请注意,NumPy不支持时区感知的日期时间)。

Pandas和第三方类库 延伸 NumPy的类型系统在几个地方。这一部分描述了Pandas在内部所做的扩展。看见 扩展类型 关于如何编写您自己的与Pandas一起工作的扩展。看见 扩展模块数据类型 以获取已实现扩展的第三方库的列表。

下表列出了Pandas的所有扩展类型。对于需要 dtype 参数、字符串可以按指示指定。有关每种类型的更多信息,请参阅相应的文档部分。

数据类型

数据类型

标量

阵列

字符串别名

tz-aware datetime

DatetimeTZDtype

Timestamp

arrays.DatetimeArray

'datetime64[ns, <tz>]'

Categorical

CategoricalDtype

(无)

Categorical

'category'

period (time spans)

PeriodDtype

Period

arrays.PeriodArray 'Period[<freq>]'

'period[<freq>]'

sparse

SparseDtype

(无)

arrays.SparseArray

'Sparse', 'Sparse[int]', 'Sparse[float]'

intervals

IntervalDtype

Interval

arrays.IntervalArray

'interval', 'Interval', 'Interval[<numpy_dtype>]', 'Interval[datetime64[ns, <tz>]]', 'Interval[timedelta64[<freq>]]'

nullable integer

Int64Dtype ..

(无)

arrays.IntegerArray

'Int8', 'Int16', 'Int32', 'Int64', 'UInt8', 'UInt16', 'UInt32', 'UInt64'

Strings

StringDtype

str

arrays.StringArray

'string'

Boolean (with NA)

BooleanDtype

bool

arrays.BooleanArray

'boolean'

Pandas有两种存储字符串的方法。

  1. object Dtype,它可以保存任何Python对象,包括字符串。

  2. 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]))

向上投射#

类型可能是 升级 当与其他类型组合时,意味着它们从当前类型升级(例如 intfloat )。

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() 有两个参数 includeexclude 让你说“把柱子给我” 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层次结构中,并且不会显示在上面的函数中。