Python数据分析【pandas的基础使用】

1.前言

pandas所包含的数据结构和数据处理工具的设计使得在Python中进行数据清洗和分析非常快捷。pandas经常是和其他数值计算工具,比如Numpy和Scipy,以及数据可视化工具比如matplotlib一起使用的。pandas支持大部分Numpy语言风格的数组计算,尤其是数组函数以及没有for循环的各种数据处理。

尽管pandas采用了很多Numpy的代码风格,但最大的不同在于pandas是用来处理表格型或异质性数据的。而Numpy则相反,它更适合处理同质型的数值类数组数据。

 

2.pandas数据结构介绍

为了入门pandas,需要熟悉两个常用的工具数据结构:Series和DataFrame。尽管它们并不能解决所有的问题。但它们为大多数应用提供了一个有效、易用的基础。

2.1Series

Series是一种一维的数组型对象,它包含了一个值序列(与Numpy中的类型相似),并且包含了数据标签,称为索引(index)。最简单的序列可以仅仅由一个数组形成:

In [3]: obj = pd.Series([4, 7, -5, 3])

In [4]: obj
Out[4]:
0    4
1    7
2   -5
3    3
dtype: int64

交互式环境中的Series的字符串表示,索引在左边,值在右边。由于我们不为数据指定索引,默认生成的索引是从0到N-1(N是数据的长度)。可以通过values属性和index属性分别获得Series对象的值和索引:

In [5]: obj.values
Out[5]: array([ 4,  7, -5,  3], dtype=int64)

In [6]: obj.index
Out[6]: RangeIndex(start=0, stop=4, step=1)

通常需要创建一个索引系列,用标签标识每个数据点:

In [7]: obj2 = pd.Series([4, 7, -5, 3], index=['g', 's', 'a', 'f'])

In [8]: obj2
Out[8]:
g    4
s    7
a   -5
f    3
dtype: int64

In [9]: obj2.index
Out[9]: Index(['g', 's', 'a', 'f'], dtype='object')

与Numpy的数组相比,我们可以在从数据中选择数据的时候使用标签来进行索引:

In [10]: obj2['a']
Out[10]: -5

In [11]: obj2['s'] = 6

In [13]: obj2[['g', 's', 'f']]
Out[13]:
g    4
s    6
f    3
dtype: int64

上面的例子中,['g', 's', 'f']包含的不是数字而是字符串,作为索引列表。

使用Numpy的函数或Numpy风格的操作,比如使用布尔值数组进行过滤,与标量相乘,或是应用数学函数,这些操作将保存索引值连接:

In [14]: obj2[obj2 > 0]
Out[14]:
g    4
s    6
f    3
dtype: int64

In [15]: obj2 * 2
Out[15]:
g     8
s    12
a   -10
f     6
dtype: int64

从另一个角度考虑Series,可以认为它是一个长度固定且有序的字典,因为它将索引值和数据值按位置配对。在可能使用字典的上下文中,也可以使用Series:

In [2]: obj2 = pd.Series([4, 2, 3, 5], index=['d', 'b', 'a', 'c'])

In [3]: 'b' in obj2
Out[3]: True

In [4]: 'e' in obj2
Out[4]: False

如果已经有数据包含在Python字典中,你可以使用字典生成一个Series:

In [5]: sdata = {'Ohio': 35000, 'Texas': 71000, 'Oregon': 16000, 'Utah': 5000}

In [6]: obj3 = pd.Series(sdata)

In [7]: obj3
Out[7]:
Ohio      35000
Texas     71000
Oregon    16000
Utah       5000
dtype: int64

当把字典传递给Series构造函数时,产生的Series的索引将是排序好的字典键。可以将字典键按照想要的顺序传递给构造函数,从而使生成的Series的索引顺序符合预期:

In [8]: states = ['California', 'Ohio', 'Oregon', 'Texas']

In [9]: obj4 = pd.Series(sdata, index=states)

In [10]: obj4
Out[10]:
California        NaN
Ohio          35000.0
Oregon        16000.0
Texas         71000.0
dtype: float64

上面的例子中,sdata中的三个值被放置在正确的位置,但是因为'California'没有出现在sdata的键中,它对应的值是NaN(not a number),这是pandas中标记缺失值或NA值的方式。因为'Utah' 并不在states中,它被排除在结果对象外。

pandas中使用isnull和notnull函数来检查缺失数据:

In [11]: pd.isnull(obj4)
Out[11]:
California     True
Ohio          False
Oregon        False
Texas         False
dtype: bool

In [12]: pd.notnull(obj4)
Out[12]:
California    False
Ohio           True
Oregon         True
Texas          True
dtype: bool

isnull和notnull也是Series的实例方法:

In [13]: obj4.isnull()
Out[13]:
California     True
Ohio          False
Oregon        False
Texas         False
dtype: bool

对于很多应用来说,在数学操作中自动对齐索引是Series的一个非常有用的特性:

In [14]: obj3
Out[14]:
Ohio      35000
Texas     71000
Oregon    16000
Utah       5000
dtype: int64

In [15]: obj4
Out[15]:
California        NaN
Ohio          35000.0
Oregon        16000.0
Texas         71000.0
dtype: float64

In [16]: obj3 + obj4
Out[16]:
California         NaN
Ohio           70000.0
Oregon         32000.0
Texas         142000.0
Utah               NaN
dtype: float64

Series对象自身和其索引都有name属性,这个特性与pandas其他重要功能集成在一起:

In [18]: obj4.name = 'population'

In [19]: obj4.index.name = 'state'

In [20]: obj4
Out[20]:
state
California        NaN
Ohio          35000.0
Oregon        16000.0
Texas         71000.0
Name: population, dtype: float64

Series的索引可以通过按位置赋值的方式进行改变:

In [23]: obj
Out[23]:
0    4
1    7
2   -5
3    3
dtype: int64

In [24]: obj.index = ['Bob', 'Steve', 'Jeff', 'Ryan']

In [25]: obj
Out[25]:
Bob      4
Steve    7
Jeff    -5
Ryan     3
dtype: int64

2.2DataFrame

DataFrame表示的是矩阵的数据表,它包含已排序的列集合,每一列可以是不同的值类型(数值,字符串,布尔值等)。DataFrame既有行索引也有列索引,它可以被视为一个共享相同索引的Series字典。在DataFrame中,数据被存储为一个以上的二维块,而不是列表、字典或其他一维数组的集合。

