day6 多层索引与分组

MultiIndex

MultiIndex,即具有多个层次的索引,有些类似于根据索引进行分组的形式。通过多层次索引,我们就可以使用高层次的索引,来操作整个索引组的数据。

1、创建方式

第一种

我们在创建Series或DataFrame时,可以通过给index(columns)参数传递多维数组,进而构建多维索引。【数组中每个维度对应位置的元素,组成每个索引值】
多维索引的也可以设置名称(names属性),属性的值为一维数组,元素的个数需要与索引的层数相同(每层索引都需要具有一个名称)。

# 第一种
# 在创建Series或DataFrame对象时,通过index参数指定二维的数组类型。其中每个元素(一维数组类型)
# 来指定每个层次的索引内容(索引标签)。
s = pd.Series([1, 2, 3, 4], index=[["海淀区","海淀区", "昌平区", "昌平区"], ["上半年", "下半年", "上半年", "下半年"]])
s1 = pd.Series([1, 2, 3, 4], index=[["a","a", "b", "b"], ["c", "d", "c", "d"], ["e", "e", "f", "e"]])
display(s)
display(s1)
df = pd.DataFrame(np.random.rand(4, 4), index=[["上半年", "上半年", "下半年", "下半年"], ["第一季度", "第二季度", "第三季度", "第四季度"]],
                  columns=[["水果", "水果", "蔬菜", "蔬菜"], ["苹果", "香蕉", "白菜", "萝卜"]])
display(df)
display(df.index, df.columns)

在这里插入图片描述

# Series/DataFrame的索引对象可以具有名字。当索引是单层时,可以给index的name属性赋值。
s = pd.Series([1, 2, 3, 4], index=["a","a", "b", "b"], name="Series的name")
s.index.name = "index的name"
display(s)
# 当索引是多层时,可以给index的names属性赋值。(每层索引都需要具有一个名字)
s = pd.Series([1, 2, 3, 4], index=[["a","a", "b", "b"], ["c", "d", "c", "d"]], name='serises的name')
s.index.names = ["outer", "inner"]
display(s)

df = pd.DataFrame(np.random.rand(4, 4), index=[["上半年", "上半年", "下半年", "下半年"], ["第一季度", "第二季度", "第三季度", "第四季度"]],
            columns=[["水果", "水果", "蔬菜", "蔬菜"], ["苹果", "香蕉", "白菜", "萝卜"]])
display(df)
df.index.names = ["年", "季度"]
df.columns.names = ["分类", "品种"]
display(df)

在这里插入图片描述

第二种

我们可以通过MultiIndex类的相关方法,预先创建一个MultiIndex对象,然后作为Series与DataFrame中的index(或columns)参数值。同时,可以通过names参数指定多层索引的名称。

  • from_arrays:接收一个多维数组参数,高维指定高层索引,低维指定底层索引。
  • from_tuples:接收一个元组的列表,每个元组指定每个索引(高维索引,低维索引)。
  • from_product:接收一个可迭代对象的列表,根据多个可迭代对象元素的笛卡尔积进行创建索引。

from_product相对于前两个方法而言,实现相对简单,但是,也存在局限。

# 第二种创建多层索引
# 1 通过数组的方式创建。参数传递一个二维数组,每个元素(一维数组)指定相应的层次标签。(一个元素指定一个层次)
mindex = pd.MultiIndex.from_arrays([["上半年", "上半年", "下半年", "下半年"], ["第一季度", "第二季度", "第三季度", "第四季度"]],
                                  names=["年度", "季度"])
display(mindex)

# 2 通过元组的方式创建。传输传递一个(嵌套的)可迭代对象,每个元素是一个元组。
# from_arrays可以看做是纵向的方式来指定索引标签。而from_tuples可以看做是横向的方式来指定索引标签。
mindex = pd.MultiIndex.from_tuples([("上半年", "第一季度"),("上半年", "第二季度"), ("下半年", "第三季度"), ("下半年", "第四季度")])
df = pd.DataFrame(np.random.rand(4, 4), index=mindex)
display(df)

