使用分层索引进行高级索引
在使用.loc
进行高级索引时,将MultiIndex
在语法上整合在一起有点具有挑战性,但我们已经尽力做到了。一般来说,MultiIndex 键采用元组的形式。例如,以下操作会按您的预期工作:
In [39]: df = df.T In [40]: df Out[40]: A B C first second bar one 0.895717 0.410835 -1.413681 two 0.805244 0.813850 1.607920 baz one -1.206412 0.132003 1.024180 two 2.565646 -0.827317 0.569605 foo one 1.431256 -0.076467 0.875906 two 1.340309 -1.187678 -2.211372 qux one -1.170299 1.130127 0.974466 two -0.226169 -1.436737 -2.006747 In [41]: df.loc[("bar", "two")] Out[41]: A 0.805244 B 0.813850 C 1.607920 Name: (bar, two), dtype: float64
请注意,在这个例子中,df.loc['bar', 'two']
也可以工作,但这种简写符号在一般情况下可能会导致歧义。
如果您还想使用.loc
索引特定列,必须像这样使用元组:
In [42]: df.loc[("bar", "two"), "A"] Out[42]: 0.8052440253863785
你不必通过仅传递元组的第一个元素来指定MultiIndex
的所有级别。例如,你可以使用“部分”索引来获取所有第一级别中带有bar
的元素如下:
In [43]: df.loc["bar"] Out[43]: A B C second one 0.895717 0.410835 -1.413681 two 0.805244 0.813850 1.607920
这是略微更冗长的符号df.loc[('bar',),]
的快捷方式(在这个例子中等同于df.loc['bar',]
)。
“部分���切片也非常有效。
In [44]: df.loc["baz":"foo"] Out[44]: A B C first second baz one -1.206412 0.132003 1.024180 two 2.565646 -0.827317 0.569605 foo one 1.431256 -0.076467 0.875906 two 1.340309 -1.187678 -2.211372
通过提供元组切片来对“范围”值进行切片。
In [45]: df.loc[("baz", "two"):("qux", "one")] Out[45]: A B C first second baz two 2.565646 -0.827317 0.569605 foo one 1.431256 -0.076467 0.875906 two 1.340309 -1.187678 -2.211372 qux one -1.170299 1.130127 0.974466 In [46]: df.loc[("baz", "two"):"foo"] Out[46]: A B C first second baz two 2.565646 -0.827317 0.569605 foo one 1.431256 -0.076467 0.875906 two 1.340309 -1.187678 -2.211372
传递标签列表或元组类似于重新索引:
In [47]: df.loc[[("bar", "two"), ("qux", "one")]] Out[47]: A B C first second bar two 0.805244 0.813850 1.607920 qux one -1.170299 1.130127 0.974466
注意
需要注意的是,在 pandas 中,元组和列表在索引时并非被处理相同。元组被解释为一个多级键,而列表用于指定多个键。换句话说,元组水平移动(遍历级别),列表垂直移动(扫描级别)。
重要的是,元组列表索引多个完整的MultiIndex
键,而列表元组引用一个级别内的多个值:
In [48]: s = pd.Series( ....: [1, 2, 3, 4, 5, 6], ....: index=pd.MultiIndex.from_product([["A", "B"], ["c", "d", "e"]]), ....: ) ....: In [49]: s.loc[[("A", "c"), ("B", "d")]] # list of tuples Out[49]: A c 1 B d 5 dtype: int64 In [50]: s.loc[(["A", "B"], ["c", "d"])] # tuple of lists Out[50]: A c 1 d 2 B c 4 d 5 dtype: int64
使用切片器
通过提供多个索引器可以对MultiIndex
进行切片。
你可以像通过标签索引一样提供任何选择器,参见按标签选择,包括切片、标签列表、标签和布尔索引器。
你可以使用slice(None)
来选择该级别的所有内容。你不需要指定所有更深层次的级别,它们将被隐含为slice(None)
。
与标签索引一样,切片器的两侧都包括在内。
警告
你应该在.loc
指定器中指定所有轴,即索引和列的索引器。有一些模糊的情况,传递的索引器可能被误解为同时索引两个轴,而不是例如为行的MultiIndex
。
你应该这样做:
df.loc[(slice("A1", "A3"), ...), :] # noqa: E999
你不应该这样做:
df.loc[(slice("A1", "A3"), ...)] # noqa: E999
In [51]: def mklbl(prefix, n): ....: return ["%s%s" % (prefix, i) for i in range(n)] ....: In [52]: miindex = pd.MultiIndex.from_product( ....: [mklbl("A", 4), mklbl("B", 2), mklbl("C", 4), mklbl("D", 2)] ....: ) ....: In [53]: micolumns = pd.MultiIndex.from_tuples( ....: [("a", "foo"), ("a", "bar"), ("b", "foo"), ("b", "bah")], names=["lvl0", "lvl1"] ....: ) ....: In [54]: dfmi = ( ....: pd.DataFrame( ....: np.arange(len(miindex) * len(micolumns)).reshape( ....: (len(miindex), len(micolumns)) ....: ), ....: index=miindex, ....: columns=micolumns, ....: ) ....: .sort_index() ....: .sort_index(axis=1) ....: ) ....: In [55]: dfmi Out[55]: lvl0 a b lvl1 bar foo bah foo A0 B0 C0 D0 1 0 3 2 D1 5 4 7 6 C1 D0 9 8 11 10 D1 13 12 15 14 C2 D0 17 16 19 18 ... ... ... ... ... A3 B1 C1 D1 237 236 239 238 C2 D0 241 240 243 242 D1 245 244 247 246 C3 D0 249 248 251 250 D1 253 252 255 254 [64 rows x 4 columns]
使用切片、列表和标签进行基本的 MultiIndex 切片。
In [56]: dfmi.loc[(slice("A1", "A3"), slice(None), ["C1", "C3"]), :] Out[56]: lvl0 a b lvl1 bar foo bah foo A1 B0 C1 D0 73 72 75 74 D1 77 76 79 78 C3 D0 89 88 91 90 D1 93 92 95 94 B1 C1 D0 105 104 107 106 ... ... ... ... ... A3 B0 C3 D1 221 220 223 222 B1 C1 D0 233 232 235 234 D1 237 236 239 238 C3 D0 249 248 251 250 D1 253 252 255 254 [24 rows x 4 columns]
你可以使用pandas.IndexSlice
来使用:
更自然的语法,而不是使用slice(None)
。
In [57]: idx = pd.IndexSlice In [58]: dfmi.loc[idx[:, :, ["C1", "C3"]], idx[:, "foo"]] Out[58]: lvl0 a b lvl1 foo foo A0 B0 C1 D0 8 10 D1 12 14 C3 D0 24 26 D1 28 30 B1 C1 D0 40 42 ... ... ... A3 B0 C3 D1 220 222 B1 C1 D0 232 234 D1 236 238 C3 D0 248 250 D1 252 254 [32 rows x 2 columns]
可以同时在多个轴上使用此方法执行相当复杂的选择。
In [59]: dfmi.loc["A1", (slice(None), "foo")] Out[59]: lvl0 a b lvl1 foo foo B0 C0 D0 64 66 D1 68 70 C1 D0 72 74 D1 76 78 C2 D0 80 82 ... ... ... B1 C1 D1 108 110 C2 D0 112 114 D1 116 118 C3 D0 120 122 D1 124 126 [16 rows x 2 columns] In [60]: dfmi.loc[idx[:, :, ["C1", "C3"]], idx[:, "foo"]] Out[60]: lvl0 a b lvl1 foo foo A0 B0 C1 D0 8 10 D1 12 14 C3 D0 24 26 D1 28 30 B1 C1 D0 40 42 ... ... ... A3 B0 C3 D1 220 222 B1 C1 D0 232 234 D1 236 238 C3 D0 248 250 D1 252 254 [32 rows x 2 columns]
使用布尔索引器可以提供与值相关的选择。
In [61]: mask = dfmi[("a", "foo")] > 200 In [62]: dfmi.loc[idx[mask, :, ["C1", "C3"]], idx[:, "foo"]] Out[62]: lvl0 a b lvl1 foo foo A3 B0 C1 D1 204 206 C3 D0 216 218 D1 220 222 B1 C1 D0 232 234 D1 236 238 C3 D0 248 250 D1 252 254
你还可以在.loc
中指定axis
参数,以在单个轴上解释传递的切片器。
In [63]: dfmi.loc(axis=0)[:, :, ["C1", "C3"]] Out[63]: lvl0 a b lvl1 bar foo bah foo A0 B0 C1 D0 9 8 11 10 D1 13 12 15 14 C3 D0 25 24 27 26 D1 29 28 31 30 B1 C1 D0 41 40 43 42 ... ... ... ... ... A3 B0 C3 D1 221 220 223 222 B1 C1 D0 233 232 235 234 D1 237 236 239 238 C3 D0 249 248 251 250 D1 253 252 255 254 [32 rows x 4 columns]
此外,你可以使用以下方法设置值。
In [64]: df2 = dfmi.copy() In [65]: df2.loc(axis=0)[:, :, ["C1", "C3"]] = -10 In [66]: df2 Out[66]: lvl0 a b lvl1 bar foo bah foo A0 B0 C0 D0 1 0 3 2 D1 5 4 7 6 C1 D0 -10 -10 -10 -10 D1 -10 -10 -10 -10 C2 D0 17 16 19 18 ... ... ... ... ... A3 B1 C1 D1 -10 -10 -10 -10 C2 D0 241 240 243 242 D1 245 244 247 246 C3 D0 -10 -10 -10 -10 D1 -10 -10 -10 -10 [64 rows x 4 columns]
你也可以使用可对齐对象的右侧。
In [67]: df2 = dfmi.copy() In [68]: df2.loc[idx[:, :, ["C1", "C3"]], :] = df2 * 1000 In [69]: df2 Out[69]: lvl0 a b lvl1 bar foo bah foo A0 B0 C0 D0 1 0 3 2 D1 5 4 7 6 C1 D0 9000 8000 11000 10000 D1 13000 12000 15000 14000 C2 D0 17 16 19 18 ... ... ... ... ... A3 B1 C1 D1 237000 236000 239000 238000 C2 D0 241 240 243 242 D1 245 244 247 246 C3 D0 249000 248000 251000 250000 D1 253000 252000 255000 254000 [64 rows x 4 columns] ```### 横截面 `DataFrame`的`xs()`方法另外接受一个级别参数,以便更轻松地选择`MultiIndex`的特定级别的数据。 ```py In [70]: df Out[70]: A B C first second bar one 0.895717 0.410835 -1.413681 two 0.805244 0.813850 1.607920 baz one -1.206412 0.132003 1.024180 two 2.565646 -0.827317 0.569605 foo one 1.431256 -0.076467 0.875906 two 1.340309 -1.187678 -2.211372 qux one -1.170299 1.130127 0.974466 two -0.226169 -1.436737 -2.006747 In [71]: df.xs("one", level="second") Out[71]: A B C first bar 0.895717 0.410835 -1.413681 baz -1.206412 0.132003 1.024180 foo 1.431256 -0.076467 0.875906 qux -1.170299 1.130127 0.974466
# using the slicers In [72]: df.loc[(slice(None), "one"), :] Out[72]: A B C first second bar one 0.895717 0.410835 -1.413681 baz one -1.206412 0.132003 1.024180 foo one 1.431256 -0.076467 0.875906 qux one -1.170299 1.130127 0.974466
你也可以使用xs
在列上进行选择,通过提供轴参数。
In [73]: df = df.T In [74]: df.xs("one", level="second", axis=1) Out[74]: first bar baz foo qux A 0.895717 -1.206412 1.431256 -1.170299 B 0.410835 0.132003 -0.076467 1.130127 C -1.413681 1.024180 0.875906 0.974466
# using the slicers In [75]: df.loc[:, (slice(None), "one")] Out[75]: first bar baz foo qux second one one one one A 0.895717 -1.206412 1.431256 -1.170299 B 0.410835 0.132003 -0.076467 1.130127 C -1.413681 1.024180 0.875906 0.974466
xs
还允许使用多个键进行选择。
In [76]: df.xs(("one", "bar"), level=("second", "first"), axis=1) Out[76]: first bar second one A 0.895717 B 0.410835 C -1.413681
# using the slicers In [77]: df.loc[:, ("bar", "one")] Out[77]: A 0.895717 B 0.410835 C -1.413681 Name: (bar, one), dtype: float64
你可以向xs
传递drop_level=False
以保留所选的级别。
In [78]: df.xs("one", level="second", axis=1, drop_level=False) Out[78]: first bar baz foo qux second one one one one A 0.895717 -1.206412 1.431256 -1.170299 B 0.410835 0.132003 -0.076467 1.130127 C -1.413681 1.024180 0.875906 0.974466
将上述与使用drop_level=True
(默认值)的结果进行比较。
In [79]: df.xs("one", level="second", axis=1, drop_level=True) Out[79]: first bar baz foo qux A 0.895717 -1.206412 1.431256 -1.170299 B 0.410835 0.132003 -0.076467 1.130127 C -1.413681 1.024180 0.875906 0.974466 ```### 高级重新索引和对齐 在 pandas 对象的`reindex()`和`align()`方法中使用参数`level`可以实现跨级别广播值。例如: ```py In [80]: midx = pd.MultiIndex( ....: levels=[["zero", "one"], ["x", "y"]], codes=[[1, 1, 0, 0], [1, 0, 1, 0]] ....: ) ....: In [81]: df = pd.DataFrame(np.random.randn(4, 2), index=midx) In [82]: df Out[82]: 0 1 one y 1.519970 -0.493662 x 0.600178 0.274230 zero y 0.132885 -0.023688 x 2.410179 1.450520 In [83]: df2 = df.groupby(level=0).mean() In [84]: df2 Out[84]: 0 1 one 1.060074 -0.109716 zero 1.271532 0.713416 In [85]: df2.reindex(df.index, level=0) Out[85]: 0 1 one y 1.060074 -0.109716 x 1.060074 -0.109716 zero y 1.271532 0.713416 x 1.271532 0.713416 # aligning In [86]: df_aligned, df2_aligned = df.align(df2, level=0) In [87]: df_aligned Out[87]: 0 1 one y 1.519970 -0.493662 x 0.600178 0.274230 zero y 0.132885 -0.023688 x 2.410179 1.450520 In [88]: df2_aligned Out[88]: 0 1 one y 1.060074 -0.109716 x 1.060074 -0.109716 zero y 1.271532 0.713416 x 1.271532 0.713416
使用swaplevel
交换级别
swaplevel()
方法可以交换两个级别的顺序:
In [89]: df[:5] Out[89]: 0 1 one y 1.519970 -0.493662 x 0.600178 0.274230 zero y 0.132885 -0.023688 x 2.410179 1.450520 In [90]: df[:5].swaplevel(0, 1, axis=0) Out[90]: 0 1 y one 1.519970 -0.493662 x one 0.600178 0.274230 y zero 0.132885 -0.023688 x zero 2.410179 1.450520
使用reorder_levels
重新排序级别
reorder_levels()
方法推广了swaplevel
方法,允许您一次性对分层索引级别进行排列:
In [91]: df[:5].reorder_levels([1, 0], axis=0) Out[91]: 0 1 y one 1.519970 -0.493662 x one 0.600178 0.274230 y zero 0.132885 -0.023688 x zero 2.410179 1.450520 ```### 重命名`Index`或`MultiIndex`的名称 `rename()`方法用于重命名`MultiIndex`的标签,通常用于重命名`DataFrame`的列。`rename`的`columns`参数允许指定一个包含您希望重命名的列的字典。 ```py In [92]: df.rename(columns={0: "col0", 1: "col1"}) Out[92]: col0 col1 one y 1.519970 -0.493662 x 0.600178 0.274230 zero y 0.132885 -0.023688 x 2.410179 1.450520
该方法还可用于重命名DataFrame
的主索引的特定标签。
In [93]: df.rename(index={"one": "two", "y": "z"}) Out[93]: 0 1 two z 1.519970 -0.493662 x 0.600178 0.274230 zero z 0.132885 -0.023688 x 2.410179 1.450520
rename_axis()
方法用于重命名Index
或MultiIndex
的名称。特别是,可以指定MultiIndex
级别的名称,如果稍后使用reset_index()
将值从MultiIndex
移动到列中,则这是有用的。
In [94]: df.rename_axis(index=["abc", "def"]) Out[94]: 0 1 abc def one y 1.519970 -0.493662 x 0.600178 0.274230 zero y 0.132885 -0.023688 x 2.410179 1.450520
请注意,DataFrame
的列是一个索引,因此使用带有columns
参数的rename_axis
将更改该索引的名称。
In [95]: df.rename_axis(columns="Cols").columns Out[95]: RangeIndex(start=0, stop=2, step=1, name='Cols')
rename
和rename_axis
都支持指定字典、Series
或映射函数来将标签/名称映射到新值。
在直接使用Index
对象而不是通过DataFrame
时,可以使用Index.set_names()
来更改名称。
In [96]: mi = pd.MultiIndex.from_product([[1, 2], ["a", "b"]], names=["x", "y"]) In [97]: mi.names Out[97]: FrozenList(['x', 'y']) In [98]: mi2 = mi.rename("new name", level=0) In [99]: mi2 Out[99]: MultiIndex([(1, 'a'), (1, 'b'), (2, 'a'), (2, 'b')], names=['new name', 'y'])
您无法通过级别设置MultiIndex
的名称。
In [100]: mi.levels[0].name = "name via level" --------------------------------------------------------------------------- RuntimeError Traceback (most recent call last) Cell In[100], line 1 ----> 1 mi.levels[0].name = "name via level" File ~/work/pandas/pandas/pandas/core/indexes/base.py:1690, in Index.name(self, value) 1686 @name.setter 1687 def name(self, value: Hashable) -> None: 1688 if self._no_setting_name: 1689 # Used in MultiIndex.levels to avoid silently ignoring name updates. -> 1690 raise RuntimeError( 1691 "Cannot set name on a level of a MultiIndex. Use " 1692 "'MultiIndex.set_names' instead." 1693 ) 1694 maybe_extract_name(value, None, type(self)) 1695 self._name = value RuntimeError: Cannot set name on a level of a MultiIndex. Use 'MultiIndex.set_names' instead.
使用Index.set_names()
代替。 ### 使用切片器
通过提供多个索引器,可以对MultiIndex
进行切片。
您可以提供任何选择器,就像您正在按标签进行索引一样,请参阅按标签选择,包括切片、标签列表、标签和布尔索引器。
您可以使用slice(None)
来选择该级别的所有内容。您不需要指定所有更深层次的级别,它们将被隐含为slice(None)
。
通常情况下,切片器的两侧都包含在内,因为这是标签索引。
警告
您应该在.loc
指定器中指定所有轴,即索引和列的索引器。有一些模棱两可的情况,传递的索引器可能被误解为对两个轴进行索引,而不是例如对行的MultiIndex
进行索引。
你应该这样做:
df.loc[(slice("A1", "A3"), ...), :] # noqa: E999
你不应该这样做:
df.loc[(slice("A1", "A3"), ...)] # noqa: E999
In [51]: def mklbl(prefix, n): ....: return ["%s%s" % (prefix, i) for i in range(n)] ....: In [52]: miindex = pd.MultiIndex.from_product( ....: [mklbl("A", 4), mklbl("B", 2), mklbl("C", 4), mklbl("D", 2)] ....: ) ....: In [53]: micolumns = pd.MultiIndex.from_tuples( ....: [("a", "foo"), ("a", "bar"), ("b", "foo"), ("b", "bah")], names=["lvl0", "lvl1"] ....: ) ....: In [54]: dfmi = ( ....: pd.DataFrame( ....: np.arange(len(miindex) * len(micolumns)).reshape( ....: (len(miindex), len(micolumns)) ....: ), ....: index=miindex, ....: columns=micolumns, ....: ) ....: .sort_index() ....: .sort_index(axis=1) ....: ) ....: In [55]: dfmi Out[55]: lvl0 a b lvl1 bar foo bah foo A0 B0 C0 D0 1 0 3 2 D1 5 4 7 6 C1 D0 9 8 11 10 D1 13 12 15 14 C2 D0 17 16 19 18 ... ... ... ... ... A3 B1 C1 D1 237 236 239 238 C2 D0 241 240 243 242 D1 245 244 247 246 C3 D0 249 248 251 250 D1 253 252 255 254 [64 rows x 4 columns]
使用切片、列表和标签进行基本的 MultiIndex 切片。
In [56]: dfmi.loc[(slice("A1", "A3"), slice(None), ["C1", "C3"]), :] Out[56]: lvl0 a b lvl1 bar foo bah foo A1 B0 C1 D0 73 72 75 74 D1 77 76 79 78 C3 D0 89 88 91 90 D1 93 92 95 94 B1 C1 D0 105 104 107 106 ... ... ... ... ... A3 B0 C3 D1 221 220 223 222 B1 C1 D0 233 232 235 234 D1 237 236 239 238 C3 D0 249 248 251 250 D1 253 252 255 254 [24 rows x 4 columns]
你可以使用pandas.IndexSlice
来使用:
更自然的语法,而不是使用slice(None)
。
In [57]: idx = pd.IndexSlice In [58]: dfmi.loc[idx[:, :, ["C1", "C3"]], idx[:, "foo"]] Out[58]: lvl0 a b lvl1 foo foo A0 B0 C1 D0 8 10 D1 12 14 C3 D0 24 26 D1 28 30 B1 C1 D0 40 42 ... ... ... A3 B0 C3 D1 220 222 B1 C1 D0 232 234 D1 236 238 C3 D0 248 250 D1 252 254 [32 rows x 2 columns]
使用此方法可以在同一时间在多个轴上执行相当复杂的选择。
In [59]: dfmi.loc["A1", (slice(None), "foo")] Out[59]: lvl0 a b lvl1 foo foo B0 C0 D0 64 66 D1 68 70 C1 D0 72 74 D1 76 78 C2 D0 80 82 ... ... ... B1 C1 D1 108 110 C2 D0 112 114 D1 116 118 C3 D0 120 122 D1 124 126 [16 rows x 2 columns] In [60]: dfmi.loc[idx[:, :, ["C1", "C3"]], idx[:, "foo"]] Out[60]: lvl0 a b lvl1 foo foo A0 B0 C1 D0 8 10 D1 12 14 C3 D0 24 26 D1 28 30 B1 C1 D0 40 42 ... ... ... A3 B0 C3 D1 220 222 B1 C1 D0 232 234 D1 236 238 C3 D0 248 250 D1 252 254 [32 rows x 2 columns]
使用布尔索引器可以提供与值相关的选择。
In [61]: mask = dfmi[("a", "foo")] > 200 In [62]: dfmi.loc[idx[mask, :, ["C1", "C3"]], idx[:, "foo"]] Out[62]: lvl0 a b lvl1 foo foo A3 B0 C1 D1 204 206 C3 D0 216 218 D1 220 222 B1 C1 D0 232 234 D1 236 238 C3 D0 248 250 D1 252 254
您还可以在.loc
中指定axis
参数,以在单个轴上解释传递的切片器。
In [63]: dfmi.loc(axis=0)[:, :, ["C1", "C3"]] Out[63]: lvl0 a b lvl1 bar foo bah foo A0 B0 C1 D0 9 8 11 10 D1 13 12 15 14 C3 D0 25 24 27 26 D1 29 28 31 30 B1 C1 D0 41 40 43 42 ... ... ... ... ... A3 B0 C3 D1 221 220 223 222 B1 C1 D0 233 232 235 234 D1 237 236 239 238 C3 D0 249 248 251 250 D1 253 252 255 254 [32 rows x 4 columns]
此外,您可以使用以下方法设置值。
In [64]: df2 = dfmi.copy() In [65]: df2.loc(axis=0)[:, :, ["C1", "C3"]] = -10 In [66]: df2 Out[66]: lvl0 a b lvl1 bar foo bah foo A0 B0 C0 D0 1 0 3 2 D1 5 4 7 6 C1 D0 -10 -10 -10 -10 D1 -10 -10 -10 -10 C2 D0 17 16 19 18 ... ... ... ... ... A3 B1 C1 D1 -10 -10 -10 -10 C2 D0 241 240 243 242 D1 245 244 247 246 C3 D0 -10 -10 -10 -10 D1 -10 -10 -10 -10 [64 rows x 4 columns]
你也可以使用可对齐对象的右侧。
In [67]: df2 = dfmi.copy() In [68]: df2.loc[idx[:, :, ["C1", "C3"]], :] = df2 * 1000 In [69]: df2 Out[69]: lvl0 a b lvl1 bar foo bah foo A0 B0 C0 D0 1 0 3 2 D1 5 4 7 6 C1 D0 9000 8000 11000 10000 D1 13000 12000 15000 14000 C2 D0 17 16 19 18 ... ... ... ... ... A3 B1 C1 D1 237000 236000 239000 238000 C2 D0 241 240 243 242 D1 245 244 247 246 C3 D0 249000 248000 251000 250000 D1 253000 252000 255000 254000 [64 rows x 4 columns]
Pandas 2.2 中文官方教程和指南(十二·二)(2)https://developer.aliyun.com/article/1509800