有很多种方式可以创建DataFrame,其中最常用的方式是利用包含等长度的列表或Numpy数组的字典来形成DataFrame:

In [27]: data = {'state': ['Ohio', 'Ohio', 'Ohio', 'Nevada', 'Nevada', 'Nevada'], 'year': [2000, 2001, 2002, 2001, 2002
    ...: , 2003], 'pop': [1.5, 1.7, 3.6, 2.4, 2.9, 3.2]}


In [29]: frame = pd.DataFrame(data)

产生的DataFrame会自动为Series分配索引,并且列会按照排序的顺序排列:

In [30]: frame
Out[30]:
    state  year  pop
0    Ohio  2000  1.5
1    Ohio  2001  1.7
2    Ohio  2002  3.6
3  Nevada  2001  2.4
4  Nevada  2002  2.9
5  Nevada  2003  3.2

对于大型的DataFrame,head方法将会只选出头部的五行:

In [31]: frame.head()
Out[31]:
    state  year  pop
0    Ohio  2000  1.5
1    Ohio  2001  1.7
2    Ohio  2002  3.6
3  Nevada  2001  2.4
4  Nevada  2002  2.9

如果指定了列的顺序,DataFrame的列将会按照指定的顺序排列:

In [32]: pd.DataFrame(data, columns=['year', 'state', 'pop'])
Out[32]:
   year   state  pop
0  2000    Ohio  1.5
1  2001    Ohio  1.7
2  2002    Ohio  3.6
3  2001  Nevada  2.4
4  2002  Nevada  2.9
5  2003  Nevada  3.2

如果传的列不包含在字典中,将会在结果中出现缺失值:

In [33]: frame2 = pd.DataFrame(data, columns=['year', 'state', 'pop', 'debt'], index=['one', 'two', 'three', 'four', 'f
    ...: ive', 'six'])

In [34]: frame2
Out[34]:
       year   state  pop debt
one    2000    Ohio  1.5  NaN
two    2001    Ohio  1.7  NaN
three  2002    Ohio  3.6  NaN
four   2001  Nevada  2.4  NaN
five   2002  Nevada  2.9  NaN
six    2003  Nevada  3.2  NaN

In [35]: frame2.columns
Out[35]: Index(['year', 'state', 'pop', 'debt'], dtype='object')

DataFrame中的一列,可以按字典型标记或属性那样检索为Series:

In [36]: frame2['state']
Out[36]:
one        Ohio
two        Ohio
three      Ohio
four     Nevada
five     Nevada
six      Nevada
Name: state, dtype: object

In [37]: frame2.year
Out[37]:
one      2000
two      2001
three    2002
four     2001
five     2002
six      2003
Name: year, dtype: int64

注意:frame2[column]对于任意列名均有效,但是frame2.column只会在列名是有效的Python变量名时有效。

注意:返回的Series与原DataFrame有相同的索引,且Series的name属性也会被合理地设置。

列的引用是可以修改的。例如,空的'debt'列可以赋值为标量值或值数组:

In [38]: frame2['debt'] = 16.5

In [39]: frame2
Out[39]:
       year   state  pop  debt
one    2000    Ohio  1.5  16.5
two    2001    Ohio  1.7  16.5
three  2002    Ohio  3.6  16.5
four   2001  Nevada  2.4  16.5
five   2002  Nevada  2.9  16.5
six    2003  Nevada  3.2  16.5

In [42]: frame2['debt'] = np.arange(6.)

In [43]: frame2
Out[43]:
       year   state  pop  debt
one    2000    Ohio  1.5   0.0
two    2001    Ohio  1.7   1.0
three  2002    Ohio  3.6   2.0
four   2001  Nevada  2.4   3.0
five   2002  Nevada  2.9   4.0
six    2003  Nevada  3.2   5.0

当将列表或数组赋值给一个列时,值的长度必须和DataFrame的长度相匹配。如果将Series赋值给一列时,Series的索引将会按照DataFrame的索引重新排列,并在空缺的地方填充缺失值:

In [44]: val = pd.Series([-1.2, -1.5, -1.7], index=['two', 'four', 'five'])

In [45]: frame2['debt'] = val

In [46]: frame2
Out[46]:
       year   state  pop  debt
one    2000    Ohio  1.5   NaN
two    2001    Ohio  1.7  -1.2
three  2002    Ohio  3.6   NaN
four   2001  Nevada  2.4  -1.5
five   2002  Nevada  2.9  -1.7
six    2003  Nevada  3.2   NaN

如果被赋值的列并不存在,则会生成一个新的列。del关键字可以像在字典中那样对DataFrame删除列。

在del的例子中,首先增加一列,这一列是布尔值,判断条件是state列是否为'ohio':

In [47]: frame2['eastern'] = frame2.state == 'Ohio'

In [48]: frame2
Out[48]:
       year   state  pop  debt  eastern
one    2000    Ohio  1.5   NaN     True
two    2001    Ohio  1.7  -1.2     True
three  2002    Ohio  3.6   NaN     True
four   2001  Nevada  2.4  -1.5    False
five   2002  Nevada  2.9  -1.7    False
six    2003  Nevada  3.2   NaN    False

注意:frame2.eastern的语法无法创建新的列。

del方法可以用于移除之前新建的列:

In [49]: del frame2['eastern']

In [50]: frame2.columns
Out[50]: Index(['year', 'state', 'pop', 'debt'], dtype='object')

注意:从DataFrame中选取的列是数据的视图,而不是拷贝。因此,对Series的修改会映射到DataFrame中。如果需要复制,则应当显式地使用Series的copy方法。

另一种常见的数据形式是包含字典的嵌套字典:

In [51]: pop = {'Nevada': {2001: 2.4, 2002: 2.9}, 'Ohio': {2000: 1.5, 2001: 1.7, 2002: 3.6}}

如果嵌套字典被赋值给DataFrame,pandas会将字典的键作为列,将内部字典的键作为行索引:

In [52]: frame3 = pd.DataFrame(pop)

In [53]: frame3
Out[53]:
      Nevada  Ohio
2000     NaN   1.5
2001     2.4   1.7
2002     2.9   3.6

可以使用类似Numpy的语法对DataFrame进行转置操作(调换行和列):

In [54]: frame3.T
Out[54]:
        2000  2001  2002
Nevada   NaN   2.4   2.9
Ohio     1.5   1.7   3.6

包含Series的字典也可以用于构造DataFrame:

In [57]: pdata = {'Ohio': frame3['Ohio'][:-1], 'Nevada': frame3['Nevada'][: 2]}

In [58]: pd.DataFrame(pdata)
Out[58]:
      Ohio  Nevada
2000   1.5     NaN
2001   1.7     2.4

如果DataFrame的索引和列拥有name属性,则这些name属性也会被显示:

In [59]: frame3.index.name = 'year';frame3.columns.name = 'state'

In [60]: frame3
Out[60]:
state  Nevada  Ohio
year
2000      NaN   1.5
2001      2.4   1.7
2002      2.9   3.6

和Series类似,DataFrame的values属性会将包含在DataFrame中的二进制数据以二维ndarray的形式返回:

In [61]: frame3.values
Out[61]:
array([[nan, 1.5],
       [2.4, 1.7],
       [2.9, 3.6]])

如果DataFrame的列是不同的dtypes,则values的dtype会自动选择适合所有列的类型:

In [62]: frame2.values
Out[62]:
array([[2000, 'Ohio', 1.5, nan],
       [2001, 'Ohio', 1.7, -1.2],
       [2002, 'Ohio', 3.6, nan],
       [2001, 'Nevada', 2.4, -1.5],
       [2002, 'Nevada', 2.9, -1.7],
       [2003, 'Nevada', 3.2, nan]], dtype=object)

DataFrame构造函数的有效输入表

da31fc1accef4c8289968e5d2bd075c8.jpeg

2.3索引对象

pandas中的索引对象是用于存储轴标签和其他元数据的(例如轴名称或标签)。在构造Series或DataFrame时,你所使用的任意数组或标签序列都可以在内部转换为索引对象:

In [63]: obj = pd.Series(range(3), index=['a', 'b', 'c'])

In [64]: index = obj.index

In [65]: index
Out[65]: Index(['a', 'b', 'c'], dtype='object')

In [66]: index[1: ]
Out[66]: Index(['b', 'c'], dtype='object')

索引对象是不可变的,因此用户是无法修改索引对象的。

不变性使得在多种数据结构中分享索引对象更为安全:

In [67]: labels = pd.Index(np.arange(3))

In [68]: labels
Out[68]: Int64Index([0, 1, 2], dtype='int64')

In [69]: obj2 = pd.Series([1.5, -2.5, 0], index=labels)

In [70]: obj2
Out[70]:
0    1.5
1   -2.5
2    0.0
dtype: float64

In [71]: obj2.index is labels
Out[71]: True

除了类似数组,索引对象也像一个固定大小的集合:

In [72]: frame3
Out[72]:
state  Nevada  Ohio
year
2000      NaN   1.5
2001      2.4   1.7
2002      2.9   3.6

In [73]: frame3.columns
Out[73]: Index(['Nevada', 'Ohio'], dtype='object', name='state')

In [74]: 'Ohio' in frame3.columns
Out[74]: True

In [75]: 2003 in frame3.index
Out[75]: False

与Python集合不同,pandas索引对象可以包含重复标签:

In [76]: dup_labels = pd.Index(['foo', 'foo', 'bar', 'bar'])

In [77]: dup_labels
Out[77]: Index(['foo', 'foo', 'bar', 'bar'], dtype='object')

根据重复标签进行筛选,会选取所有重复标签对应的数据。

一些索引对象的方法和属性表

f9a55c9b019a476aa05c7f94de077d9e.jpeg

 

3.基本功能

3.1重建索引

reindex是pandas对象的重要方法,该方法用于创建一个符合新索引的新对象。考虑下面例子:

In [78]: obj = pd.Series([4.5, 7.2, -5.3, 3.6], index=['d', 'b', 'a', 'c'])

In [79]: obj
Out[79]:
d    4.5
b    7.2
a   -5.3
c    3.6
dtype: float64

Series调用reindex方法时,会将数据按照新的索引进行排列,如果某个索引值之前并不存在,则会引入缺失值:

In [80]: obj2 = obj.reindex(['a', 'b', 'c', 'd', 'e'])

In [81]: obj2
Out[81]:
a   -5.3
b    7.2
c    3.6
d    4.5
e    NaN
dtype: float64

对于顺序数据,比如时间序列,在重建索引时可能会需要进行插值或填值。method可选参数允许使用诸如ffill等方法在重建索引时插值,ffill方法会将值前向填充:

In [82]: obj3 = pd.Series(['blue', 'purple', 'yellow'], index=[0, 2, 4])

In [83]: obj3
Out[83]:
0      blue
2    purple
4    yellow
dtype: object

In [84]: obj3.reindex(range(6), method='ffill')
Out[84]:
0      blue
1      blue
2    purple
3    purple
4    yellow
5    yellow
dtype: object

在DataFrame中,reindex可以改变行索引、列索引,也可以同时改变二者。当仅传入一个序列时,结果中的行会重建索引:

In [85]: frame = pd.DataFrame(np.arange(9).reshape((3, 3)), index=['a', 'c', 'd'], columns=['Ohio', 'Texas', 'Californi
    ...: a'])

In [86]: frame
Out[86]:
   Ohio  Texas  California
a     0      1           2
c     3      4           5
d     6      7           8

In [87]: frame2 = frame.reindex(['a', 'b', 'c', 'd'])

In [88]: frame2
Out[88]:
   Ohio  Texas  California
a   0.0    1.0         2.0
b   NaN    NaN         NaN
c   3.0    4.0         5.0
d   6.0    7.0         8.0

列可以使用columns关键字重建索引:

In [89]: states = ['Texas', 'Utah', 'California']

In [90]: frame.reindex(columns=states)
Out[90]:
   Texas  Utah  California
a      1   NaN           2
c      4   NaN           5
d      7   NaN           8

可以使用loc进行更为简洁的标签索引,许多用户更倾向于使用这种方式:

In [91]: frame.loc[['a', 'b', 'c', 'd'], states]
Out[91]:
   Texas  Utah  California
a    1.0   NaN         2.0
b    NaN   NaN         NaN
c    4.0   NaN         5.0
d    7.0   NaN         8.0

reindex方法的参数表

0229eb553ae240bfa21d262dc097c790.jpeg

7c5aba62be604a6c874db0222c598bbe.jpeg

3.2轴向上删除条目

如果已经拥有索引数组或不含条目的列表,在轴向上删除一个或更多的条目就非常容易,但这样需要一些数据操作和集合逻辑,drop方法会返回一个含有指示值或轴向上删除值的新对象:

In [3]: obj = pd.Series(np.arange(5.), index=['a', 'b', 'c', 'd', 'e'])

In [4]: obj
Out[4]:
a    0.0
b    1.0
c    2.0
d    3.0
e    4.0
dtype: float64

In [5]: new_obj = obj.drop('c')

In [6]: new_obj
Out[6]:
a    0.0
b    1.0
d    3.0
e    4.0
dtype: float64

In [8]: obj.drop(['d', 'c'])
Out[8]:
a    0.0
b    1.0
e    4.0
dtype: float64

在DataFrame中,索引值可以从轴向上删除。为了表明这个特性,我们首先创建一个示例DataFrame:

In [9]: data = pd.DataFrame(np.arange(16).reshape((4, 4)), index=['Ohio', 'Colorado', 'Utah', 'New York'], columns=['on
   ...: e', 'two', 'three', 'four'])

In [10]: data
Out[10]:
          one  two  three  four
Ohio        0    1      2     3
Colorado    4    5      6     7
Utah        8    9     10    11
New York   12   13     14    15

在调用drop时使用标签序列会根据行标签删除值(轴0):

In [11]: data.drop(['Colorado', 'Ohio'])
Out[11]:
          one  two  three  four
Utah        8    9     10    11
New York   12   13     14    15

可以通过传递axis=1或者axis='columns'来从列中删除值:

In [12]: data.drop('two', axis='columns')
Out[12]:
          one  three  four
Ohio        0      2     3
Colorado    4      6     7
Utah        8     10    11
New York   12     14    15

很多函数,例如drop,注意inplace参数,会修改Series或DataFrame的尺寸或形状,这些方法直接操作原对象而不返回新对象:

In [14]: obj.drop('c', inplace=True)

In [15]: obj
Out[15]:
a    0.0
b    1.0
d    3.0
e    4.0
dtype: float64

注意inplace属性,它会清除被删除的数据。

3.3索引、选择和过滤

Series的索引与Numpy数组索引的功能类似,只不过Series的索引值可以不仅仅是整数。相关示例如下:

In [3]: obj = pd.Series(np.arange(4.), index=['a', 'b', 'c', 'd'])

In [4]: obj
Out[4]:
a    0.0
b    1.0
c    2.0
d    3.0
dtype: float64

In [5]: obj['b']
Out[5]: 1.0

In [6]: obj[1]
Out[6]: 1.0

In [7]: obj[2: 4]
Out[7]:
c    2.0
d    3.0
dtype: float64

In [8]: obj[['b', 'a', 'd']]
Out[8]:
b    1.0
a    0.0
d    3.0
dtype: float64

In [9]: obj[[1, 3]]
Out[9]:
b    1.0
d    3.0
dtype: float64

In [10]: obj[obj < 2]
Out[10]:
a    0.0
b    1.0
dtype: float64

普通的Python切片中是不包含尾部的,Series切片有点不同,当使用正常的整数切片也是不包含尾部,不过当使用像字符来进行切片的时候就会不一样:

In [11]: obj[1: 3]
Out[11]:
b    1.0
c    2.0
dtype: float64

In [12]: obj['b': 'c']
Out[12]:
b    1.0
c    2.0
dtype: float64

使用这些方法设值时会修改Series相应的部分:

In [13]: obj['b': 'c'] = 5

In [14]: obj
Out[14]:
a    0.0
b    5.0
c    5.0
d    3.0
dtype: float64

使用单个值或序列,可以从DataFrame中索引一个或多个列:

In [17]: data = pd.DataFrame(np.arange(16.).reshape((4, 4)), index=['Ohio', 'Colorado', 'Utah', 'New York'], columns=['
    ...: one', 'two', 'three', 'four'])

In [18]: data
Out[18]:
           one   two  three  four
Ohio       0.0   1.0    2.0   3.0
Colorado   4.0   5.0    6.0   7.0
Utah       8.0   9.0   10.0  11.0
New York  12.0  13.0   14.0  15.0

In [19]: data['two']
Out[19]:
Ohio         1.0
Colorado     5.0
Utah         9.0
New York    13.0
Name: two, dtype: float64

In [20]: data[['three', 'one']]
Out[20]:
          three   one
Ohio        2.0   0.0
Colorado    6.0   4.0
Utah       10.0   8.0
New York   14.0  12.0

这种索引方式也有特殊案例。首先,可以根据一个布尔值数组切片或选择数据:

In [21]: data[: 2]
Out[21]:
          one  two  three  four
Ohio      0.0  1.0    2.0   3.0
Colorado  4.0  5.0    6.0   7.0

In [22]: data[data['three'] > 2]
Out[22]:
           one   two  three  four
Colorado   4.0   5.0    6.0   7.0
Utah       8.0   9.0   10.0  11.0
New York  12.0  13.0   14.0  15.0

行选择语法data[: 2]非常方便。传递单个元素或一个列表[]符号中可以选择列。

另一个用例是使用布尔值DataFrame进行索引,布尔值DataFrame可以是对标量值进行比较产生的:

In [23]: data < 5
Out[23]:
            one    two  three   four
Ohio       True   True   True   True
Colorado   True  False  False  False
Utah      False  False  False  False
New York  False  False  False  False

In [24]: data[data < 5] = 0

In [25]: data
Out[25]:
           one   two  three  four
Ohio       0.0   0.0    0.0   0.0
Colorado   0.0   5.0    6.0   7.0
Utah       8.0   9.0   10.0  11.0
New York  12.0  13.0   14.0  15.0

3.3.1使用loc和iloc选择数据

针对DataFrame在行上的标签索引,将介绍特殊的索引符号loc和iloc。它们允许使用轴标签(loc)或整数标签(iloc)以Numpy风格的语法从DataFrame中选出数组的行和列的子集。

通过标签选出单行多列的数据作为基础示例:

In [26]: data.loc['Colorado', ['two', 'three']]
Out[26]:
two      5.0
three    6.0
Name: Colorado, dtype: float64

然后使用整数标签iloc进行类似的数据选择:

In [27]: data.iloc[2, [3, 0, 1]]
Out[27]:
four    11.0
one      8.0
two      9.0
Name: Utah, dtype: float64

In [28]: data.iloc[2]
Out[28]:
one       8.0
two       9.0
three    10.0
four     11.0
Name: Utah, dtype: float64

In [29]: data.iloc[[1, 2], [3, 0, 1]]
Out[29]:
          four  one  two
Colorado   7.0  0.0  5.0
Utah      11.0  8.0  9.0

除了单个标签或标签列表之外,索引功能还可以用于切片:

In [30]: data.loc[:'Utah', 'two']
Out[30]:
Ohio        0.0
Colorado    5.0
Utah        9.0
Name: two, dtype: float64

In [31]: data.iloc[:, : 3][data.three > 5]
Out[31]:
           one   two  three
Colorado   0.0   5.0    6.0
Utah       8.0   9.0   10.0
New York  12.0  13.0   14.0

因此,有多种方式可以选择、重排pandas对象中的数据。

DataFrame索引选项表

8cb10abc4a014945b00598ca4cfc07f2.jpeg

78880096b3d242388f240d1d62c758b7.jpeg

3.4整数索引

在pandas对象上使用整数索引对新用户来说经常会产生歧义,这是因为它和在列表、元组等Python内建数据结构上进行索引有些许不同。例如,你可能会认为下面的代码会产生错误:

In [32]: ser = pd.Series(np.arange(3.))

In [33]: ser
Out[33]:
0    0.0
1    1.0
2    2.0
dtype: float64

In [34]: ser[-1]

在上面的例子中,pandas可以“回退”到整数索引,但是这样的方式难免会引起一些微小的错误。假设我们有一个索引,它包含了0、1、2,但是推断用户所需要的索引方式(标签索引或位置索引)是很难的。

另一方面,对于非整数索引,则不会有潜在的歧义。

为了更精确地处理,可以使用loc(用于标签)或iloc(用于整数):

In [37]: ser[: 1]
Out[37]:
0    0.0
dtype: float64

In [38]: ser.loc[: 1]
Out[38]:
0    0.0
1    1.0
dtype: float64

In [39]: ser.iloc[: 1]
Out[39]:
0    0.0
dtype: float64

注意:这里我们可以发现,loc根据标签包含尾部,iloc根据索引不包含尾部。

 

3.5算术和数据对齐

不同索引的对象之间的算术行为是pandas提供给一些应用的一项重要特性。当将对象相加时,如果存在某个索引对不相同,则返回结果的索引将是索引对的并集。对数据库用户来说,这个特性类似于索引标签的自动外连接。看下面的示例:

In [40]: s1 = pd.Series([7.3, -2.5, 3.4, 1.5], index=['a', 'c', 'd', 'e'])

In [41]: s2 = pd.Series([2.1, 3.6, -1.5, 4, 3.1], index=['a', 'c', 'e', 'f', 'g'])

In [42]: s1
Out[42]:
a    7.3
c   -2.5
d    3.4
e    1.5
dtype: float64

In [43]: s2
Out[43]:
a    2.1
c    3.6
e   -1.5
f    4.0
g    3.1
dtype: float64

In [44]: s1 + s2
Out[44]:
a    9.4
c    1.1
d    NaN
e    0.0
f    NaN
g    NaN
dtype: float64

没有交叠的标签位置上,内部数据对齐会产生缺失值。缺失值会在后续的算术操作上产生影响。在DataFrame的示例中,行和列上都会执行对齐:

In [46]: df1 = pd.DataFrame(np.arange(9.).reshape((3, 3)), columns=list('bcd'), index=['Ohio', 'Texas', 'Colorado'])

In [48]: df2 = pd.DataFrame(np.arange(12.).reshape((4, 3)), columns=list('bde'), index=['Utah', 'Ohio', 'Texas', 'Orego
    ...: n'])

In [49]: df1
Out[49]:
            b    c    d
Ohio      0.0  1.0  2.0
Texas     3.0  4.0  5.0
Colorado  6.0  7.0  8.0

In [50]: df2
Out[50]:
          b     d     e
Utah    0.0   1.0   2.0
Ohio    3.0   4.0   5.0
Texas   6.0   7.0   8.0
Oregon  9.0  10.0  11.0

将这些对象加在一起,返回一个DataFrame,它的索引、列是每个DataFrame的索引、列的并集:

In [51]: df1 + df2
Out[51]:
            b   c     d   e
Colorado  NaN NaN   NaN NaN
Ohio      3.0 NaN   6.0 NaN
Oregon    NaN NaN   NaN NaN
Texas     9.0 NaN  12.0 NaN
Utah      NaN NaN   NaN NaN

由于'c' 和 'e' 列并不是两个DataFrame共有的列,这两列中产生了缺失值。对于行标签不同的DataFrame对象也是如此。

如果将两个行或列完全不同的DataFrame对象相加,结果将全部为空:

In [52]: df1 = pd.DataFrame({'A': [1, 2]})

In [53]: df2 = pd.DataFrame({'B': [3, 4]})

In [54]: df1
Out[54]:
   A
0  1
1  2

In [55]: df2
Out[55]:
   B
0  3
1  4

In [56]: df1 - df2
Out[56]:
    A   B
0 NaN NaN
1 NaN NaN

3.5.1使用填充值的算术方法

在两个不同的索引化对象之间进行算术操作时,可能会想要使用特殊填充值,比如当轴标签在一个对象中存在,在另一个对象中不存在时,想将缺失值填充为0:

In [57]: df1 = pd.DataFrame(np.arange(12.).reshape((3, 4)), columns=list('abcd'))

In [58]: df2 = pd.DataFrame(np.arange(20.).reshape((4, 5)), columns=list('abcde'))

In [59]: df2.loc[1, 'b'] = np.nan

In [60]: df1
Out[60]:
     a    b     c     d
0  0.0  1.0   2.0   3.0
1  4.0  5.0   6.0   7.0
2  8.0  9.0  10.0  11.0

In [61]: df2
Out[61]:
      a     b     c     d     e
0   0.0   1.0   2.0   3.0   4.0
1   5.0   NaN   7.0   8.0   9.0
2  10.0  11.0  12.0  13.0  14.0
3  15.0  16.0  17.0  18.0  19.0

将这些df添加到一起会导致在一些不重叠的位置出现NA值:

In [62]: df1 + df2
Out[62]:
      a     b     c     d   e
0   0.0   2.0   4.0   6.0 NaN
1   9.0   NaN  13.0  15.0 NaN
2  18.0  20.0  22.0  24.0 NaN
3   NaN   NaN   NaN   NaN NaN

在df1上使用add方法,将df2和一个fill_value作为参数传入:

In [63]: df1.add(df2, fill_value=0)
Out[63]:
      a     b     c     d     e
0   0.0   2.0   4.0   6.0   4.0
1   9.0   5.0  13.0  15.0   9.0
2  18.0  20.0  22.0  24.0  14.0
3  15.0  16.0  17.0  18.0  19.0

这些方法中的每一个都有一个以r开头的副本,这些副本方法的参数是翻转的。因此下面两个语句的结果是等价的:

In [64]: 1 / df1
Out[64]:
          a         b         c         d
0       inf  1.000000  0.500000  0.333333
1  0.250000  0.200000  0.166667  0.142857
2  0.125000  0.111111  0.100000  0.090909

In [65]: df1.rdiv(1)
Out[65]:
          a         b         c         d
0       inf  1.000000  0.500000  0.333333
1  0.250000  0.200000  0.166667  0.142857
2  0.125000  0.111111  0.100000  0.090909

与此相关的一点,当对Series或DataFrame重建索引时,也可以指定一个不同的填充值:

In [66]: df1.reindex(columns=df2.columns, fill_value=0)
Out[66]:
     a    b     c     d  e
0  0.0  1.0   2.0   3.0  0
1  4.0  5.0   6.0   7.0  0
2  8.0  9.0  10.0  11.0  0

灵活算术方法表

3e34a19b6ed64eec868c9f6c215bfd95.jpeg

3.5.2DataFrame和Series间的操作

DataFrame和Series间的算术操作与Numpy中不同维度数组间的操作类似。首先,在下面的生动示例中,考虑二维数组和其中一行之间的区别:

In [67]: arr = np.arange(12.).reshape((3, 4))

In [68]: arr
Out[68]:
array([[ 0.,  1.,  2.,  3.],
       [ 4.,  5.,  6.,  7.],
       [ 8.,  9., 10., 11.]])

In [69]: arr[0]
Out[69]: array([0., 1., 2., 3.])

In [70]: arr - arr[0]
Out[70]:
array([[0., 0., 0., 0.],
       [4., 4., 4., 4.],
       [8., 8., 8., 8.]])

当从arr中减去arr[0]时,减法在每一行都进行了操作。这就是所谓的广播机制。DataFrame和Series间的操作是类似的:

In [71]: frame = pd.DataFrame(np.arange(12.).reshape((4, 3)), columns=list('bde'), index=['Utah', 'Ohio', 'Texas', 'Ore
    ...: gon'])

In [72]: series = frame.iloc[0]

In [73]: frame
Out[73]:
          b     d     e
Utah    0.0   1.0   2.0
Ohio    3.0   4.0   5.0
Texas   6.0   7.0   8.0
Oregon  9.0  10.0  11.0

In [74]: series
Out[74]:
b    0.0
d    1.0
e    2.0
Name: Utah, dtype: float64

默认情况下,DataFrame和Series的数学操作中会将Series的索引和DataFrame的列进行匹配,并广播到各行:

In [75]: frame - series
Out[75]:
          b    d    e
Utah    0.0  0.0  0.0
Ohio    3.0  3.0  3.0
Texas   6.0  6.0  6.0
Oregon  9.0  9.0  9.0

如果一个索引不在DataFrame的列中,也不在Series的索引中,则对象会重建索引并形成联合:

In [76]: series2 = pd.Series(range(3), index=['b', 'e', 'f'])

In [77]: frame + series2
Out[77]:
          b   d     e   f
Utah    0.0 NaN   3.0 NaN
Ohio    3.0 NaN   6.0 NaN
Texas   6.0 NaN   9.0 NaN

如果想改为在列上进行广播,在行上进行匹配,必须使用算术方法中的一种。例如:

In [78]: series3 = frame['d']

In [79]: frame
Out[79]:
          b     d     e
Utah    0.0   1.0   2.0
Ohio    3.0   4.0   5.0
Texas   6.0   7.0   8.0
Oregon  9.0  10.0  11.0

In [80]: series3
Out[80]:
Utah       1.0
Ohio       4.0
Texas      7.0
Oregon    10.0
Name: d, dtype: float64

In [81]: frame.sub(series3, axis='index')
Out[81]:
          b    d    e
Utah   -1.0  0.0  1.0
Ohio   -1.0  0.0  1.0
Texas  -1.0  0.0  1.0
Oregon -1.0  0.0  1.0

传递的axis值是用于匹配轴的。上面的示例中表示我们需要在DataFrame的行索引上对行匹配(axis='index'或axis=0),并进行广播。

 

3.6函数应用和映射

Numpy的通用函数(逐元素数组方法)对pandas对象也有效:

In [82]: frame = pd.DataFrame(np.random.randn(4, 3), columns=list('bde'), index=['Utah', 'Ohio', 'Texas', 'Oregon'])

In [83]: frame
Out[83]:
               b         d         e
Utah   -0.022472 -0.193473 -0.670609
Ohio    1.509514 -0.433377 -0.245948
Texas   0.632129 -0.642589  0.160467
Oregon -0.191544  0.475054  0.433943

In [84]: np.abs(frame)
Out[84]:
               b         d         e
Utah    0.022472  0.193473  0.670609
Ohio    1.509514  0.433377  0.245948
Texas   0.632129  0.642589  0.160467
Oregon  0.191544  0.475054  0.433943

另一个常用的操作是将函数应用到一行或一列的一维数组上。DataFrame的apply方法可以实现这个功能:

In [85]: f = lambda x: x.max() - x.min()

In [86]: frame.apply(f)
Out[86]:
b    1.701058
d    1.117643
e    1.104552
dtype: float64

这里的函数f,可以计算Series最大值和最小值的差,会被frame中的每一列调用一次。结果是一个以frame的列作为索引的Series。

如果传递axis='columns'给apply函数,函数将会被每行调用一次:

In [87]: frame.apply(f, axis='columns')
Out[87]:
Utah      0.648137
Ohio      1.942891
Texas     1.274718
Oregon    0.666597
dtype: float64

大部分最常用的数组统计(比如sum和mean)都是DataFrame的方法,因此计算统计值时使用apply并不是必需的。

传递给apply的啊哈双女户并不一定要返回一个标量值,也可以返回带有多个值的Series:

In [88]: def f(x):
    ...:     return pd.Series([x.min(), x.max()], index=['min', 'max'])
    ...:
    ...:

In [89]: frame.apply(f)
Out[89]:
            b         d         e
min -0.191544 -0.642589 -0.670609
max  1.509514  0.475054  0.433943

逐元素的Python函数也可以使用。假设想要根据frame中的每个浮点数计算一个格式化字符串,可以使用applymap方法:

In [90]: format_ = lambda x: '%.2f' % x

In [91]: frame.applymap(format_)
Out[91]:
            b      d      e
Utah    -0.02  -0.19  -0.67
Ohio     1.51  -0.43  -0.25
Texas    0.63  -0.64   0.16
Oregon  -0.19   0.48   0.43

使用applymap作为函数名是因为Series有map方法,可以将一个逐元素的函数应用到Series上:

In [92]: frame['e'].map(format_)
Out[92]:
Utah      -0.67
Ohio      -0.25
Texas      0.16
Oregon     0.43
Name: e, dtype: object

 

3.7排序和排名

根据某些准则对数据集进行排序是另一个重要的内建操作。如果按行或列索引进行字典型排序,需要使用sort_index方法,该方法返回一个新的、排序好的对象:

In [93]: obj = pd.Series(range(4), index=['d', 'a', 'b', 'c'])

In [94]: obj.sort_index()
Out[94]:
a    1
b    2
c    3
d    0
dtype: int64

在DataFrame中,可以在各个轴上按索引排序:

In [95]: frame = pd.DataFrame(np.arange(8).reshape((2, 4)), index=['three', 'one'], columns=['d', 'a', 'b', 'c'])

In [96]: frame.sort_index()
Out[96]:
       d  a  b  c
one    4  5  6  7
three  0  1  2  3

In [97]: frame.sort_index(axis=1)
Out[97]:
       a  b  c  d
three  1  2  3  0
one    5  6  7  4

数据默认会升序排序,但是也可以按照降序排序:

In [98]: frame.sort_index(axis=1, ascending=False)
Out[98]:
       d  c  b  a
three  0  3  2  1
one    4  7  6  5

如果要根据Series的值进行排序,使用sort_values方法:

In [99]: obj = pd.Series([4, 7, -3, 2])

In [100]: obj.sort_values()
Out[100]:
2   -3
3    2
0    4
1    7
dtype: int64

默认情况下,所有的缺失值都会被排序至Series的尾部:

In [101]: obj = pd.Series([4, np.nan, 7, np.nan, -3, 2])

In [103]: obj.sort_values()
Out[103]:
4   -3.0
5    2.0
0    4.0
2    7.0
1    NaN
3    NaN
dtype: float64

当对DataFrame排序时,可以使用一列或多列作为排序键。为了实现这个功能,传递一个或多个列名给sort_values的可选参数by:

In [106]: frame.sort_values(by='b')
Out[106]:
   b  a
2 -3  0
3  2  1
0  4  0
1  7  1

对多列排序时,传递列名的列表:

In [107]: frame.sort_values(by=['a', 'b'])
Out[107]:
   b  a
2 -3  0
0  4  0
3  2  1
1  7  1

排名是指对数组从1到有数据点总数分配名次的操作。Series和DataFrame的rank方法是实现排名的方法,默认情况下,rank通过将平均排名分配到每个组来打破平级关系:

In [108]: obj = pd.Series([7, -5, 7, 4, 2, 0, 4])

In [109]: obj.rank()
Out[109]:
0    6.5
1    1.0
2    6.5
3    4.5
4    3.0
5    2.0
6    4.5
dtype: float64

可以看到,第一列是值的索引,第二列是值的排名,两个7并列6.5 。

排名也可以根据它们在数据中的观察顺序进行分配:

In [110]: obj.rank(method='first')
Out[110]:
0    6.0
1    1.0
2    7.0
3    4.0
4    3.0
5    2.0
6    5.0
dtype: float64

像第一个7被先观察到,就是第6 。

还可以按降序排名:

In [111]: obj.rank(ascending=False, method='max')
Out[111]:
0    2.0
1    7.0
2    2.0
3    4.0
4    5.0
5    6.0
6    4.0
dtype: float64

DataFrame可以对行或列计算排名:

In [112]: frame = pd.DataFrame({'b': [4.3, 7, -3, 2], 'a': [0, 1, 0, 1], 'c': [-2, 5, 8, -2.5]})

In [113]: frame
Out[113]:
     b  a    c
0  4.3  0 -2.0
1  7.0  1  5.0
2 -3.0  0  8.0
3  2.0  1 -2.5

In [114]: frame.rank(axis='columns')
Out[114]:
     b    a    c
0  3.0  2.0  1.0
1  3.0  1.0  2.0
2  1.0  2.0  3.0
3  3.0  2.0  1.0

上面是给列的值计算排名。

排名中的平级关系打破方法表

169ffaefbd8640f0af2b304d021d7403.jpeg

3.8含有重复标签的轴索引

目前为止所见过的示例中,轴索引都是唯一的(索引值)。尽管很多pandas函数(比如reindex)需要标签是唯一的,但这个并不是强制性的。来考虑一个小型的带有重复索引的Series:

In [115]: obj = pd.Series(range(5), index=['a', 'a', 'b', 'b', 'c'])

In [116]: obj
Out[116]:
a    0
a    1
b    2
b    3
c    4
dtype: int64

索引的is_unique属性可以告诉它的标签是否唯一:

In [117]: obj.index.is_unique
Out[117]: False

带有重复索引的情况下,数据选择是与之前操作有差别的主要情况。根据一个标签索引多个条目会返回一个序列,而单个条目会返回标量值:

In [118]: obj['a']
Out[118]:
a    0
a    1
dtype: int64

In [119]: obj['c']
Out[119]: 4

这可能会使代码更复杂,因为来自索引的输出类型可能因标签是否重复而有所不同。

相同的逻辑可以拓展到在DataFrame中进行行索引:

In [120]: df = pd.DataFrame(np.random.randn(4, 3), index=list('aabb'))

In [121]: df
Out[121]:
          0         1         2
a  0.623063  0.036681  1.057633
a  0.326719 -0.306967  0.031440
b -1.062273 -1.151934 -0.022903
b -1.161489 -0.493180  0.437980

In [122]: df.loc['b']
Out[122]:
          0         1         2
b -1.062273 -1.151934 -0.022903
b -1.161489 -0.493180  0.437980

 

4.描述性统计的概述与计算

pandas对象装配了一个常用数学、统计方法的集合。其中大部分属于归约或汇总统计的类别,这些方法从DataFrame的行或列中抽取一个Series或一系列值的单个值(如总和或平均值)。与Numpy数组中的类似方法相比,它们内建了处理缺失值的功能。考虑一个小型的DataFrame:

In [3]: df = pd.DataFrame([[1.4, np.nan], [7.1, -4.5], [np.nan, np.nan], [0.75, -1.3]], index=['a', 'b', 'c', 'd'], col
   ...: umns=['one', 'two'])

In [4]: df
Out[4]:
    one  two
a  1.40  NaN
b  7.10 -4.5
c   NaN  NaN
d  0.75 -1.3

调用DataFrame的sum方法返回一个包含列上加和的Series:

In [5]: df.sum()
Out[5]:
one    9.25
two   -5.80
dtype: float64

传入axis='columns'或axis=1,则会将一行上各个列的值相加:

In [6]: df.sum(axis=1)
Out[6]:
a    1.40
b    2.60
c    0.00
d   -0.55
dtype: float64

除非整个切片上(在本例中是行或列)都是NA,否则NA值是被自动排除的。可以通过禁用skipna来实现不排除NA值:

In [7]: df.mean(axis=1, skipna=False)
Out[7]:
a      NaN
b    1.300
c      NaN
d   -0.275
dtype: float64

归约方法的常用可选参数列表

4aecd076e78c4461af674ee94053bf71.jpeg

一些方法,比如idxmin和idxmax,返回的是间接统计信息,比如最小值或最大值的索引值:

In [8]: df.idxmax()
Out[8]:
one    b
two    d
dtype: object

除了归约方法外,有的方法是积累型方法:

In [9]: df.cumsum()
Out[9]:
    one  two
a  1.40  NaN
b  8.50 -4.5
c   NaN  NaN
d  9.25 -5.8

还有一类方法既不是归约型方法也不是积累型方法。describe就是其中之一,它一次性产生多个汇总统计:

In [10]: df.describe()
Out[10]:
            one       two
count  3.000000  2.000000
mean   3.083333 -2.900000
std    3.493685  2.262742
min    0.750000 -4.500000
25%    1.075000 -3.700000
50%    1.400000 -2.900000
75%    4.250000 -2.100000
max    7.100000 -1.300000

对于非数值型数据,describe产生另一种汇总统计:

In [11]: obj = pd.Series(list('aabc') * 4)

In [12]: obj.describe()
Out[12]:
count     16
unique     3
top        a
freq       8
dtype: object

汇总统计及相关方法的完整列表

1d9e98d1fb6045a8ae57abcfa5ae81d3.jpeg

4.1唯一值、计数和成员属性

一类相关的方法可以从一维Series包含的数值中提取信息。为了说明这些方法,考虑这个例子:

In [13]: obj = pd.Series(list('cadaabbcc'))

第一个函数是unique,它会给出Series中的唯一值:

In [14]: unique = obj.unique()

In [15]: unique
Out[15]: array(['c', 'a', 'd', 'b'], dtype=object)

唯一值并不一定按照排序好的顺序返回,但是如果需要的话可以进行排序(unique.sort())。相应地,value_counts计算Series包含的个数:

In [16]: obj.value_counts()
Out[16]:
a    3
c    3
b    2
d    1
dtype: int64

为了方便,返回的Series会按照数量降序排列。value_counts也是有效的pandas顶层方法,可以用于任意数组或序列:

In [17]: pd.value_counts(obj.values, sort=False)
Out[17]:
d    1
b    2
c    3
a    3
dtype: int64

isin执行向量化的成员属性检查,还可以将数据集以Series或DataFrame一列的形式过滤为数据集的值子集:

In [18]: obj
Out[18]:
0    c
1    a
2    d
3    a
4    a
5    b
6    b
7    c
8    c
dtype: object

In [20]: mask = obj.isin(['b', 'c'])

In [21]: mask
Out[21]:
0     True
1    False
2    False
3    False
4    False
5     True
6     True
7     True
8     True
dtype: bool

In [22]: obj[mask]
Out[22]:
0    c
5    b
6    b
7    c
8    c
dtype: object

与isin相关的Index.get_indexer方法,可以提供一个索引数组,这个索引数组可以将可能非唯一值数组转换为另一个唯一值数组:

In [23]: to_match = pd.Series(list('cabbca'))

In [24]: unique_vals = pd.Series(list('cba'))

In [25]: pd.Index(unique_vals).get_indexer(to_match)
Out[25]: array([0, 2, 1, 1, 0, 2], dtype=int64)

唯一值、计数和集合成员属性方法表

13562bbcbd8c440b9d7d28d6f2a0cb01.jpeg

某些情况下,可能想要计算DataFrame多个相关列的直方图,如下面的例子:

In [26]: data = pd.DataFrame({'Qu1': [1, 3, 4, 3, 4], 'Qu2': [2, 3, 1, 2, 3], 'Qu3': [1, 5, 2, 4, 4]})

In [27]: data
Out[27]:
   Qu1  Qu2  Qu3
0    1    2    1
1    3    3    5
2    4    1    2
3    3    2    4
4    4    3    4

将pandas.value_counts传入DataFrame的apply函数可以得到:

In [28]: result = data.apply(pd.value_counts).fillna(0)

In [29]: result
Out[29]:
   Qu1  Qu2  Qu3
1  1.0  1.0  1.0
2  0.0  2.0  1.0
3  2.0  2.0  0.0
4  2.0  0.0  2.0
5  0.0  0.0  1.0

这里,结果中的行标签是所有列中出现的不同值,数值则是这些不同值在每个列中出现的次数。

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

还有糕手

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值