# 3 通过笛卡尔积的方式创建。传递一个嵌套的可迭代对象。每个内层的元素采用笛卡尔积的方式组合。
# 第3种方式相比与前两种方式,较简单,但是,也存在局限(必须每种组合都要存在)。
mindex = pd.MultiIndex.from_product([["2017", "2018"], ["上半年", "下半年"]])
df = pd.DataFrame(np.random.rand(4, 4), index=mindex)
display(df)

在这里插入图片描述

多层索引操作

对于多层索引,同样也支持单层索引的相关操作,例如,索引元素,切片,索引数组选择元素等。我们也可以根据多级索引,按层次逐级选择元素。
多层索引的优势:通过创建多层索引,我们就可以使用高层次的索引,来操作整个索引组的数据。

格式:

  • s[操作]
  • s.loc[操作]
  • s.iloc[操作]

其中,操作可以是索引,切片,数组索引,布尔索引。

Series多层索引

  • 通过loc(标签索引)操作,可以通过多层索引,获取该索引所对应的一组值。
  • 通过iloc(位置索引)操作,会获取对应位置的元素值(与是否多层索引无关)。
  • 通过s[操作]的行为有些诡异,建议不用。
  • 对于索引(单级),首先按照标签选择,如果标签不存在,则按照位置选择。
  • 对于多级索引,则按照标签进行选择。
  • 对于切片,如果提供的是整数,则按照位置选择,否则按照标签选择。
  • 对于数组索引, 如果数组元素都是整数,则根据位置进行索引,否则,根据标签进行索引(此时如果标签不存在,也不会出现错误)。
s = pd.Series([11, 12, 13, 14], index=[["a", "a", "b", "b"], ["1", "2", "3", "4"]])
display(s)
# 根据多层索引的外层标签,可以获取一组元素。(标签索引)
display(s.loc["a"])
# 根据标签,向下延伸
display(s.loc["a", "2"])
# 多层索引(标签)对通过位置访问元素(位置索引)没有影响。(位置索引)
display(s.iloc[0])
display(s.iloc[0:3])

# 通过标签数组访问。
display(s.loc[["a", "b"]])
# 通过布尔数组访问。
display(s[[True, False, True, False]])

在这里插入图片描述

DataFrame多层索引

  • 通过loc(标签索引)操作,可以通过多层索引,获取该索引所对应的一组值。
  • 通过iloc(位置索引)操作,会获取对应位置的一行(与是否多层索引无关)。
  • 通过s[操作]的行为有些诡异,建议不用。
  • 对于索引,根据标签获取相应的列(如果是多层索引,则可以获得多列)。
  • 对于数组索引, 根据标签,获取相应的列(如果是多层索引,则可以获得多列)。
  • 对于切片,首先按照标签进行索引,然后再按照位置进行索引(取行)。
df = pd.DataFrame(np.random.rand(4, 4), index=[["a", "a", "b", "b"], ["c", "d", "e", "f"]])
display(df)
display(df.loc["b", "e"])
# 层级索引,对通过位置索引访问元素没有影响。
display(df.iloc[0:2])

在这里插入图片描述

交换索引

我们可以调用DataFrame对象的swaplevel方法来交换两个层级索引。该方法默认对倒数第2层与倒数第1层进行交换。我们也可以指定交换的层。层次从0开始,由外向内递增(或者由上到下递增),也可以指定负值,负值表示倒数第n层。除此之外,我们也可以使用层次索引的名称来进行交换。

df = pd.DataFrame(np.random.rand(4, 4), index=[["a", "a", "b", "b"], ["c", "d", "c", "d"]])
display(df)
# 交换索引的层级,如果没有指定参数,则交换最内的两层。
display(df.swaplevel())
# 索引的层级,从外到内,依次递增,0, 1, 2……
# 索引层级,也支持负数值,从内到外,依次递减。-1,-2,……
df = pd.DataFrame(np.random.rand(4, 4), index=[["a", "a", "b", "b"], ["c", "d", "c", "d"], ["e", "f", "f", "e"]],
            columns=[["k", "k", "L", "L"], ["x", "y", "x", "y"]])
