利用Python进行数据分析之pandas入门学习

利用Python进行数据分析之pandas入门学习



前言

本系列博文为利用 Python 进行数据分析相关工具包的学习,主要包含NumPy、pandas和matplotlib. 学习主要参考莫烦Python网站上面的教程。


一、pandas是什么?

NumPy 是将矩阵序列化,使用NumPy中避免了使用循环语句以达到某些计算目的。相比于NumPy,pandas则更像是“字典型的NumPy”,因为在pandas中我们可以给矩阵的行和列进行不同的命名。
总体来说,pandas 是基于NumPy 的一种工具,该工具是为了解决数据分析任务而创建的,二者相互搭配使用。

二、pandas基本介绍

首先先引入pandas工具包,代码如下:

import numpy as np
import pandas as pd

2.1 创建pandas序列

s = pd.Series([1, 2, 3, 6, np.nan, 4])      #注意这里的Serious首字母要大写
s
# 0    1.0
# 1    2.0
# 2    3.0
# 3    6.0
# 4    NaN
# 5    4.0
# dtype: float64

上述代码中的np.nan为空值。注意在输入值的前侧有0-5的index,这有点像NumPy中的一维数据的索引。而dtype: float64则表示输入的数字格式为64位浮点型数值。
注:不同于NumPy中有int、float多种数值类型,Series中只有float一种数值类型。

2.2 创建DataFrame

矩阵在pandas中被称为DataFrame。首先需要定义一个date来作为描述其行的索引,如果不指定索引,则默认索引为0,1,2,…

dates = pd.date_range('20160101', periods=6)
dates
# DatetimeIndex(['2016-01-01', '2016-01-02', '2016-01-03', '2016-01-04',
#                '2016-01-05', '2016-01-06'],
#               dtype='datetime64[ns]', freq='D')

注意这里的dtype是日期(datatime[64])。

df = pd.(np.random.randn(6, 4), index=dates, columns=['a', 'b', 'c', 'd'])
df
#                      a	        b	        c	        d
# 2016-01-01	0.765527	-0.681561	-1.078267	-1.464479
# 2016-01-02	-1.022756	1.313707	0.158951	-0.261652
# 2016-01-03	-0.016420	0.463552	1.924633	1.851053
# 2016-01-04	-0.797636	-1.285860	-0.691840	1.170988
# 2016-01-05	0.306082	-0.242542	0.166530	1.747711
# 2016-01-06	-0.186562	0.959031	0.110047	0.666948

上述代码生成的DateFrame类似于NumPy中的矩阵,其中数据是使用NumPy中随机抽样所得,行索引(index)为之前定义的日期,列索引(columns)为[‘a’, ‘b’, ‘c’, ‘d’].
下面看一些不指定行索引和列索引情况下的输入。

df1 = pd.DataFrame(np.random.randn(12).reshape(3, -1))
df1
#          0	        1	        2      	   3
# 0	    1.623124	-0.059781	-0.545961	1.278110
# 1	    0.535882	-0.012219	1.429241	1.283243
# 2	   -0.558577	0.288868	-1.380940	1.057342

这里的行列索引为默认的0,1,2,3.

2.3 DataFrame的基本属性

3.1 属性dtypes

dtypes表示DataFrame中每一列的数值属性

df1.dtypes
# 0    float64
# 1    float64
# 2    float64
# 3    float64
# dtype: object

3.2 索引

输出DataFrame中所有的索引。

df1.index         # 输出所有行标签
# RangeIndex(start=0, stop=3, step=1)
df1.columns         # 输出所有列标签
# RangeIndex(start=0, stop=4, step=1)

3.3 数值

输出所有数值(values)

df1.values
# array([[ 1.62312401, -0.05978129, -0.54596109,  1.2781104 ],
#        [ 0.53588153, -0.01221874,  1.42924132,  1.28324285],
#        [-0.5585765 ,  0.28886821, -1.38094041,  1.05734184]])

3.4 描述

这里用describe()计算出一些统计量来描述每一列的一些信息。这里要注意describe()只针对数值类型的列进行计算,例如字符串类的列跳过不做分析。

