Pandas 2.2 中文官方教程和指南(九·一)(4)

简介: Pandas 2.2 中文官方教程和指南(九·一)

Pandas 2.2 中文官方教程和指南(九·一)(3)https://developer.aliyun.com/article/1509697

默认值

默认情况下,整数类型为int64,浮点类型为float64不受平台(32 位或 64 位)影响。以下都将导致int64数据类型。

In [359]: pd.DataFrame([1, 2], columns=["a"]).dtypes
Out[359]: 
a    int64
dtype: object
In [360]: pd.DataFrame({"a": [1, 2]}).dtypes
Out[360]: 
a    int64
dtype: object
In [361]: pd.DataFrame({"a": 1}, index=list(range(2))).dtypes
Out[361]: 
a    int64
dtype: object 

请注意,当创建数组时,Numpy 将选择依赖于平台的类型。在 32 位平台上,以下导致int32

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

向上转换

当与其他类型组合时,类型可能会被向上转换,这意味着它们从当前类型(例如intfloat)提升。

In [363]: df3 = df1.reindex_like(df2).fillna(value=0.0) + df2
In [364]: df3
Out[364]: 
 A         B      C
0  1.047606  0.256090   26.0
1  3.497968  1.426469   86.0
2 -0.150862 -0.416203   46.0
3  0.724370  1.139976  212.0
4 -1.203098 -1.193477   26.0
5  1.346426  0.096706    7.0
6 -0.052599 -1.956850  184.0
7 -0.756495 -0.714337  206.0
In [365]: df3.dtypes
Out[365]: 
A    float32
B    float64
C    float64
dtype: object 

DataFrame.to_numpy()将返回数据类型的最低公共分母,即可以容纳结果同类数据类型的 NumPy 数组。这可能会强制进行一些向上转换

In [366]: df3.to_numpy().dtype
Out[366]: dtype('float64')

astype

您可以使用astype()方法将数据类型明确转换为另一种。默认情况下,即使数据类型未更改(通过传递copy=False来更改此行为),它们也将返回一个副本。此外,如果 astype 操作无效,它们将引发异常。

向上转换始终遵循NumPy规则。如果操作涉及两种不同的数据类型,则将使用更通用的数据类型作为操作的结果。

In [367]: df3
Out[367]: 
 A         B      C
0  1.047606  0.256090   26.0
1  3.497968  1.426469   86.0
2 -0.150862 -0.416203   46.0
3  0.724370  1.139976  212.0
4 -1.203098 -1.193477   26.0
5  1.346426  0.096706    7.0
6 -0.052599 -1.956850  184.0
7 -0.756495 -0.714337  206.0
In [368]: df3.dtypes
Out[368]: 
A    float32
B    float64
C    float64
dtype: object
# conversion of dtypes
In [369]: df3.astype("float32").dtypes
Out[369]: 
A    float32
B    float32
C    float32
dtype: object 

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

In [370]: dft = pd.DataFrame({"a": [1, 2, 3], "b": [4, 5, 6], "c": [7, 8, 9]})
In [371]: dft[["a", "b"]] = dft[["a", "b"]].astype(np.uint8)
In [372]: dft
Out[372]: 
 a  b  c
0  1  4  7
1  2  5  8
2  3  6  9
In [373]: dft.dtypes
Out[373]: 
a    uint8
b    uint8
c    int64
dtype: object 

通过将字典传递给astype()将某些列转换为特定数据类型。

In [374]: dft1 = pd.DataFrame({"a": [1, 0, 1], "b": [4, 5, 6], "c": [7, 8, 9]})
In [375]: dft1 = dft1.astype({"a": np.bool_, "c": np.float64})
In [376]: dft1
Out[376]: 
 a  b    c
0   True  4  7.0
1  False  5  8.0
2   True  6  9.0
In [377]: dft1.dtypes
Out[377]: 
a       bool
b      int64
c    float64
dtype: object 

注意

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

loc()尝试适应我们分配给当前数据类型的内容,而[]将覆盖它们,从右侧获取数据类型。因此,以下代码片段会产生意外结果。

In [378]: dft = pd.DataFrame({"a": [1, 2, 3], "b": [4, 5, 6], "c": [7, 8, 9]})
In [379]: dft.loc[:, ["a", "b"]].astype(np.uint8).dtypes
Out[379]: 
a    uint8
b    uint8
dtype: object
In [380]: dft.loc[:, ["a", "b"]] = dft.loc[:, ["a", "b"]].astype(np.uint8)
In [381]: dft.dtypes
Out[381]: 
a    int64
b    int64
c    int64
dtype: object 