df.index.names = ["level1", "level2", "level3"]
display(df)
display(df.swaplevel(0, 2))
display(df.swaplevel(-1, -3))
# 我们也可以通过层级索引的名字,来进行访问。
display(df.swaplevel("level2", "level3"))
# 通过axis指定交换行标签(0)还是列标签(1)。
display(df.swaplevel(0, 1, axis=1))

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

索引排序

我们可以使用sort_index方法对索引进行排序处理。

  • level:指定根据哪一层进行排序,默认为最外(上)层。该值可以是数值,索引名,或者是由二者构成的列表。
  • inplace:是否就地修改。默认为False。
df = pd.DataFrame(np.random.rand(4, 4), index=[["b", "b", "a", "a"], ["d", "c", "d", "c"]])
display(df)
display(df.swaplevel())  # 索引d,c重复,不像上面的省略一个
# 索引排序
df = df.swaplevel()
#  对索引进行排序。level指定排序的层级。当我们指定一个层级时,除了对当前层级进行排序之外,对其内部的
# 层级也会进行排序。如果没有指定level,则认为是最外层。
df.sort_index()  # 默认最外层,但是里面的也会在最外层的基础上进行排序

在这里插入图片描述

# 索引排序
df = pd.DataFrame(np.random.rand(4, 4), index=[["b", "b", "a", "a"], ["d", "c", "d", "c"], ["g", "f", "e", "a"]])
df.index.names = ["level1", "level2", "level3"]
display(df)
# 默认是最外层,但是里面层也会排序
display(df.sort_index())
display(df.sort_index(level=1))  # 调整level2列,里面的level3列也会调整
# 也支持层级索引的名字进行排序。
display(df.sort_index(level="level2"))
# ascending 参数,指定是否升序排序,默认为True。axis指定对行索引(0)还是列索引(1)排序。
display(df.sort_index(ascending=False, axis=1))

在这里插入图片描述
在这里插入图片描述

索引堆叠 & 取消堆叠

通过DataFrame对象的stack方法,可以进行索引堆叠,即将指定层级的列转换成行。
level:指定转换的层级,默认为-1。

通过DataFrame对象的unstack方法,可以取消索引堆叠,即将指定层级的行转换成列。
level:指定转换的层级,默认为-1。
fill_value:指定填充值。默认为NaN。

df = pd.DataFrame(np.random.rand(4, 4), index=[["a", "a", "b", "b"],["c", "d", "c", "k"]],
                 columns=[["e", "e", "f", "f"], ["g", "h", "g", "h"]])
display(df)
# 列索引变成行索引。
display(df.stack())
# 行索引变成列索引。
display(df.unstack())  # 这里的df还是以前的df
# 在堆叠或者取消堆叠方法中,可以通过level来指定堆叠(取消堆叠)的层级,默认为-1(最内的层级)。
display(df.stack(0))
# 在取消堆叠的过程中,可能会产生空值,我们可以使用fill_value进行填充。
display(df.unstack(fill_value=-100))

在这里插入图片描述
在这里插入图片描述

设置索引

在DataFrame中,如果我们需要将现有的某一(几)列作为索引列,可以调用set_index方法来实现。

  • drop:是否丢弃作为新索引的列,默认为True。
  • append:是否以追加的方式设置索引,默认为False。
  • inplace:是否就地修改,默认为False。
df = pd.DataFrame([[1, 2, 3], [4, 5, 6]], columns=["id", "id2", "y"])
display(df)
# 设置索引列。
display(df.set_index("id"))
# 也可以将多列设置为索引列。此时,就会产生层级索引。
display(df.set_index(["id", "id2"]))
# drop参数:当设置索引列后,该列是否删除。默认为True。
display(df.set_index("id",drop=False))

# append参数:设置是否追加。默认为False(替换到之前的索引)。
display(df.set_index("id2", append=True))

在这里插入图片描述

重置索引

调用在DataFrame对象的reset_index,可以重置索引。该操作与set_index正好相反。

  • level:重置索引的层级,默认重置所有层级的索引。如果重置所有索引,将会创建默认整数序列索引。
  • drop:是否丢弃重置的索引列,默认为False。
  • inplace:是否就地修改,默认为False。