df1.describe()
#              0	       1	       2	       3
# count	3.000000	3.000000	3.000000	3.000000       #数据个数
# mean	0.533476	0.072289	-0.165887	1.206232       #数据均值
# std	1.090852	0.189064	1.443129	0.128968       #数据标准差
# min	-0.558577	-0.059781	-1.380940	1.057342
# 25%	-0.011347	-0.036000	-0.963451	1.167726
# 50%	0.535882	-0.012219	-0.545961	1.278110
# 75%	1.079503	0.138325	0.441640	1.280677
# max	1.623124	0.288868	1.429241	1.283243

3.5 转置

df1.T
#          0	       1	        2
# 0	1.623124	0.535882	-0.558577
# 1	-0.059781	-0.012219	0.288868
# 2	-0.545961	1.429241	-1.380940
# 3	1.278110	1.283243	1.057342

3.6 排序

df1.sort_index(axis=1, ascending=False)   

上述代码中是根据列(index=1表示列,取0时表示行)名称进行排序,同时可以对ascending赋值True或False来确定是正向排序还是倒序。
不仅仅可以对行列索引进行排序,也可以对其中某个列的取值进行排序。

df1.sort_values(by=2)     # 根据列索引为2的列中的值进行从小到大(默认)进行排序

三、pandas数据选择

首先生成一个DataFrame以供后面的学习。

import pandas as pd
import numpy as np
dates = pd.date_range('20160101', periods=6)
df = pd.DataFrame(np.arange(24).reshape((6, 4)), index=dates, columns=['a', 'b', 'c', 'd'])
df
#                	a	b	c	d
#     2016-01-01	0	1	2	3
#     2016-01-02	4	5	6	7
#     2016-01-03	8	9	10	11
#     2016-01-04	12	13	14	15
#     2016-01-05	16	17	18	19
#     2016-01-06	20	21	22	23

3.1 输出指定列

print(df['a'])   #或是df.a

上述两种方法都可以输出df的列索引为a的列。

3.2 输出指定行

选出指定行有两种方法,一个是直接给出行所在‘序号’,另一个是给出行的索引名称。

print(df[0:3])         #这里输出的[0:3]是左闭右闭的
#                	a	b	c	d
#     2016-01-01	0	1	2	3
#     2016-01-02	4	5	6	7
#     2016-01-03	8	9	10	11
print(df['2016-01-02': '2016-01-04'])
#                	a	b	c	d
#     2016-01-02	4	5	6	7
#     2016-01-03	8	9	10	11
#     2016-01-04	12	13	14	15

更一般地,可以用pandas的后缀‘loc’去描述选哪个标签下的数据,或是根据位置’position’选择:

# select by lobal:loc    
print(df.loc['20160102'])
# a    4
# b    5
# c    6
# d    7
# Name: 2016-01-02 00:00:00, dtype: int32
print(df.loc['2016-01-04', ['a', 'b']])
# a    4
# b    5
# Name: 2016-01-02 00:00:00, dtype: int32


# select by position: iloc
print(df.iloc[3])    #输出第三行的数据
# a    12
# b    13
# c    14
# d    15
# Name: 2016-01-04 00:00:00, dtype: int32
print(df.iloc[3, 1])       #输出第三行第一位
# 13
print(df.iloc[1:3, 2:4])      #切片输出
#              c   d
# 2016-01-02   6   7
# 2016-01-03  10  11

print(df.iloc[[1,3,5], 2:4])      #逐个筛选后输出
#              c   d
# 2016-01-02   6   7
# 2016-01-04  14  15
# 2016-01-06  22  23

3.3 布尔逻辑选择

这里和NumPy中的布尔逻辑筛选很像。

#Boolean indexing
print(df[df.a > 8])
#              a   b   c   d
# 2016-01-04  12  13  14  15
# 2016-01-05  16  17  18  19
# 2016-01-06  20  21  22  23

print(df[[True, False, True, True, False, True]])
#              a   b   c   d
# 2016-01-01   0   1   2   3
# 2016-01-03   8   9  10  11
# 2016-01-04  12  13  14  15
# 2016-01-06  20  21  22  23

四、pandas设定值

4.1 使用位置参数设置值

这里可以使用上述的iloc、loc或布尔逻辑值取数后再设定值。

df.iloc[2, 2] = 111        # 将第2行第2列元素设置为111
df
#                	a	b	c	d
#     2016-01-01	0	1	2	3
#     2016-01-02	4	5	6	7
#     2016-01-03	8	9	111	11
#     2016-01-04	12	13	14	15
#     2016-01-05	16	17	18	19
#     2016-01-06	20	21	22	23