对象转换

pandas 提供了各种函数来尝试将object数据类型转换为其他类型。在数据已经是正确类型但存储在object数组中的情况下,可以使用DataFrame.infer_objects()Series.infer_objects()方法进行软转换为正确类型。

In [382]: import datetime
In [383]: df = pd.DataFrame(
 .....:    [
 .....:        [1, 2],
 .....:        ["a", "b"],
 .....:        [datetime.datetime(2016, 3, 2), datetime.datetime(2016, 3, 2)],
 .....:    ]
 .....: )
 .....: 
In [384]: df = df.T
In [385]: df
Out[385]: 
 0  1                    2
0  1  a  2016-03-02 00:00:00
1  2  b  2016-03-02 00:00:00
In [386]: df.dtypes
Out[386]: 
0    object
1    object
2    object
dtype: object 

由于数据被转置,原始推断将所有列存储为对象,infer_objects将进行更正。

In [387]: df.infer_objects().dtypes
Out[387]: 
0             int64
1            object
2    datetime64[ns]
dtype: object 

以下函数适用于一维对象数组或标量,以执行将对象硬转换为指定类型的操作:

  • to_numeric()(转换为数值数据类型)
In [388]: m = ["1.1", 2, 3]
In [389]: pd.to_numeric(m)
Out[389]: array([1.1, 2\. , 3\. ]) 
  • to_datetime()(转换为日期时间对象)
In [390]: import datetime
In [391]: m = ["2016-07-09", datetime.datetime(2016, 3, 2)]
In [392]: pd.to_datetime(m)
Out[392]: DatetimeIndex(['2016-07-09', '2016-03-02'], dtype='datetime64[ns]', freq=None) 
  • to_timedelta()(转换为时间间隔对象)
In [393]: m = ["5us", pd.Timedelta("1day")]
In [394]: pd.to_timedelta(m)
Out[394]: 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(对于数值)。如果您正在读取大部分是所需数据类型(例如数值、日期时间)的数据,但偶尔混有不符合规范的元素,您希望将其表示为缺失值,则这可能很有用:

In [395]: import datetime
In [396]: m = ["apple", datetime.datetime(2016, 3, 2)]
In [397]: pd.to_datetime(m, errors="coerce")
Out[397]: DatetimeIndex(['NaT', '2016-03-02'], dtype='datetime64[ns]', freq=None)
In [398]: m = ["apple", 2, 3]
In [399]: pd.to_numeric(m, errors="coerce")
Out[399]: array([nan,  2.,  3.])
In [400]: m = ["apple", pd.Timedelta("1day")]
In [401]: pd.to_timedelta(m, errors="coerce")
Out[401]: TimedeltaIndex([NaT, '1 days'], dtype='timedelta64[ns]', freq=None) 

除了对象转换,to_numeric()还提供另一个参数downcast,该参数可以将新(或已有)的数值数据向下转换为较小的数据类型,以节省内存:

In [402]: m = ["1", 2, 3]
In [403]: pd.to_numeric(m, downcast="integer")  # smallest signed int dtype
Out[403]: array([1, 2, 3], dtype=int8)
In [404]: pd.to_numeric(m, downcast="signed")  # same as 'integer'
Out[404]: array([1, 2, 3], dtype=int8)
In [405]: pd.to_numeric(m, downcast="unsigned")  # smallest unsigned int dtype
Out[405]: array([1, 2, 3], dtype=uint8)
In [406]: pd.to_numeric(m, downcast="float")  # smallest float dtype
Out[406]: array([1., 2., 3.], dtype=float32) 

由于这些方法仅适用于一维数组、列表或标量;不能直接用于多维对象,如 DataFrames。但是,通过apply(),我们可以高效地对每列应用函数:

In [407]: import datetime
In [408]: df = pd.DataFrame([["2016-07-09", datetime.datetime(2016, 3, 2)]] * 2, dtype="O")
In [409]: df
Out[409]: 
 0                    1
0  2016-07-09  2016-03-02 00:00:00
1  2016-07-09  2016-03-02 00:00:00
In [410]: df.apply(pd.to_datetime)
Out[410]: 
 0          1
