处理缺失数据#
被认为是“缺失”的值#
pandas 使用不同的标记值来表示缺失(也称为 NA),具体取决于数据类型。
numpy.nan
用于 NumPy 数据类型。使用 NumPy 数据类型的缺点是原始数据类型将被强制转换为 np.float64
或 object
。
In [1]: pd.Series([1, 2], dtype=np.int64).reindex([0, 1, 2])
Out[1]:
0 1.0
1 2.0
2 NaN
dtype: float64
In [2]: pd.Series([True, False], dtype=np.bool_).reindex([0, 1, 2])
Out[2]:
0 True
1 False
2 NaN
dtype: object
NaT
用于 NumPy np.datetime64
, np.timedelta64
, 和 PeriodDtype
。对于类型应用,使用 api.typing.NaTType
。
In [3]: pd.Series([1, 2], dtype=np.dtype("timedelta64[ns]")).reindex([0, 1, 2])
Out[3]:
0 0 days 00:00:00.000000001
1 0 days 00:00:00.000000002
2 NaT
dtype: timedelta64[ns]
In [4]: pd.Series([1, 2], dtype=np.dtype("datetime64[ns]")).reindex([0, 1, 2])
Out[4]:
0 1970-01-01 00:00:00.000000001
1 1970-01-01 00:00:00.000000002
2 NaT
dtype: datetime64[ns]
In [5]: pd.Series(["2020", "2020"], dtype=pd.PeriodDtype("D")).reindex([0, 1, 2])
Out[5]:
0 2020-01-01
1 2020-01-01
2 NaT
dtype: period[D]
NA
用于 StringDtype
、Int64Dtype`(以及其他位宽)、:class:`Float64Dtype`(以及其他位宽)、:class:`BooleanDtype
和 ArrowDtype
。这些类型将保持数据的原始数据类型。对于类型应用,使用 api.typing.NAType
。
In [6]: pd.Series([1, 2], dtype="Int64").reindex([0, 1, 2])
Out[6]:
0 1
1 2
2 <NA>
dtype: Int64
In [7]: pd.Series([True, False], dtype="boolean[pyarrow]").reindex([0, 1, 2])
Out[7]:
0 True
1 False
2 <NA>
dtype: bool[pyarrow]
要检测这些缺失值,请使用 isna()
或 notna()
方法。
In [8]: ser = pd.Series([pd.Timestamp("2020-01-01"), pd.NaT])
In [9]: ser
Out[9]:
0 2020-01-01
1 NaT
dtype: datetime64[s]
In [10]: pd.isna(ser)
Out[10]:
0 False
1 True
dtype: bool
备注
isna()
或 notna()
也将考虑 None
为缺失值。
In [11]: ser = pd.Series([1, None], dtype=object)
In [12]: ser
Out[12]:
0 1
1 None
dtype: object
In [13]: pd.isna(ser)
Out[13]:
0 False
1 True
dtype: bool
警告
np.nan
、NaT
和 NA
之间的相等比较不像 None
那样表现。
In [14]: None == None # noqa: E711
Out[14]: True
In [15]: np.nan == np.nan
Out[15]: False
In [16]: pd.NaT == pd.NaT
Out[16]: False
In [17]: pd.NA == pd.NA
Out[17]: <NA>
因此,在包含这些缺失值的 DataFrame
或 Series
之间进行相等比较,不会提供与 isna()
或 notna()
相同的信息。
In [18]: ser = pd.Series([True, None], dtype="boolean[pyarrow]")
In [19]: ser == pd.NA
Out[19]:
0 <NA>
1 <NA>
dtype: bool[pyarrow]
In [20]: pd.isna(ser)
Out[20]:
0 False
1 True
dtype: bool
NA
语义#
警告
实验性:NA
的行为仍可能在无警告的情况下发生变化。
从 pandas 1.0 开始,一个实验性的 NA
值(单例)可用于表示标量缺失值。NA
的目标是提供一个可以在不同数据类型中一致使用的“缺失”指示符(而不是根据数据类型使用 np.nan
、None
或 pd.NaT
)。
例如,当在具有可空整数类型的 Series
中存在缺失值时,它将使用 NA
:
In [21]: s = pd.Series([1, 2, None], dtype="Int64")
In [22]: s
Out[22]:
0 1
1 2
2 <NA>
dtype: Int64
In [23]: s[2]
Out[23]: <NA>
In [24]: s[2] is pd.NA
Out[24]: True
目前,pandas 在 DataFrame
或 Series
中默认不使用这些数据类型使用 NA
,因此您需要显式指定 dtype。在 转换部分 中解释了一种将这些 dtypes 转换为简单的方法。
算术和比较运算中的传播#
通常,缺失值在涉及 NA
的操作中 传播 。当一个操作数未知时,操作的结果也是未知的。
例如,NA
在算术运算中传播,类似于 np.nan
:
In [25]: pd.NA + 1
Out[25]: <NA>
In [26]: "a" * pd.NA
Out[26]: <NA>
在某些特殊情况下,即使其中一个操作数是 NA
,结果也是已知的。
In [27]: pd.NA ** 0
Out[27]: 1
In [28]: 1 ** pd.NA
Out[28]: 1
在相等和比较操作中,NA
也会传播。这与 np.nan
的行为不同,其中与 np.nan
的比较总是返回 False
。
In [29]: pd.NA == 1
Out[29]: <NA>
In [30]: pd.NA == pd.NA
Out[30]: <NA>
In [31]: pd.NA < 2.5
Out[31]: <NA>
In [32]: pd.isna(pd.NA)
Out[32]: True
备注
这种基本传播规则的一个例外是 归约 (例如均值或最小值),其中 pandas 默认跳过缺失值。更多信息请参见 计算部分。
逻辑操作#
对于逻辑操作,NA
遵循 三值逻辑 (或 Kleene逻辑,类似于 R、SQL 和 Julia)的规则。这种逻辑意味着仅在逻辑上需要时才传播缺失值。
例如,对于逻辑“或”操作(|
),如果其中一个操作数是``True``,我们已经知道结果将是``True``,无论另一个值是什么(因此无论缺失的值是``True``还是``False``)。在这种情况下,NA
不会传播:
In [33]: True | False
Out[33]: True
In [34]: True | pd.NA
Out[34]: True
In [35]: pd.NA | True
Out[35]: True
另一方面,如果其中一个操作数是 False
,结果取决于另一个操作数的值。因此,在这种情况下 NA
传播:
In [36]: False | True
Out[36]: True
In [37]: False | False
Out[37]: False
In [38]: False | pd.NA
Out[38]: <NA>
逻辑“与”操作 (&
) 的行为可以使用类似的逻辑推导(现在如果其中一个操作数已经是 False
,NA
将不会传播):
In [39]: False & True
Out[39]: False
In [40]: False & False
Out[40]: False
In [41]: False & pd.NA
Out[41]: False
In [42]: True & True
Out[42]: True
In [43]: True & False
Out[43]: False
In [44]: True & pd.NA
Out[44]: <NA>
在布尔上下文中 NA
#
由于NA的实际值是未知的,将其转换为布尔值是不明确的。
In [45]: bool(pd.NA)
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
Cell In[45], line 1
----> 1 bool(pd.NA)
File missing.pyx:388, in pandas._libs.missing.NAType.__bool__()
TypeError: boolean value of NA is ambiguous
这也意味着 NA
不能在评估为布尔值的上下文中使用,例如 if condition: ...
其中 condition
可能为 NA
。在这种情况下,可以使用 isna()
检查 NA
或避免 condition
为 NA
,例如事先填充缺失值。
在使用 if
语句中的 Series
或 DataFrame
对象时,也会出现类似的情况,参见 在 pandas 中使用 if/truth 语句。
NumPy ufuncs#
pandas.NA
实现了 NumPy 的 __array_ufunc__
协议。大多数 ufuncs 与 NA
一起工作,并且通常返回 NA
:
In [46]: np.log(pd.NA)
Out[46]: <NA>
In [47]: np.add(pd.NA, 1)
Out[47]: <NA>
警告
目前,涉及 ndarray 和 NA
的 ufuncs 将返回一个填充了 NA 值的 object-dtype。
In [48]: a = np.array([1, 2, 3])
In [49]: np.greater(a, pd.NA)
Out[49]: array([<NA>, <NA>, <NA>], dtype=object)
这里的返回类型未来可能会改为返回不同的数组类型。
更多关于ufuncs的信息,请参见 DataFrame 与 NumPy 函数的互操作性。
转换#
如果你有一个 DataFrame
或 Series
使用 np.nan
,DataFrame.convert_dtypes()
和 Series.convert_dtypes()
将分别将你的数据转换为使用支持 NA
的可空数据类型,例如 Int64Dtype
或 ArrowDtype
。这在从 IO 方法读取数据集后,数据类型被推断时特别有帮助。
在这个例子中,虽然所有列的数据类型都改变了,我们展示了前10列的结果。
In [50]: import io
In [51]: data = io.StringIO("a,b\n,True\n2,")
In [52]: df = pd.read_csv(data)
In [53]: df.dtypes
Out[53]:
a float64
b object
dtype: object
In [54]: df_conv = df.convert_dtypes()
In [55]: df_conv
Out[55]:
a b
0 <NA> True
1 2 <NA>
In [56]: df_conv.dtypes
Out[56]:
a Int64
b boolean
dtype: object
插入缺失数据#
你可以通过简单地赋值给 Series
或 DataFrame
来插入缺失值。所使用的缺失值标记将根据数据类型选择。
In [57]: ser = pd.Series([1., 2., 3.])
In [58]: ser.loc[0] = None
In [59]: ser
Out[59]:
0 NaN
1 2.0
2 3.0
dtype: float64
In [60]: ser = pd.Series([pd.Timestamp("2021"), pd.Timestamp("2021")])
In [61]: ser.iloc[0] = np.nan
In [62]: ser
Out[62]:
0 NaT
1 2021-01-01
dtype: datetime64[s]
In [63]: ser = pd.Series([True, False], dtype="boolean[pyarrow]")
In [64]: ser.iloc[0] = None
In [65]: ser
Out[65]:
0 <NA>
1 False
dtype: bool[pyarrow]
对于 object
类型,pandas 将使用给定的值:
In [66]: s = pd.Series(["a", "b", "c"], dtype=object)
In [67]: s.loc[0] = None
In [68]: s.loc[1] = np.nan
In [69]: s
Out[69]:
0 None
1 NaN
2 c
dtype: object
缺失数据的计算#
缺失值在 pandas 对象之间的算术运算中会传播。
In [70]: ser1 = pd.Series([np.nan, np.nan, 2, 3])
In [71]: ser2 = pd.Series([np.nan, 1, np.nan, 4])
In [72]: ser1
Out[72]:
0 NaN
1 NaN
2 2.0
3 3.0
dtype: float64
In [73]: ser2
Out[73]:
0 NaN
1 1.0
2 NaN
3 4.0
dtype: float64
In [74]: ser1 + ser2
Out[74]:
0 NaN
1 NaN
2 NaN
3 7.0
dtype: float64
在 数据结构概述 中讨论的描述性统计和计算方法(并列在 这里 和 这里)都考虑了缺失数据。
在汇总数据时,NA 值或空数据将被视为零。
In [75]: pd.Series([np.nan]).sum()
Out[75]: 0.0
In [76]: pd.Series([], dtype="float64").sum()
Out[76]: 0.0
当使用产品时,NA 值或空数据将被视为 1。
In [77]: pd.Series([np.nan]).prod()
Out[77]: 1.0
In [78]: pd.Series([], dtype="float64").prod()
Out[78]: 1.0
像 cumsum()
和 cumprod()
这样的累积方法默认忽略 NA 值,但在结果数组中保留它们。要覆盖此行为并在计算中包含 NA 值,请使用 skipna=False
。
In [79]: ser = pd.Series([1, np.nan, 3, np.nan])
In [80]: ser
Out[80]:
0 1.0
1 NaN
2 3.0
3 NaN
dtype: float64
In [81]: ser.cumsum()
Out[81]:
0 1.0
1 NaN
2 4.0
3 NaN
dtype: float64
In [82]: ser.cumsum(skipna=False)
Out[82]:
0 1.0
1 NaN
2 NaN
3 NaN
dtype: float64
删除缺失数据#
dropna()
删除包含缺失数据的行或列。
In [83]: df = pd.DataFrame([[np.nan, 1, 2], [1, 2, np.nan], [1, 2, 3]])
In [84]: df
Out[84]:
0 1 2
0 NaN 1 2.0
1 1.0 2 NaN
2 1.0 2 3.0
In [85]: df.dropna()
Out[85]:
0 1 2
2 1.0 2 3.0
In [86]: df.dropna(axis=1)
Out[86]:
1
0 1
1 2
2 2
In [87]: ser = pd.Series([1, pd.NA], dtype="int64[pyarrow]")
In [88]: ser.dropna()
Out[88]:
0 1
dtype: int64[pyarrow]
填充缺失数据#
按值填充#
fillna()
用非NA数据替换NA值。
将 NA 替换为标量值
In [89]: data = {"np": [1.0, np.nan, np.nan, 2], "arrow": pd.array([1.0, pd.NA, pd.NA, 2], dtype="float64[pyarrow]")}
In [90]: df = pd.DataFrame(data)
In [91]: df
Out[91]:
np arrow
0 1.0 1.0
1 NaN <NA>
2 NaN <NA>
3 2.0 2.0
In [92]: df.fillna(0)
Out[92]:
np arrow
0 1.0 1.0
1 0.0 0.0
2 0.0 0.0
3 2.0 2.0
当数据具有对象数据类型时,您可以控制存在哪种类型的 NA 值。
In [93]: df = pd.DataFrame({"a": [pd.NA, np.nan, None]}, dtype=object)
In [94]: df
Out[94]:
a
0 <NA>
1 NaN
2 None
In [95]: df.fillna(None)
Out[95]:
a
0 None
1 None
2 None
In [96]: df.fillna(np.nan)
Out[96]:
a
0 NaN
1 NaN
2 NaN
In [97]: df.fillna(pd.NA)
Out[97]:
a
0 <NA>
1 <NA>
2 <NA>
然而,当 dtype 不是对象时,这些都将被替换为该 dtype 的适当 NA 值。
In [98]: data = {"np": [1.0, np.nan, np.nan, 2], "arrow": pd.array([1.0, pd.NA, pd.NA, 2], dtype="float64[pyarrow]")}
In [99]: df = pd.DataFrame(data)
In [100]: df
Out[100]:
np arrow
0 1.0 1.0
1 NaN <NA>
2 NaN <NA>
3 2.0 2.0
In [101]: df.fillna(None)
Out[101]:
np arrow
0 1.0 1.0
1 NaN <NA>
2 NaN <NA>
3 2.0 2.0
In [102]: df.fillna(np.nan)
Out[102]:
np arrow
0 1.0 1.0
1 NaN <NA>
2 NaN <NA>
3 2.0 2.0
In [103]: df.fillna(pd.NA)
Out[103]:
np arrow
0 1.0 1.0
1 NaN <NA>
2 NaN <NA>
3 2.0 2.0
向前或向后填充空白
In [104]: df.ffill()
Out[104]:
np arrow
0 1.0 1.0
1 1.0 1.0
2 1.0 1.0
3 2.0 2.0
In [105]: df.bfill()
Out[105]:
np arrow
0 1.0 1.0
1 2.0 2.0
2 2.0 2.0
3 2.0 2.0
限制填充的 NA 值的数量
In [106]: df.ffill(limit=1)
Out[106]:
np arrow
0 1.0 1.0
1 1.0 1.0
2 NaN <NA>
3 2.0 2.0
NA 值可以用 Series
或 DataFrame
中的相应值替换,其中索引和列在原始对象和填充对象之间对齐。
In [107]: dff = pd.DataFrame(np.arange(30, dtype=np.float64).reshape(10, 3), columns=list("ABC"))
In [108]: dff.iloc[3:5, 0] = np.nan
In [109]: dff.iloc[4:6, 1] = np.nan
In [110]: dff.iloc[5:8, 2] = np.nan
In [111]: dff
Out[111]:
A B C
0 0.0 1.0 2.0
1 3.0 4.0 5.0
2 6.0 7.0 8.0
3 NaN 10.0 11.0
4 NaN NaN 14.0
5 15.0 NaN NaN
6 18.0 19.0 NaN
7 21.0 22.0 NaN
8 24.0 25.0 26.0
9 27.0 28.0 29.0
In [112]: dff.fillna(dff.mean())
Out[112]:
A B C
0 0.00 1.0 2.000000
1 3.00 4.0 5.000000
2 6.00 7.0 8.000000
3 14.25 10.0 11.000000
4 14.25 14.5 14.000000
5 15.00 14.5 13.571429
6 18.00 19.0 13.571429
7 21.00 22.0 13.571429
8 24.00 25.0 26.000000
9 27.00 28.0 29.000000
备注
DataFrame.where()
也可以用来填充NA值。与上述结果相同。
In [113]: dff.where(pd.notna(dff), dff.mean(), axis="columns")
Out[113]:
A B C
0 0.00 1.0 2.000000
1 3.00 4.0 5.000000
2 6.00 7.0 8.000000
3 14.25 10.0 11.000000
4 14.25 14.5 14.000000
5 15.00 14.5 13.571429
6 18.00 19.0 13.571429
7 21.00 22.0 13.571429
8 24.00 25.0 26.000000
9 27.00 28.0 29.000000
插值#
DataFrame.interpolate()
和 Series.interpolate()
使用各种插值方法填充 NA 值。
In [114]: df = pd.DataFrame(
.....: {
.....: "A": [1, 2.1, np.nan, 4.7, 5.6, 6.8],
.....: "B": [0.25, np.nan, np.nan, 4, 12.2, 14.4],
.....: }
.....: )
.....:
In [115]: df
Out[115]:
A B
0 1.0 0.25
1 2.1 NaN
2 NaN NaN
3 4.7 4.00
4 5.6 12.20
5 6.8 14.40
In [116]: df.interpolate()
Out[116]:
A B
0 1.0 0.25
1 2.1 1.50
2 3.4 2.75
3 4.7 4.00
4 5.6 12.20
5 6.8 14.40
In [117]: idx = pd.date_range("2020-01-01", periods=10, freq="D")
In [118]: data = np.random.default_rng(2).integers(0, 10, 10).astype(np.float64)
In [119]: ts = pd.Series(data, index=idx)
In [120]: ts.iloc[[1, 2, 5, 6, 9]] = np.nan
In [121]: ts
Out[121]:
2020-01-01 8.0
2020-01-02 NaN
2020-01-03 NaN
2020-01-04 2.0
2020-01-05 4.0
2020-01-06 NaN
2020-01-07 NaN
2020-01-08 0.0
2020-01-09 3.0
2020-01-10 NaN
Freq: D, dtype: float64
In [122]: ts.plot()
Out[122]: <Axes: >
In [123]: ts.interpolate()
Out[123]:
2020-01-01 8.000000
2020-01-02 6.000000
2020-01-03 4.000000
2020-01-04 2.000000
2020-01-05 4.000000
2020-01-06 2.666667
2020-01-07 1.333333
2020-01-08 0.000000
2020-01-09 3.000000
2020-01-10 3.000000
Freq: D, dtype: float64
In [124]: ts.interpolate().plot()
Out[124]: <Axes: >
在 DatetimeIndex
中相对于 Timestamp
的插值可以通过设置 method="time"
来实现
In [125]: ts2 = ts.iloc[[0, 1, 3, 7, 9]]
In [126]: ts2
Out[126]:
2020-01-01 8.0
2020-01-02 NaN
2020-01-04 2.0
2020-01-08 0.0
2020-01-10 NaN
dtype: float64
In [127]: ts2.interpolate()
Out[127]:
2020-01-01 8.0
2020-01-02 6.0
2020-01-04 2.0
2020-01-08 0.0
2020-01-10 0.0
dtype: float64
In [128]: ts2.interpolate(method="time")
Out[128]:
2020-01-01 8.0
2020-01-02 6.0
2020-01-04 2.0
2020-01-08 0.0
2020-01-10 0.0
dtype: float64
对于浮点数索引,使用 method='values'
:
In [129]: idx = [0.0, 1.0, 10.0]
In [130]: ser = pd.Series([0.0, np.nan, 10.0], idx)
In [131]: ser
Out[131]:
0.0 0.0
1.0 NaN
10.0 10.0
dtype: float64
In [132]: ser.interpolate()
Out[132]:
0.0 0.0
1.0 1.0
10.0 10.0
dtype: float64
In [133]: ser.interpolate(method="values")
Out[133]:
0.0 0.0
1.0 1.0
10.0 10.0
dtype: float64
如果你安装了 scipy,你可以将一个一维插值例程的名称传递给 method
,如 scipy 插值文档 和参考指南 中所述。适当的插值方法将取决于数据类型。
小技巧
如果你处理的是一个增长速度不断加快的时间序列,请使用 method='barycentric'
。
如果你有近似累积分布函数的值,请使用 method='pchip'
。
为了填补缺失值以实现平滑绘图,请使用 method='akima'
。
In [134]: df = pd.DataFrame(
.....: {
.....: "A": [1, 2.1, np.nan, 4.7, 5.6, 6.8],
.....: "B": [0.25, np.nan, np.nan, 4, 12.2, 14.4],
.....: }
.....: )
.....:
In [135]: df
Out[135]:
A B
0 1.0 0.25
1 2.1 NaN
2 NaN NaN
3 4.7 4.00
4 5.6 12.20
5 6.8 14.40
In [136]: df.interpolate(method="barycentric")
Out[136]:
A B
0 1.00 0.250
1 2.10 -7.660
2 3.53 -4.515
3 4.70 4.000
4 5.60 12.200
5 6.80 14.400
In [137]: df.interpolate(method="pchip")
Out[137]:
A B
0 1.00000 0.250000
1 2.10000 0.672808
2 3.43454 1.928950
3 4.70000 4.000000
4 5.60000 12.200000
5 6.80000 14.400000
In [138]: df.interpolate(method="akima")
Out[138]:
A B
0 1.000000 0.250000
1 2.100000 -0.873316
2 3.406667 0.320034
3 4.700000 4.000000
4 5.600000 12.200000
5 6.800000 14.400000
当通过多项式或样条插值时,您还必须指定插值的次数或阶数:
In [139]: df.interpolate(method="spline", order=2)
Out[139]:
A B
0 1.000000 0.250000
1 2.100000 -0.428598
2 3.404545 1.206900
3 4.700000 4.000000
4 5.600000 12.200000
5 6.800000 14.400000
In [140]: df.interpolate(method="polynomial", order=2)
Out[140]:
A B
0 1.000000 0.250000
1 2.100000 -2.703846
2 3.451351 -1.453846
3 4.700000 4.000000
4 5.600000 12.200000
5 6.800000 14.400000
比较几种方法。
In [141]: np.random.seed(2)
In [142]: ser = pd.Series(np.arange(1, 10.1, 0.25) ** 2 + np.random.randn(37))
In [143]: missing = np.array([4, 13, 14, 15, 16, 17, 18, 20, 29])
In [144]: ser.iloc[missing] = np.nan
In [145]: methods = ["linear", "quadratic", "cubic"]
In [146]: df = pd.DataFrame({m: ser.interpolate(method=m) for m in methods})
In [147]: df.plot()
Out[147]: <Axes: >
使用 Series.reindex()
从扩展数据中插入新观测值。
In [148]: ser = pd.Series(np.sort(np.random.uniform(size=100)))
# interpolate at new_index
In [149]: new_index = ser.index.union(pd.Index([49.25, 49.5, 49.75, 50.25, 50.5, 50.75]))
In [150]: interp_s = ser.reindex(new_index).interpolate(method="pchip")
In [151]: interp_s.loc[49:51]
Out[151]:
49.00 0.471410
49.25 0.476841
49.50 0.481780
49.75 0.485998
50.00 0.489266
50.25 0.491814
50.50 0.493995
50.75 0.495763
51.00 0.497074
dtype: float64
插值限制#
interpolate()
接受一个 limit
关键字参数,以限制自上次有效观测以来填充的连续 NaN
值的数量
In [152]: ser = pd.Series([np.nan, np.nan, 5, np.nan, np.nan, np.nan, 13, np.nan, np.nan])
In [153]: ser
Out[153]:
0 NaN
1 NaN
2 5.0
3 NaN
4 NaN
5 NaN
6 13.0
7 NaN
8 NaN
dtype: float64
In [154]: ser.interpolate()
Out[154]:
0 NaN
1 NaN
2 5.0
3 7.0
4 9.0
5 11.0
6 13.0
7 13.0
8 13.0
dtype: float64
In [155]: ser.interpolate(limit=1)
Out[155]:
0 NaN
1 NaN
2 5.0
3 7.0
4 NaN
5 NaN
6 13.0
7 13.0
8 NaN
dtype: float64
默认情况下,NaN
值以 forward
方向填充。使用 limit_direction
参数以 backward
或 both
方向填充。
In [156]: ser.interpolate(limit=1, limit_direction="backward")
Out[156]:
0 NaN
1 5.0
2 5.0
3 NaN
4 NaN
5 11.0
6 13.0
7 NaN
8 NaN
dtype: float64
In [157]: ser.interpolate(limit=1, limit_direction="both")
Out[157]:
0 NaN
1 5.0
2 5.0
3 7.0
4 NaN
5 11.0
6 13.0
7 13.0
8 NaN
dtype: float64
In [158]: ser.interpolate(limit_direction="both")
Out[158]:
0 5.0
1 5.0
2 5.0
3 7.0
4 9.0
5 11.0
6 13.0
7 13.0
8 13.0
dtype: float64
默认情况下,NaN
值会被填充,无论它们是被现有的有效值包围还是位于现有的有效值之外。limit_area
参数将填充限制在内部或外部值。
# fill one consecutive inside value in both directions
In [159]: ser.interpolate(limit_direction="both", limit_area="inside", limit=1)
Out[159]:
0 NaN
1 NaN
2 5.0
3 7.0
4 NaN
5 11.0
6 13.0
7 NaN
8 NaN
dtype: float64
# fill all consecutive outside values backward
In [160]: ser.interpolate(limit_direction="backward", limit_area="outside")
Out[160]:
0 5.0
1 5.0
2 5.0
3 NaN
4 NaN
5 NaN
6 13.0
7 NaN
8 NaN
dtype: float64
# fill all consecutive outside values in both directions
In [161]: ser.interpolate(limit_direction="both", limit_area="outside")
Out[161]:
0 5.0
1 5.0
2 5.0
3 NaN
4 NaN
5 NaN
6 13.0
7 13.0
8 13.0
dtype: float64
替换值#
Series.replace()
和 DataFrame.replace()
可以类似于 Series.fillna()
和 DataFrame.fillna()
用于替换或插入缺失值。
In [162]: df = pd.DataFrame(np.eye(3))
In [163]: df
Out[163]:
0 1 2
0 1.0 0.0 0.0
1 0.0 1.0 0.0
2 0.0 0.0 1.0
In [164]: df_missing = df.replace(0, np.nan)
In [165]: df_missing
Out[165]:
0 1 2
0 1.0 NaN NaN
1 NaN 1.0 NaN
2 NaN NaN 1.0
In [166]: df_filled = df_missing.replace(np.nan, 2)
In [167]: df_filled
Out[167]:
0 1 2
0 1.0 2.0 2.0
1 2.0 1.0 2.0
2 2.0 2.0 1.0
通过传递一个列表,可以替换多个值。
In [168]: df_filled.replace([1, 44], [2, 28])
Out[168]:
0 1 2
0 2.0 2.0 2.0
1 2.0 2.0 2.0
2 2.0 2.0 2.0
使用映射字典进行替换。
In [169]: df_filled.replace({1: 44, 2: 28})
Out[169]:
0 1 2
0 44.0 28.0 28.0
1 28.0 44.0 28.0
2 28.0 28.0 44.0
正则表达式替换#
备注
以 r
字符为前缀的 Python 字符串,例如 r'hello world'
是 “原始” 字符串。它们在反斜杠方面的语义与没有此前缀的字符串不同。原始字符串中的反斜杠将被解释为转义的反斜杠,例如,r'\' == '\\'
。
将 ‘.’ 替换为 NaN
In [170]: d = {"a": list(range(4)), "b": list("ab.."), "c": ["a", "b", np.nan, "d"]}
In [171]: df = pd.DataFrame(d)
In [172]: df.replace(".", np.nan)
Out[172]:
a b c
0 0 a a
1 1 b b
2 2 NaN NaN
3 3 NaN d
用正则表达式将 ‘.’ 替换为 NaN
并去除周围的空白
In [173]: df.replace(r"\s*\.\s*", np.nan, regex=True)
Out[173]:
a b c
0 0 a a
1 1 b b
2 2 NaN NaN
3 3 NaN d
替换为正则表达式列表。
In [174]: df.replace([r"\.", r"(a)"], ["dot", r"\1stuff"], regex=True)
Out[174]:
a b c
0 0 astuff astuff
1 1 b b
2 2 dot NaN
3 3 dot d
在映射字典中用正则表达式替换。
In [175]: df.replace({"b": r"\s*\.\s*"}, {"b": np.nan}, regex=True)
Out[175]:
a b c
0 0 a a
1 1 b b
2 2 NaN NaN
3 3 NaN d
传递使用 regex
关键字的嵌套正则表达式字典。
In [176]: df.replace({"b": {"b": r""}}, regex=True)
Out[176]:
a b c
0 0 a a
1 1 b
2 2 . NaN
3 3 . d
In [177]: df.replace(regex={"b": {r"\s*\.\s*": np.nan}})
Out[177]:
a b c
0 0 a a
1 1 b b
2 2 NaN NaN
3 3 NaN d
In [178]: df.replace({"b": r"\s*(\.)\s*"}, {"b": r"\1ty"}, regex=True)
Out[178]:
a b c
0 0 a a
1 1 b b
2 2 .ty NaN
3 3 .ty d
传递一个正则表达式列表,这些正则表达式将用标量替换匹配项。
In [179]: df.replace([r"\s*\.\s*", r"a|b"], "placeholder", regex=True)
Out[179]:
a b c
0 0 placeholder placeholder
1 1 placeholder placeholder
2 2 placeholder NaN
3 3 placeholder d
所有正则表达式示例也可以通过 to_replace
参数传递,作为 regex
参数。在这种情况下,必须通过名称显式传递 value
参数,或者 regex
必须是一个嵌套字典。
In [180]: df.replace(regex=[r"\s*\.\s*", r"a|b"], value="placeholder")
Out[180]:
a b c
0 0 placeholder placeholder
1 1 placeholder placeholder
2 2 placeholder NaN
3 3 placeholder d
备注
从 re.compile
生成的正则表达式对象也是一个有效的输入。