df.loc['20160101', 'b'] = 222
df
#                	a	b	c	d
#     2016-01-01	0	222	2	3
#     2016-01-02	4	5	6	7
#     2016-01-03	8	9	111	11
#     2016-01-04	12	13	14	15
#     2016-01-05	16	17	18	19
#     2016-01-06	20	21	22	23

df.b[df.a > 16]  = 0
df
#                	a	b	c	d
#     2016-01-01	0	222	2	3
#     2016-01-02	4	5	6	7
#     2016-01-03	8	9	111	11
#     2016-01-04	12	13	14	15
#     2016-01-05	16	17	18	19
#     2016-01-06	20	0	22	23

4.2 添加新的列

可以添加一列空值,然后再设定值。或是直接添加值。

df['e'] = np.nan
df
# 	            a	b	c	d	e
# 2016-01-01	0	222	2	3	NaN
# 2016-01-02	4	5	6	7	NaN
# 2016-01-03	8	9	111	11	NaN
# 2016-01-04	12	13	14	15	NaN
# 2016-01-05	16	17	18	19	NaN
# 2016-01-06	20	0	22	23	NaN

df['f'] = pd.Series([1, 2, 3, 4, 5, 6], index=pd.date_range('20160101', periods=6))
df
# 	    	    a	b	c	d	e	f
# 2016-01-01	0	222	2	3	NaN	1
# 2016-01-02	4	5	6	7	NaN	2
# 2016-01-03	8	9	111	11	NaN	3
# 2016-01-04	12	13	14	15	NaN	4
# 2016-01-05	16	17	18	19	NaN	5
# 2016-01-06	20	0	22	23	NaN	6

上述代码中的第二部分可以参考第3节,首先生成取值为1到6的序列,然后将其行标签设定为和df相同的时间序列,一一对应。

五、处理丢失值

首先生成一个DataFrame以供后面的学习分析。

import pandas as pd
import numpy as np
dates = pd.date_range('20160101', periods=6)
df = pd.DataFrame(np.arange(24).reshape((6, 4)), index=dates, columns=['a', 'b', 'c', 'd'])
df.iloc[0, 1] = np.nan
df.iloc[1, 2] = np.nan
df
# 	            a	b	    c	    d
# 2016-01-01	0	NaN	    2.0  	3
# 2016-01-02	4	5.0	    NaN	    7
# 2016-01-03	8	9.0 	10.0	11
# 2016-01-04	12	13.0	14.0	15
# 2016-01-05	16	17.0	18.0	19
# 2016-01-06	20	21.0	22.0	23

很多时候DataFrame中都含有丢失值(NaN),首先要用isnull函数检查是否有缺失值,返回的是由True和False组成的DataFrame:

print(df.isnull())

还可以用any函数判断返回的DataFrame中是否含有True:

print(np.any(df.isnull()) == True)
# True

下面介绍如何处理这些丢失值。

5.1 将含有缺失值的行或列丢掉

print(df.dropna(axis=0, how='any'))      # how='all'

上述代码中,axis取0/1时表示将含有缺失值的行/列丢掉,how取any时表示含有一个缺值值就丢掉,取all时表示全部值都是空值时丢掉,默认how取any。

5.2 将缺失值设定为某一指定数值(填数)

这里可以使用fillnan函数将value的值填到空值处。

print(df.fillna(value=0))

六、数据的读取与保存

首先说明一下pandas可以读取的数据格式,主要包含:csv、excel、hdf、sql、json、msgpack、html、gbd、stata、sas、clipborad、pickle。命令read_加上上述格式即为读取相应格式的命令,to_加上上述格式即将数据保存为相应格式的命令。
注:通常在处理数据时推荐使用csv格式,因为其存储方式简单。

6.1 数据的读取

import pandas as pd
data = pd.read_csv(r'C:\Users\HUAWEI\Desktop\student.csv')
print(data)
#    Student_id name  age  gender
# 0        1100    A   22  Female
# 1        1101    B   21    Male
# 2        1102    C   25  Female
# 3        1103    D   24    Male
# 4        1104    E   23  Female
# 5        1105    F   20    Male
# 6        1106    G   23  Female
# 7        1107    H   24    Male
# 8        1108    I   21  Female
# 9        1109    G   22    Male