0 2016-07-09 2016-03-02
1 2016-07-09 2016-03-02
In [411]: df = pd.DataFrame([["1.1", 2, 3]] * 2, dtype="O")
In [412]: df
Out[412]: 
 0  1  2
0  1.1  2  3
1  1.1  2  3
In [413]: df.apply(pd.to_numeric)
Out[413]: 
 0  1  2
0  1.1  2  3
1  1.1  2  3
In [414]: df = pd.DataFrame([["5us", pd.Timedelta("1day")]] * 2, dtype="O")
In [415]: df
Out[415]: 
 0                1
0  5us  1 days 00:00:00
1  5us  1 days 00:00:00
In [416]: df.apply(pd.to_timedelta)
Out[416]: 
 0      1
0 0 days 00:00:00.000005 1 days
1 0 days 00:00:00.000005 1 days 

注意事项

integer类型数据上执行选择操作很容易将数据向上转换为floating。在不引入nans的情况下,输入数据的数据类型将被保留。另请参阅对整数 NA 的支持。

In [417]: dfi = df3.astype("int32")
In [418]: dfi["E"] = 1
In [419]: dfi
Out[419]: 
 A  B    C  E
0  1  0   26  1
1  3  1   86  1
2  0  0   46  1
3  0  1  212  1
4 -1 -1   26  1
5  1  0    7  1
6  0 -1  184  1
7  0  0  206  1
In [420]: dfi.dtypes
Out[420]: 
A    int32
B    int32
C    int32
E    int64
dtype: object
In [421]: casted = dfi[dfi > 0]
In [422]: casted
Out[422]: 
 A    B    C  E
0  1.0  NaN   26  1
1  3.0  1.0   86  1
2  NaN  NaN   46  1
3  NaN  1.0  212  1
4  NaN  NaN   26  1
5  1.0  NaN    7  1
6  NaN  NaN  184  1
7  NaN  NaN  206  1
In [423]: casted.dtypes
Out[423]: 
A    float64
B    float64
C      int32
E      int64
dtype: object 

浮点数数据类型保持不变。

In [424]: dfa = df3.copy()
In [425]: dfa["A"] = dfa["A"].astype("float32")
In [426]: dfa.dtypes
Out[426]: 
A    float32
B    float64
C    float64
dtype: object
In [427]: casted = dfa[df2 > 0]
In [428]: casted
Out[428]: 
 A         B      C
0  1.047606  0.256090   26.0
1  3.497968  1.426469   86.0
2       NaN       NaN   46.0
3       NaN  1.139976  212.0
4       NaN       NaN   26.0
5  1.346426  0.096706    7.0
6       NaN       NaN  184.0
7       NaN       NaN  206.0
In [429]: casted.dtypes
Out[429]: 
A    float32
B    float64
C    float64
dtype: object 

基于dtype选择列

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

首先,让我们创建一个具有各种不同数据类型的DataFrame

In [430]: 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 [431]: df["tdeltas"] = df.dates.diff()
In [432]: df["uint64"] = np.arange(3, 6).astype("u8")
In [433]: df["other_dates"] = pd.date_range("20130101", periods=3)
In [434]: df["tz_aware_dates"] = pd.date_range("20130101", periods=3, tz="US/Eastern")
In [435]: df
Out[435]: 
 string  int64  uint8  ...  uint64  other_dates            tz_aware_dates
0      a      1      3  ...       3   2013-01-01 2013-01-01 00:00:00-05:00
1      b      2      4  ...       4   2013-01-02 2013-01-02 00:00:00-05:00
2      c      3      5  ...       5   2013-01-03 2013-01-03 00:00:00-05:00
[3 rows x 12 columns] 

以及数据类型:

In [436]: df.dtypes
Out[436]: 
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,允许您说“给我这些数据类型的列”(include)和/或“给我没有这些数据类型的列”(exclude)。

例如,要选择bool列:

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

您还可以在NumPy 数据类型层次结构中传递数据类型的名称:

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

select_dtypes()也适用于通用数据类型。

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

In [439]: df.select_dtypes(include=["number", "bool"], exclude=["unsignedinteger"])
Out[439]: 
 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 [440]: df.select_dtypes(include=["object"])
Out[440]: 
 string
0      a
1      b
2      c 

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

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

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