# 重置索引,可以看做是设置索引的逆操作。
df = pd.DataFrame([[1, 2, 3], [4, 5, 6]], columns=["id", "id2", "y"])
display(df)
# 设置索引
df.set_index("id", inplace=True)  # 就地修改
display(df)
# 发现设置错了,想还原,重置索引。默认会重置所有的层级。
display(df.reset_index())  # 如果是多级索引,就不会生成0,1索引


df = pd.DataFrame([[1, 2, 3], [4, 5, 6], [7, 8, 9]], index=[["h", "h", "h"], ["id", "id2", "y"]])
display(df)
# 默认会重置所有的层级。
display(df.reset_index())
# drop 参数,默认情况下,重置的索引会回到列,如果我们想要删除重置的索引,可以将drop参数
# 设置为True。
display(df.reset_index(drop=True))
# level 参数:指定重置索引的层级。
display(df.reset_index(0))
display(df.reset_index(1))

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

分组与聚合

分组与聚合操作与数据库中的分组与聚合相似。

groupby分组

我们可以通过groupby方法来对Series或DataFrame对象实现分组操作。该方法会返回一个分组对象:

  • 对于Series分组,返回SeriesGroupBy对象。
  • 对于DataFrame分组,DataFrameGroupBy对象。
df = pd.DataFrame([[1, 2, 3], [1, 5, 6], [2, 10, 9], [2, 5, 8]])
display(df)
# 对DataFrame进行分组。返回DataFrameGroupBy类型的对象。但是对象不想列表的形式,是一种类似迭代器格式
g = df.groupby(0)
display(g)
# 在DataFrameGroupBy(分组对象)取一列,就可以得到SeriesGroupBy类型的对象。
display(g[1])

在这里插入图片描述

迭代

如果直接查看(输出)该对象,并不能看到任何的分组信息(这点不同于列表类型)。不过,我们还是有能力获取分组对象的数据信息的。分组对象是可迭代对象类型(Iterable),因此,我们可以采用如下的方式进行遍历:

  • 获取迭代器,进行迭代。迭代每次会返回一个元组,第1个元素为用来分组的key,第2个元素为该组对应的数据。
  • 使用for循环来对分组对象进行迭代。

说明:

  • 对于多个字段分组,迭代返回元组的第一个元素(分组的key),依然还是一个元组。

分组对象是可迭代对象,我们无法直接看到分组对象的数据信息(这点与列表不同,类似于生成器的方式)。 如果我们需要获取分组对象的信息,可以:

  1. 获取分组对象的迭代器,然后进行遍历。
  2. 在for循环当中进行遍历。
df = pd.DataFrame([[1, 2, 3], [1, 5, 6], [2, 10, 9], [2, 5, 8]])
display(df)
# 对DataFrame进行分组。返回DataFrameGroupBy类型的对象。但是对象不想列表的形式,是一种迭代器格式
g = df.groupby(0)
display(g)
# 获取分组对象的迭代器。
g.__iter__()
# 获取下一个元素。分组对象的元素,返回一个元组。元组中第一个元素为分组的值(key)。
# 第二个元素该key值对应的数据。
i = iter(g)
item = next(i)
display(item[0], item[1])
item = next(i)
display(item[0], item[1])
# 更简单的方法(循环,推荐使用该方法)
for k, v in g:
    display(k, v)
    
# 如果根据多个字段进行分组,则用于分组的key值,依然还是一个元组。
g = df.groupby([0, 1])
for k, v in g:
    display(k, v)

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

聚合

所谓聚合,就是执行多个值变成一个值的操作。而在Python中,就是将一个矢量(数组)变成标量。
在分组之后,我们就可以调用分组对象的mean,sum等聚合函数,对每个分组进行聚合。

说明:

  • 在聚合的结果集中,默认会使用分组的键作为索引,我们可以在groupby方法中通过as_index参数来控制。
  • 我们也可以在聚合之后调用reset_index方法来实现as_index=False的功能。
df = pd.DataFrame([[1, 2, 3], [1, 5, 6], [2, 10, 9], [2, 5, 8]])
display(df)
# 在分组之后,我们就可以在分组对象上,执行聚合操作。
g = df.groupby(0)
display(g.sum())
# 如果仅对其中一列感兴趣,可以从DataFrameGroupBy中提取一列,变成SeriesGroupBy。
display(g[2].sum())