6.2 数据的保存

将上述data中的数据保存为xlsx格式

data.to_excel(r'C:\Users\HUAWEI\Desktop\student.xlsx')

七、DataFrame的合并

合并可以横向合并、纵向合并,或是按照row、column索引合并,即使行列索引不同仍然可以合并。

7.1 DataFrame的合并之concat

首先还是生成DataFrame:

import numpy as np
import pandas as pd
# concatenating
df0 = pd.DataFrame(np.ones((3,4))*0, columns=['a','b','c','d'])
df1 = pd.DataFrame(np.ones((3,4))*1, columns=['a','b','c','d'])
df2 = pd.DataFrame(np.ones((3,4))*2, columns=['a','b','c','d'])

1. 上下合并

下面将三个含有相同的colume的DataFrame进行合并,在concat函数中,参数axis取0是表示竖向合并,取1时表示横向合并.

result = pd.concat([df0, df1, df2], axis = 0)       
print(result)
#      a    b    c    d
# 0  0.0  0.0  0.0  0.0
# 1  0.0  0.0  0.0  0.0
# 2  0.0  0.0  0.0  0.0
# 0  1.0  1.0  1.0  1.0
# 1  1.0  1.0  1.0  1.0
# 2  1.0  1.0  1.0  1.0
# 0  2.0  2.0  2.0  2.0
# 1  2.0  2.0  2.0  2.0
# 2  2.0  2.0  2.0  2.0

可以看出,上述将三个DataFrame合并后的行索引是之前的三个DataFrame(0,1,2),这里可以通过对参数ignore_index赋值进行重新排序:

result = pd.concat([df0, df1, df2], axis = 0, ignore_index=True)
print(result)

#      a    b    c    d
# 0  0.0  0.0  0.0  0.0
# 1  0.0  0.0  0.0  0.0
# 2  0.0  0.0  0.0  0.0
# 3  1.0  1.0  1.0  1.0
# 4  1.0  1.0  1.0  1.0
# 5  1.0  1.0  1.0  1.0
# 6  2.0  2.0  2.0  2.0
# 7  2.0  2.0  2.0  2.0
# 8  2.0  2.0  2.0  2.0

concat中还有一个参数是join,类似于axis和ignore_index,其取值范围为{‘inner’,‘outer’}.(这里和SQL的内外连接很像,即inner取交集,outer取并集,可以参考)
由于此处主要讨论根据行列索引进行连结,所以需要重新生成几个DataFrame以供学习:

# join,['inner','outer']
df0 = pd.DataFrame(np.ones((3,4))*0, columns=['a','b','c','d'],index=[1,2,3])
df1 = pd.DataFrame(np.ones((3,4))*1, columns=['a','b','c','e'],index=[2,3,4])

注意生成的两个DataFrame的column和index不全相同。

首先看一下直接使用上述提到的concat进行连接会出现什么结果:

result = pd.concat([df0, df1])        # join='outer'
print(result)
#      a    b    c    d    e
# 1  0.0  0.0  0.0  0.0  NaN
# 2  0.0  0.0  0.0  0.0  NaN
# 3  0.0  0.0  0.0  0.0  NaN
# 2  1.0  1.0  1.0  NaN  1.0
# 3  1.0  1.0  1.0  NaN  1.0
# 4  1.0  1.0  1.0  NaN  1.0

直接使用concat会导致两个DataFrame不同的地方直接为空值NaN。实际上这里concat函数中的参数join取缺省值‘outer’。如果参数join取inner会导致不同的部分直接被舍弃掉。

result = pd.concat([df0, df1], join='inner')
print(result)
#      a    b    c
# 1  0.0  0.0  0.0
# 2  0.0  0.0  0.0
# 3  0.0  0.0  0.0
# 2  1.0  1.0  1.0
# 3  1.0  1.0  1.0
# 4  1.0  1.0  1.0

7.2 左右合并

result = pd.concat([df0, df1.reindex_like(df0)], axis = 1) 
print(result)
#      a    b    c    d    a    b    c   d
# 1  0.0  0.0  0.0  0.0  NaN  NaN  NaN NaN
# 2  0.0  0.0  0.0  0.0  1.0  1.0  1.0 NaN
# 3  0.0  0.0  0.0  0.0  1.0  1.0  1.0 NaN