In [442]: subdtypes(np.generic)
Out[442]: 
[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.longdouble]],
 [numpy.complexfloating,
 [numpy.complex64, numpy.complex128, numpy.clongdouble]]]]]],
 [numpy.flexible,
 [[numpy.character, [numpy.bytes_, numpy.str_]],
 [numpy.void, [numpy.record]]]],
 numpy.bool_,
 numpy.datetime64,
 numpy.object_]] 

注意

pandas 还定义了类型categorydatetime64[ns, tz],它们没有集成到正常的 NumPy 层次结构中,不会显示在上述函数中。

Head 和 tail

要查看 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 对象具有许多属性,使您能够访问元数据

  • shape:给出对象的轴维度,与 ndarray 一致
  • 轴标签
  • Series索引(仅轴)
  • 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 的类型系统以支持自定义数组(请参阅 dtypes)。

要获取IndexSeries内的实际数据,请使用.array属性

In [10]: s.array
Out[10]: 
<NumpyExtensionArray>
[ 0.4691122999071863, -0.2828633443286633, -1.5090585031735124,
 -1.1356323710171934,  1.2121120250208506]
Length: 5, dtype: float64
In [11]: s.index.array
Out[11]: 
<NumpyExtensionArray>
['a', 'b', 'c', 'd', 'e']
Length: 5, dtype: object

array将始终是一个ExtensionArray。关于ExtensionArray的确切细节以及 pandas 为什么使用它们略微超出了本介绍的范围。更多信息请参见 dtypes。

如果您知道您需要一个 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]) 

当 Series 或 Index 由ExtensionArray支持时,to_numpy()可能涉及复制数据和强制值。更多信息请参见 dtypes。

to_numpy()可以对生成的numpy.ndarraydtype进行一些控制。例如,考虑带有时区的日期时间。NumPy 没有一种 dtype 来表示带时区的日期时间,因此有两种可能有用的表示方式:

  1. 一个带有Timestamp对象的对象数据类型numpy.ndarray,每个对象都具有正确的tz
  2. 一个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 的某些列不全是相同 dtype),情况并非如此。与轴标签不同,值属性本身不能被赋值。

注意

当处理异构数据时,生成的 ndarray 的 dtype 将被选择以容纳所有涉及的数据。例如,如果涉及字符串,则结果将是对象 dtype。如果只有浮点数和整数,则生成的数组将是浮点 dtype。

在过去,pandas 推荐使用Series.valuesDataFrame.values来从 Series 或 DataFrame 中提取数据。您仍然会在旧代码库和在线上找到对这些的引用。未来,我们建议避免使用.values,而是使用.array.to_numpy().values具有以下缺点:

  1. 当您的 Series 包含扩展类型时,不清楚Series.values是返回 NumPy 数组还是扩展数组。Series.array将始终返回一个ExtensionArray,并且永远不会复制数据。Series.to_numpy()将始终返回一个 NumPy 数组,可能会以复制/强制转换值为代价。
  2. 当您的 DataFrame 包含不同数据类型时,DataFrame.values可能涉及复制数据并将值强制转换为公共 dtype,这是一个相对昂贵的操作。作为一个方法,DataFrame.to_numpy()更清晰地表明返回的 NumPy 数组可能不是 DataFrame 中相同数据的视图。

加速操作

pandas 支持使用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

你强烈建议安装这两个库。查看推荐依赖项部分获取更多安装信息。

这两者默认启用,您可以通过设置选项来控制:

pd.set_option("compute.use_bottleneck", False)
pd.set_option("compute.use_numexpr", False) 

灵活的二进制操作

在 pandas 数据结构之间进行二进制操作时,有两个关键点值得关注:

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

我们将演示如何独立处理这些问题,尽管它们可以同时处理。

匹配/广播行为

DataFrame 具有方法add()sub()mul()div()和相关函数radd()rsub()等用于执行二进制操作。对于广播行为,Series 输入是主要关注点。使用这些函数,您可以通过 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 

此外,您可以将 MultiIndexed 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 