# 默认情况下,用于分组的key值,会充当结果数据的索引。如果不想令其从当索引,可以
# 将as_index参数设置为False。(该参数默认值为True。)
g = df.groupby(0, as_index=False)
r = g.sum()
display(r)
# 通过调用reset_index方法来实现as_index=False的功能。
display(r.reset_index())

在这里插入图片描述

分组对象的属性与方法

  • groups(属性) 返回一个字典类型对象,包含分组信息。
  • size 返回每组记录的数量。
  • discribe 分组查看统计信息。
  • get_group 接受一个组名(key),返回该组对应的数据。
df = pd.DataFrame([[1, 2, 3], [1, 5, 6], [2, 10, 9], [2, 5, 8]])
display(df)
# group对象的属性与方法。
g = df.groupby(0)
# 返回一个字典类型。包含分组数据的信息。
display(g.groups)
# 返回每个分组的记录数。
display(g.size())
# 显示每个分组的统计信息。
display(g.describe())
# 根据分组的key值,返回对应分组的数据。
display(g.get_group(1))

在这里插入图片描述
在这里插入图片描述

分组的方式

通过by参数进行分组

使用groupby进行分组时,通过参数by指定分组,参数by可以是如下的形式:

  • 字符串或字符串数组:指定分组的列名或索引名。(如果索引没有命名,可以使用pd.Grouper(level=1)来指定索引的层级)
  • 字典或Series:key指定索引,value指定分组依据,即value值相等的,会分为一组。
  • 数组(列表):会根据数组的值进行对位分组。长度需要与列(行)相同。
  • 函数:接受索引,返回分组依据的value值。

说明:

  • 使用groupby分组时,可以使用sort参数指定是否对分组的key进行排序,默认为True(指定False可以提高性能)。

通过level参数进行分组

我们也可以通过level指定索引的层级,groupby会将该层级索引值相同的数据进行分组。level可以是整数值,索引名。

# 1 传递列或索引的标签。(也可以传递多个标签)
df = pd.DataFrame([[3, 2, 3], [3, 5, 6], [2, 10, 9], [2, 5, 8]], columns=list("abc"))
df.index.name = "index_name"
display(df)
g = df.groupby("a")
for k,v in g:
    display(k,v)
    
# 根据索引名进行分组。
g = df.groupby("index_name")
for k,v in g:
    display(k,v)
    
# 如果索引没有名字,可以借助与Grouper类型对象进行分组。(用的少)
df = pd.DataFrame([[3, 2, 3], [3, 5, 6], [2, 10, 9], [2, 5, 8]], columns=list("abc"))
# level指定用于分组索引的层级。
grouper = pd.Grouper(level=0)  # 这里df只有一层0,1,2,3,4,所以设置0
g = df.groupby(grouper)
for k,v in g:
    display(k,v)
# key只用用于分组的类标签。相当于执行df.groupby("a")
grouper = pd.Grouper(key="a")
g = df.groupby(grouper)
for k,v in g:
    display(k,v)

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

# groupby进行分组
# 2 传递一个字典或者Series。字典中每个key指定DataFrame中的标签(索引),value指定该便签对应的分组。
# 然后,会将value值相同的标签分到一组。
df = pd.DataFrame([[3, 2, 3], [3, 5, 6], [2, 10, 9], [2, 5, 8]], columns=list("abc"))
df.index.name = "index_name"
display(df)
g = df.groupby({0: "组1", 1: "组2", 2: "组1", 3: "组2"})
for k,v in g:
    display(k,v)
# 分组的时候,我们还可以根据列进行组合分组。
g = df.groupby({"a": 0, "b": 0, "c": 1}, axis=1)
for k,v in g:
    display(k,v)
# 通过传递Series进行分组。(同上,a,b对应0,c对应1)
g = df.groupby(pd.Series([0, 0, 1], index=["a", "b", "c"]), axis=1)
for k,v in g:
    display(k,v)

在这里插入图片描述
在这里插入图片描述