首先将axis取值为1表示横向合并,同时使用df1.reindex_like(df0)表示保留df0的全部行列,将df1中与df0行列标签相同的元素保留,行列都不同的直接删除,行不同或列不同的取值为空NaN。

7.2 DataFrame的合并之append

想想一张excel表格,每一列都是一个属性,每一行为一个对象。append函数的运行过程就像是在excel中添加对象的过程。下面看一个例子感受一下:

#append
df0 = pd.DataFrame(np.ones((3,4))*0, columns=['a','b','c','d'])
df1 = pd.DataFrame(np.ones((3,4))*1, columns=['a','b','c','d'])
df2 = pd.DataFrame(np.ones((3,4))*1, columns=['a','b','c','e'],index=[2,3,4])
result0 = df0.append(df1, ignore_index=True)
print(result0)
#      a    b    c    d
# 0  0.0  0.0  0.0  0.0
# 1  0.0  0.0  0.0  0.0
# 2  0.0  0.0  0.0  0.0
# 3  1.0  1.0  1.0  1.0
# 4  1.0  1.0  1.0  1.0
# 5  1.0  1.0  1.0  1.0
result1 = df0.append([df1, df2])

上述result1表示将df1,df2合并到df0下侧。接下来看一下如何添加单独一行:

s1 = pd.Series([1, 2, 3, 4], index=['a','b','c','d'])
result2 = df0.append(s1, ignore_index=True)
print(result2)
#      a    b    c    d
# 0  0.0  0.0  0.0  0.0
# 1  0.0  0.0  0.0  0.0
# 2  0.0  0.0  0.0  0.0
# 3  1.0  2.0  3.0  4.0

7.3 DataFrame的合并之merge

相对于concat,merge功能更加全面,当然也更加复杂,下面来学习一下merge。
首先生成数据:

import numpy as np
import pandas as pd
# merging two df by key/keys. may be used in database.
# simple example
left = pd.DataFrame({'key':['K0','K1','K2','K3'],
                    'A':['A0','A1','A2','A3'],
                    'B':['B0','B1','B2','B3']})
right = pd.DataFrame({'key':['K0','K1','K2','K3'],
                    'C':['C0','C1','C2','C3'],
                    'D':['D0','D1','D2','D3']})
print(left)
#   key   A   B
# 0  K0  A0  B0
# 1  K1  A1  B1
# 2  K2  A2  B2
# 3  K3  A3  B3
print(right)
#   key   C   D
# 0  K0  C0  D0
# 1  K1  C1  D1
# 2  K2  C2  D2
# 3  K3  C3  D3

然后来基于key这一列进行合并:

res = pd.merge(left, right, on = 'key')
print(res)
#   key   A   B   C   D
# 0  K0  A0  B0  C0  D0
# 1  K1  A1  B1  C1  D1
# 2  K2  A2  B2  C2  D2
# 3  K3  A3  B3  C3  D3

之后考虑根据两列来进行合并:

#consider two keys
left = pd.DataFrame({'key1':['K0','K0','K1','K2'],
                     'key2':['K0','K1','K0','K1'],
                    'A':['A0','A1','A2','A3'],
                    'B':['B0','B1','B2','B3']})
right = pd.DataFrame({'key1':['K0','K1','K1','K2'],
                     'key2':['K0','K0','K0','K0'],
                    'C':['C0','C1','C2','C3'],
                    'D':['D0','D1','D2','D3']})
res = pd.merge(left, right, on=['key1','key2'])       
# how = ['left','right','inner','outer']
print(res)
#   key1 key2   A   B   C   D
# 0   K0   K0  A0  B0  C0  D0
# 1   K1   K0  A2  B2  C1  D1
# 2   K1   K0  A2  B2  C2  D2

这里需要特殊注意的是,和concat函数中join弄人为outer不同,merge的连接方式默认为inner,即交集。在上述代码中表示只有当两个DataFrame的key1列和key2列的取值完全相同时才会连接到一起,只有由一个不同即丢弃。
merge函数中的参数how(如何连接)有四个可取值,分别为’left’,‘right’,‘inner’和’outer’,后两个就不再赘述了,而left则表示按照左侧的(前一个)DataFrame的行标签进行连接,right表示按照右侧(后一个)DataFrame的行标签进行连接。