Series 和 Index 也支持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]: Index([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], dtype='int64')
In [36]: div, rem = divmod(idx, 3)
In [37]: div
Out[37]: Index([0, 0, 0, 1, 1, 1, 2, 2, 2, 3], dtype='int64')
In [38]: rem
Out[38]: Index([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(如果需要,您可以稍后使用 fillna 将 NaN 替换为其他值)。

In [42]: df2 = df.copy()
In [43]: df2.loc["a", "three"] = 1.0
In [44]: df
Out[44]: 
 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 [45]: df2
Out[45]: 
 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 [46]: df + df2
Out[46]: 
 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 [47]: df.add(df2, fill_value=0)
Out[47]: 
 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 具有二进制比较方法 eqneltgtlege,其行为类似于上述二进制算术操作:

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

这些操作产生与左侧输入相同类型的 dtype 为 bool 的 pandas 对象。这些 boolean 对象可以用于索引操作,请参阅 布尔索引 部分。### 布尔规约

您可以应用以下规约:emptyany()all()bool() 来提供一种总结布尔结果的方式。

In [50]: (df > 0).all()
Out[50]: 
one      False
two       True
three    False
dtype: bool
In [51]: (df > 0).any()
Out[51]: 
one      True
two      True
three    True
dtype: bool 

您可以将其减少为最终布尔值。

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

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

In [53]: df.empty
Out[53]: False
In [54]: pd.DataFrame(columns=list("ABC")).empty
Out[54]: True 

警告

断言 pandas 对象的真实性将引发错误,因为对空值或值的测试是模棱两可的。

In [55]: if df:
 ....:    print(True)
 ....: 
---------------------------------------------------------------------------
ValueError  Traceback (most recent call last)
<ipython-input-55-318d08b2571a> in ?()
----> 1 if df:
  2     print(True)
~/work/pandas/pandas/pandas/core/generic.py in ?(self)
  1575     @final
  1576     def __nonzero__(self) -> NoReturn:
-> 1577         raise ValueError(
  1578             f"The truth value of a {type(self).__name__} is ambiguous. "
  1579             "Use a.empty, a.bool(), a.item(), a.any() or a.all()."
  1580         )
ValueError: The truth value of a DataFrame is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all(). 
In [56]: df and df2
---------------------------------------------------------------------------
ValueError  Traceback (most recent call last)
<ipython-input-56-b241b64bb471> in ?()
----> 1 df and df2
~/work/pandas/pandas/pandas/core/generic.py in ?(self)
  1575     @final
  1576     def __nonzero__(self) -> NoReturn:
-> 1577         raise ValueError(
  1578             f"The truth value of a {type(self).__name__} is ambiguous. "
  1579             "Use a.empty, a.bool(), a.item(), a.any() or a.all()."
  1580         )
ValueError: The truth value of a DataFrame is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all(). 

有关更详细讨论,请参阅 陷阱。### 比较对象是否等价

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

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 包含一些 False 值!这是因为 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 

请注意,为了使相等性为 True,Series 或 DataFrame 索引需要按相同顺序排列:

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 


相关文章
|
SQL 数据采集 数据挖掘
Pandas 教程
10月更文挑战第25天
271 2
|
数据采集 存储 数据可视化
Pandas高级教程:数据清洗、转换与分析
Pandas是Python的数据分析库,提供Series和DataFrame数据结构及数据分析工具,便于数据清洗、转换和分析。本教程涵盖Pandas在数据清洗(如缺失值、重复值和异常值处理)、转换(数据类型转换和重塑)和分析(如描述性统计、分组聚合和可视化)的应用。通过学习Pandas,用户能更高效地处理和理解数据,为数据分析任务打下基础。
1464 3
|
存储 JSON 数据格式
Pandas 使用教程 CSV - CSV 转 JSON
Pandas 使用教程 CSV - CSV 转 JSON
172 0
|
JSON 数据格式 Python
Pandas 使用教程 JSON
Pandas 使用教程 JSON
226 0
|
SQL 数据采集 JSON
Pandas 使用教程 Series、DataFrame
Pandas 使用教程 Series、DataFrame
323 0
|
索引 Python
Pandas 2.2 中文官方教程和指南(一)(4)
Pandas 2.2 中文官方教程和指南(一)
201 0
|
存储 SQL JSON
Pandas 2.2 中文官方教程和指南(一)(3)
Pandas 2.2 中文官方教程和指南(一)
256 0
|
XML 关系型数据库 PostgreSQL
Pandas 2.2 中文官方教程和指南(一)(2)
Pandas 2.2 中文官方教程和指南(一)
527 0
|
XML 关系型数据库 MySQL
Pandas 2.2 中文官方教程和指南(一)(1)
Pandas 2.2 中文官方教程和指南(一)
894 0
|
C++ 索引 Python
Pandas 2.2 中文官方教程和指南(五)(4)
Pandas 2.2 中文官方教程和指南(五)
140 0