Pandas 2.2 中文官方教程和指南(十六)(3)https://developer.aliyun.com/article/1509818
插值
DataFrame.interpolate()
和 Series.interpolate()
使用各种插值方法填充 NA 值。
In [103]: 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 [104]: df Out[104]: 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 [105]: df.interpolate() Out[105]: 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 [106]: idx = pd.date_range("2020-01-01", periods=10, freq="D") In [107]: data = np.random.default_rng(2).integers(0, 10, 10).astype(np.float64) In [108]: ts = pd.Series(data, index=idx) In [109]: ts.iloc[[1, 2, 5, 6, 9]] = np.nan In [110]: ts Out[110]: 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 [111]: ts.plot() Out[111]: <Axes: >
In [112]: ts.interpolate() Out[112]: 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 [113]: ts.interpolate().plot() Out[113]: <Axes: >
相对于Timestamp
在DatetimeIndex
中的插值可通过设置 method="time"
实现。
In [114]: ts2 = ts.iloc[[0, 1, 3, 7, 9]] In [115]: ts2 Out[115]: 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 [116]: ts2.interpolate() Out[116]: 2020-01-01 8.0 2020-01-02 5.0 2020-01-04 2.0 2020-01-08 0.0 2020-01-10 0.0 dtype: float64 In [117]: ts2.interpolate(method="time") Out[117]: 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 [118]: idx = [0.0, 1.0, 10.0] In [119]: ser = pd.Series([0.0, np.nan, 10.0], idx) In [120]: ser Out[120]: 0.0 0.0 1.0 NaN 10.0 10.0 dtype: float64 In [121]: ser.interpolate() Out[121]: 0.0 0.0 1.0 5.0 10.0 10.0 dtype: float64 In [122]: ser.interpolate(method="values") Out[122]: 0.0 0.0 1.0 1.0 10.0 10.0 dtype: float64
如果您已安装了scipy,可以将一个一维插值例程的名称传递给 method
。如在 scipy 插值 文档 和参考 指南 中指定的。适当的插值方法将取决于数据类型。
提示
如果您处理的时间序列呈增长趋势,请使用 method='barycentric'
。
如果您拥有近似累积分布函数的值,请使用 method='pchip'
。
若要使用 method='akima'
填充缺失值以获得平滑的绘图效果。
In [123]: 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 [124]: df Out[124]: 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 [125]: df.interpolate(method="barycentric") Out[125]: 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 [126]: df.interpolate(method="pchip") Out[126]: 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 [127]: df.interpolate(method="akima") Out[127]: 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 [128]: df.interpolate(method="spline", order=2) Out[128]: 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 [129]: df.interpolate(method="polynomial", order=2) Out[129]: 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 [130]: np.random.seed(2) In [131]: ser = pd.Series(np.arange(1, 10.1, 0.25) ** 2 + np.random.randn(37)) In [132]: missing = np.array([4, 13, 14, 15, 16, 17, 18, 20, 29]) In [133]: ser.iloc[missing] = np.nan In [134]: methods = ["linear", "quadratic", "cubic"] In [135]: df = pd.DataFrame({m: ser.interpolate(method=m) for m in methods}) In [136]: df.plot() Out[136]: <Axes: >
通过Series.reindex()
从扩展数据中插值新观测值。
In [137]: ser = pd.Series(np.sort(np.random.uniform(size=100))) # interpolate at new_index In [138]: new_index = ser.index.union(pd.Index([49.25, 49.5, 49.75, 50.25, 50.5, 50.75])) In [139]: interp_s = ser.reindex(new_index).interpolate(method="pchip") In [140]: interp_s.loc[49:51] Out[140]: 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 [141]: ser = pd.Series([np.nan, np.nan, 5, np.nan, np.nan, np.nan, 13, np.nan, np.nan]) In [142]: ser Out[142]: 0 NaN 1 NaN 2 5.0 3 NaN 4 NaN 5 NaN 6 13.0 7 NaN 8 NaN dtype: float64 In [143]: ser.interpolate() Out[143]: 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 [144]: ser.interpolate(limit=1) Out[144]: 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 [145]: ser.interpolate(limit=1, limit_direction="backward") Out[145]: 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 [146]: ser.interpolate(limit=1, limit_direction="both") Out[146]: 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 [147]: ser.interpolate(limit_direction="both") Out[147]: 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 [148]: ser.interpolate(limit_direction="both", limit_area="inside", limit=1) Out[148]: 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 [149]: ser.interpolate(limit_direction="backward", limit_area="outside") Out[149]: 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 [150]: ser.interpolate(limit_direction="both", limit_area="outside") Out[150]: 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 ```#### 插值限制 `interpolate()`接受一个`limit`关键字参数,以限制自上次有效观察以来填充的连续`NaN`值的数量。 ```py In [141]: ser = pd.Series([np.nan, np.nan, 5, np.nan, np.nan, np.nan, 13, np.nan, np.nan]) In [142]: ser Out[142]: 0 NaN 1 NaN 2 5.0 3 NaN 4 NaN 5 NaN 6 13.0 7 NaN 8 NaN dtype: float64 In [143]: ser.interpolate() Out[143]: 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 [144]: ser.interpolate(limit=1) Out[144]: 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 [145]: ser.interpolate(limit=1, limit_direction="backward") Out[145]: 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 [146]: ser.interpolate(limit=1, limit_direction="both") Out[146]: 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 [147]: ser.interpolate(limit_direction="both") Out[147]: 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 [148]: ser.interpolate(limit_direction="both", limit_area="inside", limit=1) Out[148]: 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 [149]: ser.interpolate(limit_direction="backward", limit_area="outside") Out[149]: 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 [150]: ser.interpolate(limit_direction="both", limit_area="outside") Out[150]: 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 [151]: df = pd.DataFrame(np.eye(3)) In [152]: df Out[152]: 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 [153]: df_missing = df.replace(0, np.nan) In [154]: df_missing Out[154]: 0 1 2 0 1.0 NaN NaN 1 NaN 1.0 NaN 2 NaN NaN 1.0 In [155]: df_filled = df_missing.replace(np.nan, 2) In [156]: df_filled Out[156]: 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 [157]: df_filled.replace([1, 44], [2, 28]) Out[157]: 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 [158]: df_filled.replace({1: 44, 2: 28}) Out[158]: 0 1 2 0 44.0 28.0 28.0 1 28.0 44.0 28.0 2 28.0 28.0 44.0
正则表达式替换
注意
Python 字符串前缀为r
字符,例如r'hello world'
是“原始”字符串。它们在反斜杠方面与没有此前缀的字符串有不同的语义。原始字符串中的反斜杠将被解释为转义的反斜杠,例如,r'\' == '\\'
。
用正则表达式将‘.’替换为NaN
。
In [159]: d = {"a": list(range(4)), "b": list("ab.."), "c": ["a", "b", np.nan, "d"]} In [160]: df = pd.DataFrame(d) In [161]: df.replace(".", np.nan) Out[161]: a b c 0 0 a a 1 1 b b 2 2 NaN NaN 3 3 NaN d
使用正则表达式将‘.’替换为NaN
,并去除周围的空格。
In [162]: df.replace(r"\s*\.\s*", np.nan, regex=True) Out[162]: a b c 0 0 a a 1 1 b b 2 2 NaN NaN 3 3 NaN d
用正则表达式列表替换。
In [163]: df.replace([r"\.", r"(a)"], ["dot", r"\1stuff"], regex=True) Out[163]: a b c 0 0 astuff astuff 1 1 b b 2 2 dot NaN 3 3 dot d
用映射字典中的正则表达式替换。
In [164]: df.replace({"b": r"\s*\.\s*"}, {"b": np.nan}, regex=True) Out[164]: a b c 0 0 a a 1 1 b b 2 2 NaN NaN 3 3 NaN d
传递使用regex
关键字的正则表达式的嵌套字典。
In [165]: df.replace({"b": {"b": r""}}, regex=True) Out[165]: a b c 0 0 a a 1 1 b 2 2 . NaN 3 3 . d In [166]: df.replace(regex={"b": {r"\s*\.\s*": np.nan}}) Out[166]: a b c 0 0 a a 1 1 b b 2 2 NaN NaN 3 3 NaN d In [167]: df.replace({"b": r"\s*(\.)\s*"}, {"b": r"\1ty"}, regex=True) Out[167]: a b c 0 0 a a 1 1 b b 2 2 .ty NaN 3 3 .ty d
传递一个正则表达式列表,将匹配项替换为标量。
In [168]: df.replace([r"\s*\.\s*", r"a|b"], "placeholder", regex=True) Out[168]: 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 [169]: df.replace(regex=[r"\s*\.\s*", r"a|b"], value="placeholder") Out[169]: a b c 0 0 placeholder placeholder 1 1 placeholder placeholder 2 2 placeholder NaN 3 3 placeholder d
注意
来自re.compile
的正则表达式对象也是有效的输入。#### 正则表达式替换
注意
Python 字符串前缀为r
字符,例如r'hello world'
是“原始”字符串。它们在反斜杠方面与没有此前缀的字符串有不同的语义。原始字符串中的反斜杠将被解释为转义的反斜杠,例如,r'\' == '\\'
。
用正则表达式将‘.’替换为NaN
。
In [159]: d = {"a": list(range(4)), "b": list("ab.."), "c": ["a", "b", np.nan, "d"]} In [160]: df = pd.DataFrame(d) In [161]: df.replace(".", np.nan) Out[161]: a b c 0 0 a a 1 1 b b 2 2 NaN NaN 3 3 NaN d
使用正则表达式将‘.’替换为NaN
,并去除周围的空格。
In [162]: df.replace(r"\s*\.\s*", np.nan, regex=True) Out[162]: a b c 0 0 a a 1 1 b b 2 2 NaN NaN 3 3 NaN d
用正则表达式��表替换。
In [163]: df.replace([r"\.", r"(a)"], ["dot", r"\1stuff"], regex=True) Out[163]: a b c 0 0 astuff astuff 1 1 b b 2 2 dot NaN 3 3 dot d
用映射字典中的正则表达式替换。
In [164]: df.replace({"b": r"\s*\.\s*"}, {"b": np.nan}, regex=True) Out[164]: a b c 0 0 a a 1 1 b b 2 2 NaN NaN 3 3 NaN d
传递使用regex
关键字的正则表达式的嵌套字典。
In [165]: df.replace({"b": {"b": r""}}, regex=True) Out[165]: a b c 0 0 a a 1 1 b 2 2 . NaN 3 3 . d In [166]: df.replace(regex={"b": {r"\s*\.\s*": np.nan}}) Out[166]: a b c 0 0 a a 1 1 b b 2 2 NaN NaN 3 3 NaN d In [167]: df.replace({"b": r"\s*(\.)\s*"}, {"b": r"\1ty"}, regex=True) Out[167]: a b c 0 0 a a 1 1 b b 2 2 .ty NaN 3 3 .ty d
传递一个正则表达式列表,将匹配项替换为一个标量。
In [168]: df.replace([r"\s*\.\s*", r"a|b"], "placeholder", regex=True) Out[168]: 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 [169]: df.replace(regex=[r"\s*\.\s*", r"a|b"], value="placeholder") Out[169]: a b c 0 0 placeholder placeholder 1 1 placeholder placeholder 2 2 placeholder NaN 3 3 placeholder d
注意
从re.compile
创建的正则表达式对象也是有效的输入。