res1 = pd.merge(left, right, on=['key1','key2'], how='left', indicator=True)
print(res1)
#   key1 key2   A   B    C    D     _merge
# 0   K0   K0  A0  B0   C0   D0       both
# 1   K0   K1  A1  B1  NaN  NaN  left_only
# 2   K1   K0  A2  B2   C1   D1       both
# 3   K1   K0  A2  B2   C2   D2       both
# 4   K2   K1  A3  B3  NaN  NaN  left_only

上述代码中,函数merge中加入的参数indicator,当其取值为True时,可以在输出的表格的最后一列展示每行标签是both,left_only还是right_only。此时该列名称默认为_merge,可直接给参数indicator传递一个字符串以作为该列名称:

res1 = pd.merge(left, right, on=['key1','key2'], how='left', indicator='indicator_column')

学习完根据一列或是两列进行连接后,我们再来看一下根据行索引进行连接:

left = pd.DataFrame({'A':['A0','A1','A2','A3'],
                    'B':['B0','B1','B2','B3']},
                     index=['K0','K1','K2','K3'])
right = pd.DataFrame({'C':['C0','C1','C2','C3'],
                    'D':['D0','D1','D2','D3']},
                     index=['K0','K1','K4','K3'])
res = pd.merge(left, right, left_index=True, right_index=True, how='inner')
print(res)
#      A   B   C   D
# K0  A0  B0  C0  D0
# K1  A1  B1  C1  D1
# K3  A3  B3  C3  D3

根据行索引进行连接的参数取值和根据列进行连接一样,就不再赘述了。

最后来考虑一种情况:假设我们想要根据A这一列来连接两个DataFrame,但是我们想在连接后新的DataFrame中将两个原始DataFrame的列区分开来,需进行如下操作:

boys = pd.DataFrame({'k':['k0','k1','k2'], 'age':[1,2,3]})
girls = pd.DataFrame({'k':['k0','k2','k3'], 'age':[4,5,6]})
# 我们想要在新的DataFrame中将两个age区分开来
res = pd.merge(boys, girls, on='k', suffixes=['_boy','_girl'], how='inner')
print(res)
#     k  age_boy  age_girl
# 0  k0        1         4
# 1  k2        3         5

上述代码中,通过对参数suffixes赋值,这使得得到的新的DataFrame中boys的每个列标签后面都加上了_boy,girls的每个列标签后面都加上了_girl。

八、plot画图

这里调用matplotlib包进行画图:

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

常见的画图方法主要包含:bar、hist、box、kde、area、scatter、hexbin等等,在此不详细展开,但是在之后的matplotlib的学习中会系统介绍画图的方式方法。

下面看几个简单的用plot画图的例子:

【例1】:线性数据

# plot data
#Series    线性数据
data = pd.Series(np.random.randn(1000), index=np.arange(1000))
data = data.cumsum()
data.plot()
plt.show()

一个简单的例子
【例2】:DataFrame

# DataFrame
data = pd.DataFrame(np.random.randn(1000,4), index=np.arange(1000), columns=list('abcd'))
data = data.cumsum()
print(data.head())
#           a         b         c         d
# 0  0.850435 -0.779919  1.576871  0.760385
# 1  0.547593  0.128119  0.304691  0.737124
# 2 -0.334124  0.111012  0.526692  0.300202
# 3  0.007890 -0.099115 -1.474958 -0.074081
# 4 -2.316933 -1.993305 -3.500215 -1.471161

data.plot()
plt.show()

第二个简单的例子

接下来看画散点图的例子:

ax = data.plot.scatter(x='a',y='b',color='DarkBlue',label='Class1')
data.plot.scatter(x='a', y='c', color='DarkGreen', label='Class2', ax=ax)
plt.show()

第三个简单的例子
上述代码第二行中的ax=ax,前一个ax表示改行的图,后一个ax表示上一个图,令二者相等表示将第二个图画到第一个图中去。


总结

以上就是pandas基础学习的内容,本文仅仅简单介绍了pandas基本使用方法,其更多的功能还需要在实践中慢慢探索学习,各位加油。祝我们变得更强!

注1:建议搭配pandas官方学习手册一起学习。
注2:有不足或错误之处欢迎各位及时指出,感谢理解。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值