# 3 根据数组进行分组。将数组中元素值相同的,会划分到一个分组当中。
df = pd.DataFrame([[3, 2, 3], [3, 5, 6], [2, 10, 9], [2, 5, 8]], columns=list("abc"))
df.index.name = "index_name"
display(df)
# 按照行,4行就4个
g = df.groupby([1, 2, 1, 2])  # 【5,6,5,6】具体数字不重要,重要的是哪两个相等
for k,v in g:
    display(k,v)
# 按照列 3列,所以3个数
g = df.groupby([0, 0, 5], axis=1)
for k,v in g:
    display(k,v)

在这里插入图片描述
在这里插入图片描述

# 4 根据函数进行分组。该函数fun需要具有一个参数,用来接收每个索引(行标签或者列标签)。
# 同时,函数需要具有返回值。返回值指定参数索引对应的分组。相同的返回值会划分到同一个组中。
df = pd.DataFrame([[3, 2, 3], [3, 5, 6], [2, 10, 9], [2, 5, 8]], columns=list("abc"))
df.index.name = "index_name"
display(df)
# 奇数标签%2为1,偶数%2为0,相当于奇数分一组,偶数分一组(相同的返回值在一起)
def fun(item):
    return item % 2
    
g = df.groupby(fun)
for k,v in g:
    display(k,v)

# 默认情况下,groupby产生的分组,会根据分组的key值进行排序。我们可以通过指定sort参数为False(默认为True)禁止排序。
# 禁止排序可以提高一定的性能。
g = df.groupby("a")  # 2在前,3在后
for k, v in g:
    display(k, v)
    
g = df.groupby("a", sort=False)
for k, v in g:
    display(k, v)

在这里插入图片描述
在这里插入图片描述

agg聚合(实现自定义的聚合)

我们可以使用DataFrame或者分组对象的agg / aggregate方法实现多个聚合操作。
方法可以接受如下形式:

  • 字符串函数名
  • 函数对象
  • 列表 可提供多个函数(函数名),进行多种聚合。
  • 字典 可针对不同的列实现不同的聚合方式。

说明:

  • 对于分组对象,会使用函数名作为聚合之后的列名。如果需要自定义列名,可以提供元组的列表,格式为:
    [(列名1, 聚合函数1), (列名2, 聚合函数2), ……]
df = pd.DataFrame([[3, 2, 3], [3, 5, 6], [2, 10, 9], [2, 5, 8]], columns=list("abc"))
df.index.name = "index_name"
display(df)
# 提供函数名实现聚合
display(df.mean())
display(df.agg('mean'))
g = df.groupby('a')
display(g.agg('mean'))
# 提供函数对象实现聚合
display(g.agg(np.mean))
# 提供一个列表,对多个指标进行聚合操作
display(g.agg(['max','min','mean']))
# 自定义名字,不用max,min,mean
display(g.agg([('最大值','max'),('最小值','min'),('平均值','mean')]))
# 字典 可针对不同的列实现不同的聚合方式。
display(g.agg({'b':'max','c':'min'}))
display(g.agg({'b':['max','sum'],'c':['min','mean']}))

在这里插入图片描述
在这里插入图片描述

apply

对分组对象,可以调用apply函数,apply函数需要传入一个操作函数,该函数会依次接收每个分组的数据,并在函数体中进行处理,返回处理之后的结果。
最后,apply会将每个分组调用函数的返回结果合并(concat),作为最终的处理结果。

说明:

  • apply的函数的参数函数除了必要的一个参数(用来接收每个分组的数据)外,还可以定义额外的参数。其他参数可以在调用apply时,一并传入(置于参数函数的后面)。
  • 在apply分组中,传入每个组的数据,name属性为该分组键的值。
df = pd.DataFrame([[3, 2, 3], [3, 5, 6], [2, 10, 9], [2, 5, 8]], columns=list("abc"))
df.index.name = "index_name"
display(df)
g = df.groupby('a')
# 在分组对象上调用apply方法,该方法参数为一个函数fun,fun需要定义一个参数,用来接受每一个分组数据。
# 函数局域明确的返回值,返回值为对传递进行的分组数据进行处理之后的结果。
def fun(item):
    return item.max()- item.min()
display(g.apply(fun))

def fun(item):
    return item.describe()
display(g.apply(fun))

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值