【学习笔记】数据分析(Ⅱ)—— Pandas

Pandas

1、Pandas是什么

安装依赖:pip install pandas
导入:import pandas as pd

      1.1、Panda概述

        Pandas 是一个基于 Python 的数据分析库,提供了用于处理结构化数据的丰富的数据结构和数据操作工具。它特别适用于数据清洗、数据转换、数据分析和数据可视化等任务 (中文学习网站)

      1.2、Panda特点

        ① 它提供了一个简单、高效、带有默认标签(也可以自定义标签)的 DataFrame 对象
        ② 能够快速得从不同格式的文件中加载数据(比如 Excel、CSV 、SQL文件),然后将其转换为可处理的对象
        ③ 能够按数据的行、列标进行分组,并对分组后的对象执行聚合和转换操作
        ④ 能够很方便地实现数据归一化操作和缺失值处理
        ⑤ 能够很方便地对 DataFrame 的数据列进行增加、修改或者删除的操作
        ⑥ 能够处理不同格式的数据集,比如矩阵数据、异构数据表、时间序列等
        ⑦ 提供了多种处理数据集的方式,比如构建子集、切片、过滤、分组以及重新排序等

      1.3、Pandas和Numpy的一些区别

        ① 数据结构
        NumPy 主要提供了多维数组对象 ndarray,它是一个固定大小的数组,所有元素的类型都相同
        Pandas 提供了两种主要的数据结构:Series 和 DataFrame。Series 是一维标记数组,类似于 NumPy 的一维数组;而 DataFrame 是二维标记数据结构,类似于电子表格或数据库表格
        ② 用途:
        NumPy 主要用于数值计算和科学计算领域,提供了高性能的数值运算功能,如数组运算、线性代数运算、傅里叶变换等
        Pandas 主要用于数据分析和数据处理领域,提供了丰富的数据操作工具,包括数据清洗、数据转换、数据分组、数据聚合、数据可视化等功能
        ③ 数据处理能力:
        NumPy 更适合处理数值型数据,提供了丰富的数值运算函数和方法
        Pandas 更适合处理结构化数据,如表格型数据、时间序列数据等,提供了灵活的数据操作和分析工具

比较项PandasNumPy
适应性Pandas主要用来处理类表格数据NumPy 主要用来处理数值数据
工具Pandas提供了Series和DataFrame数据结构NumPy 构建了 ndarray array来容纳数据
性能Pandas对于处理50万行以上的数据更具优势NumPy 则对于50万以下或者更少的数据,性能更佳
内存利用率与 NumPy相比,Pandas会消耗大量的内存NumPy 会消耗较少的内存
对象Pandas 提供了 DataFrame 2D数据表对象NumPy 则提供了一个多维数组 ndarray 对象

Pandas的DataFrame对象转换成ndarray的方法:to_numpy()

import pandas as pd

# 构建DataFrame对象
df = pd.DataFrame({"P": [2, 3], "Q": [4.0, 5.8]})
df['R'] = pd.date_range('2020-12-23', periods=2)  # 再添加一列
print(df)
print('-' * 30)

# 转化为numpy数组
n = df.to_numpy()
print(n)

2、Pandas的数据结构 —— Series

      2.1、Series概述

        Pandas 中的 Series 是一种一维标记数组,类似于 Python 中的字典或者 NumPy 中的一维数组。它由一组数据和一组与之相关联的索引(标签)组成,可以存储任意类型的数据,并且索引可以是任意类型的

      2.2、Series创建

        ① 使用列表创建

import pandas as pd

list1 = [1, 2, 3, 4]
s1 = pd.Series(list1)
print(s1)
0    1
1    2
2    3
3    4
dtype: int64

        ② 使用ndarray对象创建

import pandas as pd
import numpy as np

arr = np.array([1, 2, 3, 4])
s1 = pd.Series(arr, index=['A', 'B', 'C', 'D']) # 可以使用index来指定索引
print(s1)
A    1
B    2
C    3
D    4
dtype: int32

        ③ 使用字典创建

import pandas as pd

s1 = pd.Series({'name': 'hyh', 'age': 18, 'gender': 'boy'})
print(s1)
name      hyh
age        18
gender    boy
dtype: object

        ④ 使用标量创建

import pandas as pd

s1 = pd.Series(4, index=['a', 'b', 'c', 'd'])
print(s1)
a    4
b    4
c    4
d    4
dtype: int64

      2.3、Series的常用属性

属性描述
values以ndarray的形式返回数据
index索引,是一个Index对象
axes每个轴的索引,是一个Index对象数组
size长度
ndim数据的维度
dtype数据类型
import pandas as pd

l1 = [1, 2, 3, 4]
s = pd.Series(l1, index=['a', 'b', 'c', 'd'])
print("Series:\n", s)
print('-' * 30)
# 访问数据
print(s.values, type(s.values))
print('-' * 30)
# 访问索引
print(s.index, list(s.index))
print('-' * 30)
# 访问每个轴的索引
print(s.axes, s.axes[0] is s.index)
print('-' * 30)
# 访问大小
print(s.size)
print('-' * 30)
# 访问维度
print(s.ndim)
print('-' * 30)
# 访问数据类型
print(s.dtype)
Series:
 a    1
b    2
c    3
d    4
dtype: int64
------------------------------
[1 2 3 4] <class 'numpy.ndarray'>
------------------------------
Index(['a', 'b', 'c', 'd'], dtype='object') ['a', 'b', 'c', 'd']
------------------------------
[Index(['a', 'b', 'c', 'd'], dtype='object')] True
------------------------------
4
------------------------------
1
------------------------------
int64

      2.4、Series的常用方法

说明:下方的ser代指Series的实例对象

方法描述
ser.head(num)前num行数据
ser.tail(num)尾num行数据
pd.isnull(ser)
pd.nonull(ser)
检测是否有缺失值,返回的是一个Series对象
import pandas as pd
import numpy as np

arr = np.random.randint(1, 10, 5)
s = pd.Series(arr)
print(s)
print('-' * 30)
print(s.head(2))
print('-' * 30)
print(s.tail(2))
print('-' * 30)
print(pd.isnull(s))
print('-' * 30)
0    8
1    1
2    4
3    2
4    4
dtype: int32
------------------------------
0    8
1    1
dtype: int32
------------------------------
3    2
4    4
dtype: int32
0    False
1    False
2    False
3    False
4    False
dtype: bool

3、Pandas的数据结构 —— DataFrame

      3.1、DataFrame概述

        DataFrame 是 Pandas 中最重要的数据结构之一,它是一个二维标记数据结构,类似于电子表格或者数据库中的表格。DataFrame 由行和列组成,每一列可以是不同的数据类型(例如整数、浮点数、字符串等),并且每一行和每一列都有对应的标签索引

      3.2、DataFrame创建

        ① 使用列表创建

import pandas as pd

list1 = [1, 2]
df = pd.DataFrame(list1)
print(df)
print('-' * 30)

list2 = [('Alex', 11), ('Bob', 12), ('Clarke', 13)]
df = pd.DataFrame(list2, columns=['name', 'age'], dtype=float)
print(df)
   0
0  1
1  2
------------------------------
     name   age
0    Alex  11.0
1     Bob  12.0
2  Clarke  13.0

        ② 使用字典嵌套列表创建

import pandas as pd

data1 = {'name': ['Tom', 'Jack', 'Steve', 'Hyh'], 'age': [28, 48, 61, 15]}
df = pd.DataFrame(data1)
print(df)

data2 = {'name': ['Pyy', 'Zayn', 'Yh'], 'age': [32, 51, 23]}
df = pd.DataFrame(data2, index=['rank1', 'rank2', 'rank3'])
print(df)
    name  age
0    Tom   28
1   Jack   48
2  Steve   61
3    Hyh   15
       name  age
rank1   Pyy   32
rank2  Zayn   51
rank3    Yh   23

        ③ 使用列表嵌套字典创建

import pandas as pd

data1 = [{'name': 'Pyy', 'age': 22}, {'name': 'Zayn', 'age': 31, 'gender': 'boy'}]
df = pd.DataFrame(data1)
print(df)
print('-' * 30)

data1 = [{'name': 'Pyy', 'age': 22}, {'name': 'Zayn', 'age': 31, 'gender': 'boy'}]
df = pd.DataFrame(data1, index=['first', 'second'], columns=['age', 'name'])
print(df)
   name  age gender
0   Pyy   22    NaN
1  Zayn   31    boy
------------------------------
        age  name
first    22   Pyy
second   31  Zayn

        ④ 使用字典嵌套Series创建

import pandas as pd

ser1 = pd.Series([1, 2, 3], index=['a', 'b', 'c'])
ser2 = pd.Series([2, 3, 4, 5], index=['b', 'c', 'd', 'e'])
arr = {'one': ser1, 'two': ser2}
df = pd.DataFrame(arr)
print(df)
   one  two
a  1.0  NaN
b  2.0  2.0
c  3.0  3.0
d  NaN  4.0
e  NaN  5.0

      3.3、列索引操作DataFrame

import pandas as pd

ser1 = pd.Series([1, 2, 3], index=['a', 'b', 'c'])
ser2 = pd.Series([2, 3, 4, 5], index=['b', 'c', 'd', 'e'])
arr = {'one': ser1, 'two': ser2}
df = pd.DataFrame(arr)
print(df)
print('-' * 30)

# 访问一列,返回的是一个Series对象
print(df['one'])
print('-' * 30)

# 访问多列,返回的是一个DataFrame对象
print(df[['one', 'two']])
print('-' * 30)

# 添加一列
df['three'] = pd.Series([10, 20, 30], index=['a', 'b', 'c'])
df.insert(loc=1, column='four', value=[40, 50, 60, 70, 80])  # insert的数据长度要同现有的index长度
print(df)
print('-' * 30)

# 删除一列
df.pop('four')
print(df)
   one  two
a  1.0  NaN
b  2.0  2.0
c  3.0  3.0
d  NaN  4.0
e  NaN  5.0
------------------------------
a    1.0
b    2.0
c    3.0
d    NaN
e    NaN
Name: one, dtype: float64
------------------------------
   one  two
a  1.0  NaN
b  2.0  2.0
c  3.0  3.0
d  NaN  4.0
e  NaN  5.0
------------------------------
   one  four  two  three
a  1.0    40  NaN   10.0
b  2.0    50  2.0   20.0
c  3.0    60  3.0   30.0
d  NaN    70  4.0    NaN
e  NaN    80  5.0    NaN
------------------------------
   one  two  three
a  1.0  NaN   10.0
b  2.0  2.0   20.0
c  3.0  3.0   30.0
d  NaN  4.0    NaN
e  NaN  5.0    NaN

      3.4、行索引操作DataFrame

import pandas as pd

ser1 = pd.Series([1, 2, 3], index=['a', 'b', 'c'])
ser2 = pd.Series([2, 3, 4, 5], index=['b', 'c', 'd', 'e'])
arr = {'one': ser1, 'two': ser2}
df = pd.DataFrame(arr)
print(df)
print('-' * 30)

# 使用切片访问行
print(df[1:4])
print('-' * 30)

# 使用loc访问行,需要使用行的标签名
print(df.loc['b'], '\n', dict(df.loc['b']))
print('-' * 30)

# 使用iloc访问行,需要使用行的位置索引
print(df.iloc[3], '\n', dict(df.iloc[3]))
print('-' * 30)

# 添加
newrow = pd.DataFrame([[10, 20], [30, 40]], columns=['one', 'two'], index=['f', 'g'])
df = df.append(newrow)
print(df)
print('-' * 30)

# 删除
df = df.drop('b')
print(df)
   one  two
a  1.0  NaN
b  2.0  2.0
c  3.0  3.0
d  NaN  4.0
e  NaN  5.0
------------------------------
   one  two
b  2.0  2.0
c  3.0  3.0
d  NaN  4.0
------------------------------
one    2.0
two    2.0
Name: b, dtype: float64 
 {'one': 2.0, 'two': 2.0}
------------------------------
one    NaN
two    4.0
Name: d, dtype: float64 
 {'one': nan, 'two': 4.0}
------------------------------
    one   two
a   1.0   NaN
b   2.0   2.0
c   3.0   3.0
d   NaN   4.0
e   NaN   5.0
f  10.0  20.0
g  30.0  40.0
------------------------------
    one   two
a   1.0   NaN
c   3.0   3.0
d   NaN   4.0
e   NaN   5.0
f  10.0  20.0
g  30.0  40.0

      3.5、条件查询、索引器查询

import pandas as pd
import numpy as np

df = pd.DataFrame(np.random.randint(1, 10, (4, 4)),
                  columns=['c1', 'c2', 'c3', 'c4'],
                  index=['i1', 'i2', 'i3', 'i4'])
print(df)
print('-' * 30)

# 条件索引
print(df[df['c1'] >= 5])
print('-' * 30)

# 多条件
print(df[(df['c1'] >= 5) & (df['c3'] <= 5)])
print('-' * 30)

# 索引器,其实也就是loc和iloc,首先传入行,再传入列
print(df.loc[['i1', 'i3'], ['c2', 'c4']])
print('-' * 30)
print(df.loc[df['c1'] >= 5, ['c2', 'c4']])
print('-' * 30)
print(df.iloc[0:2, 1:3])
#运行结果
    c1  c2  c3  c4
i1   1   5   8   9
i2   1   2   3   3
i3   4   9   5   7
i4   7   9   1   4
------------------------------
    c1  c2  c3  c4
i4   7   9   1   4
------------------------------
    c1  c2  c3  c4
i4   7   9   1   4
------------------------------
    c2  c4
i1   5   9
i3   9   7
------------------------------
    c2  c4
i4   9   4
------------------------------
    c2  c3
i1   5   8
i2   2   3

      3.6、DataFrame的常用方法

方法描述
rename(columns,index,inplace)修改行名、列名
columns:修改列名,index:修改行名,inplace:是否在原数据中进行修改,默认为False
insert(loc,column,value,allow_duplicates)插入列
loc:插入的位置,column:列名,value:值,allow_duplicates是否允许列名重复,默认为False
drop(labels,axis,index,inplace)删除
labels:行/列的名,index:行/列的位置(与labels等效,两者选一),axis:删除行还是列,默认为0表示删除行,inplace:是否在原数据上删除,默认为False
head(n)、tail(n)首尾n行
import pandas as pd
import numpy as np

df = pd.DataFrame(np.random.randint(1, 10, (4, 4)),
                  columns=['c1', 'c2', 'c3', 'c4'],
                  index=['i1', 'i2', 'i3', 'i4'])
# 原数组
print(df)
print('-' * 30)

# 修改行列名
df.rename(index={'i1': 0, 'i2': 1}, inplace=True)  # 修改行名
df.rename(columns={'c1': '3', 'c2': '4'}, inplace=True)  # 修改列名
print(df)
print('-' * 30)

# 插入列
df.insert(loc=2, column='5', value=[100, 200, 300, 400])
print(df)
print('-' * 30)

# 删除行列
df.drop(axis=0, labels='i3', inplace=True)  # 删除行
df.drop(axis=1, labels='5', inplace=True)  # 删除列
print(df)
print('-' * 30)

# 获取首行和尾两行
print(df.head(1))
print('-' * 30)
print(df.tail(2))
#运行结果
    c1  c2  c3  c4
i1   7   9   5   3
i2   2   8   2   6
i3   7   9   7   7
i4   5   7   5   9
------------------------------
    3  4  c3  c4
0   7  9   5   3
1   2  8   2   6
i3  7  9   7   7
i4  5  7   5   9
------------------------------
    3  4    5  c3  c4
0   7  9  100   5   3
1   2  8  200   2   6
i3  7  9  300   7   7
i4  5  7  400   5   9
------------------------------
    3  4  c3  c4
0   7  9   5   3
1   2  8   2   6
i4  5  7   5   9
------------------------------
   3  4  c3  c4
0  7  9   5   3
------------------------------
    3  4  c3  c4
1   2  8   2   6
i4  5  7   5   9

      3.7、DataFrame的常用属性

属性描述
head(num)、tail(num)前num行、后num行数据
values返回数据,是一个二维的ndarray数组
size元素的元素数量(不是行数,一行可能包含多个元素)
axes返回包含行标签、列标签的列表
ndim轴的数量
shape返回一个元组,表示DataFrame的维度
dtypes返回每列数据的数据类型
T转置
shift(peroids,freq,axis,fill_value)将行/列移动指定步幅长度
peroids类型为int,表示移动的幅度,默认为1,正数表示向下/右移动
freq表示日期偏移量,适用于时间序,默认为None
axis为0表示上下移动,为1表示左右移动,默认为0
fill_value用来填充缺失值
import pandas as pd

df = pd.DataFrame({'a_data': [28, 71, 37, 16, 58], 'b_data': [35, 25, 17, 39, 54], 'c_data': [36, 51, 34, 56, 71]})
print(df)
print('-' * 30)
df = df.shift(periods=1).shift(periods=1, axis=1)
print(df)
print('-' * 30)
df = df.shift(periods=1, axis=1, fill_value='a')
print(df)
   a_data  b_data  c_data
0      28      35      36
1      71      25      51
2      37      17      34
3      16      39      56
4      58      54      71
------------------------------
   a_data  b_data  c_data
0     NaN     NaN     NaN
1     NaN    28.0    35.0
2     NaN    71.0    25.0
3     NaN    37.0    17.0
4     NaN    16.0    39.0
------------------------------
  a_data b_data c_data
0      a    NaN    NaN
1      a    NaN     28
2      a    NaN     71
3      a    NaN     37
4      a    NaN     16

      3.8、统计函数

方法描述
count()统计非空值的数量
sum()求和
mean()均值
median()中位数
mode()众数
std()标准差
min()最小值
max()最大值
abs()绝对值
prod()所有数值的乘积
cumsum()axis=0:按行累加,axis=1:按列累加
cumprod()axis=0:按行累积,axis=1:按列累积
corr()计算数列或变量之间的相关系数,取值-1到1,越接近1相关性越强
describe(include=‘all’)统计信息摘要
import pandas as pd

# 创建字典型series结构
d = {'Name': pd.Series(['小明', '小亮', '小红', '小华', '老赵', '小曹', '小陈',
                        '老李', '老王', '小冯', '小何', '老张']),
     'Age': pd.Series([25, 26, 25, 23, 30, 29, 23, 34, 40, 30, 51, 46]),
     'Rating': pd.Series([4.23, 3.24, 3.98, 2.56, 3.20, 4.6, 3.8, 3.78, 2.98, 4.80, 4.10, 3.65])
     }
df = pd.DataFrame(d)
print(df)
print('-' * 30)
print(df.sum())
print('-' * 30)
print(df.sum(axis=1))
print('-' * 30)
print(df.describe(include='all'))
   Name  Age  Rating
0    小明   25    4.23
1    小亮   26    3.24
2    小红   25    3.98
3    小华   23    2.56
4    老赵   30    3.20
5    小曹   29    4.60
6    小陈   23    3.80
7    老李   34    3.78
8    老王   40    2.98
9    小冯   30    4.80
10   小何   51    4.10
11   老张   46    3.65
------------------------------
Name      小明小亮小红小华老赵小曹小陈老李老王小冯小何老张
Age                            382
Rating                       44.92
dtype: object
------------------------------
0     29.23
1     29.24
2     28.98
3     25.56
4     33.20
5     33.60
6     26.80
7     37.78
8     42.98
9     34.80
10    55.10
11    49.65
dtype: float64
------------------------------
       Name        Age     Rating
count    12  12.000000  12.000000
unique   12        NaN        NaN
top      小亮        NaN        NaN
freq      1        NaN        NaN
mean    NaN  31.833333   3.743333
std     NaN   9.232682   0.661628
min     NaN  23.000000   2.560000
25%     NaN  25.000000   3.230000
50%     NaN  29.500000   3.790000
75%     NaN  35.500000   4.132500
max     NaN  51.000000   4.800000

4、Pandas绘图 —— plot

      4.1、plot介绍

DataFrame.plot(x=None, y=None, kind='line', ax=None, subplots=False, 
                sharex=None, sharey=False, layout=None, figsize=None, 
                use_index=True, title=None, grid=None, legend=True, 
                style=None, logx=False, logy=False, loglog=False, 
                xticks=None, yticks=None, xlim=None, ylim=None, rot=None, 
                fontsize=None, colormap=None, position=0.5, table=False, yerr=None, 
                xerr=None, stacked=True/False, sort_columns=False, 
                secondary_y=False, mark_right=True, **kwds)

        plot 函数是 Pandas 中的一个函数,用于绘制数据的图表。它是基于 Matplotlib 库实现的,能够直接在 Pandas 的 Series 和 DataFrame 对象上使用,提供了一种简单而强大的数据可视化功能。plot 函数可以绘制多种类型的图表,如折线图、柱状图、散点图、箱线图等,具体的图表类型由 kind 参数指定, 使用DataFrame的plot方法绘制图像会按照数据的每一列绘制一条曲线,默认按照列columns的名称在适当的位置展示图例,比matplotlib绘制节省时间,且DataFrame格式的数据更规范,方便向量化及计算

      4.2、plot主要参数

参数描述
kind绘图类型
line:折线图、bar:条形图(Stacked=True时为堆叠柱状图)、barh:横向条形图
hist:直方图、box:箱型图、area:面积图(Stacked=True时,每列的正负性要相同)
kde:密度图、pie:饼状图、scatter:散点图、hexbin:蜂巢图
subplots指定图表的行数和列数,从而创建一个由多个子图组成的矩阵式布局
搭配layout可以设置子图的布局
grid显示或隐藏网格线
legend图例,用于解释图表中各个数据系列的含义
logx在 x 轴上使用对数刻度
logy在 y 轴上使用对数刻度
loglog在 x 轴和 y 轴上同时使用对数刻度
xlim&ylim设置 x 轴和 y 轴的刻度范围。可以传递一个包含两个元素的列表或元组,分别表示轴的最小值和最大值
fontsize设置图表中的字体大小
style / color / colors自定义颜色,不同的统计图可能需要的参数不一样
secondary_y设置右边的y轴

      4.3、折线图

            4.3.1、折线图

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

# 生成一千条符合标准正太分布的数据(此时数据扎堆在0附近),index是日期,列名记为ABCD
df = pd.DataFrame(np.random.randn(1000, 4), index=pd.date_range('1/1/2000', periods=1000), columns=list('ABCD'))
print(df)
print('-' * 30)
# 对原数组的数据做下改造,使不会扎堆在0附近
df = df.cumsum()
print(df)
print('-' * 30)
# df.plot用于构建成一个图表对象(AxesSubplot),行索引做x轴,列数表示有几条数据
# 若行索引index中包含日期,Pandas 会自动调用 gct().autofmt_xdate() 来格式化x轴
df.plot(kind='line',  # 折线图
        grid=True,  # 显示表格
        color=['#79CDCD', '#EEB4B4', '#6CA6CD', '#FFA54F'],  # 自定义颜色
        )

# 将现有的图表对象显示出来
plt.show()

在这里插入图片描述

            4.3.2、多个子图

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

# 生成一千条符合标准正太分布的数据(此时数据扎堆在0附近),index是日期,列名记为ABCD
df = pd.DataFrame(np.random.randn(1000, 4), index=pd.date_range('1/1/2000', periods=1000), columns=list('ABCD'))
print(df)
print('-' * 30)
# 对原数组的数据做下改造,使不会扎堆在0附近
df = df.cumsum()
print(df)
print('-' * 30)
# df.plot用于构建成一个图表对象(AxesSubplot),行索引做x轴,列数表示有几条数据
# 若行索引index中包含日期,Pandas 会自动调用 gct().autofmt_xdate() 来格式化x轴
df.plot(kind='line',  # 折线图
        grid=True,  # 显示表格
        color=['#79CDCD', '#EEB4B4', '#6CA6CD', '#FFA54F'],  # 自定义颜色
        subplots=True  # 每列数据在一个子图中展示
        )

# 将现有的图表对象显示出来
plt.show()

在这里插入图片描述

            4.3.3、多个子图任意排列

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

# 生成一千条符合标准正太分布的数据(此时数据扎堆在0附近),index是日期,列名记为ABCD
df = pd.DataFrame(np.random.randn(1000, 4), index=pd.date_range('1/1/2000', periods=1000), columns=list('ABCD'))
print(df)
print('-' * 30)
# 对原数组的数据做下改造,使不会扎堆在0附近
df = df.cumsum()
print(df)
print('-' * 30)
# df.plot用于构建成一个图表对象(AxesSubplot),行索引做x轴,列数表示有几条数据
# 若行索引index中包含日期,Pandas 会自动调用 gct().autofmt_xdate() 来格式化x轴
df.plot(kind='line',  # 折线图
        grid=True,  # 显示表格
        color=['#79CDCD', '#EEB4B4', '#6CA6CD', '#FFA54F'],  # 自定义颜色
        subplots=True,  # 每列数据在一个子图中展示
        layout=(2, 2)  # 子图布局
        )

# 将现有的图表对象显示出来
plt.show()

在这里插入图片描述

            4.3.4、主副轴设置

import numpy as np
import pandas as pd
from matplotlib.axes._subplots import Axes
from matplotlib import pyplot as plt

df = pd.DataFrame(np.random.randn(1000, 4), index=pd.date_range('1/1/2000', periods=1000), columns=list('ABCD'))
df = df.cumsum()
# 编辑代码时,Pycharm不知道df.plot返回的是个什么东西,因此可以用ax:Axes来指明,这样下面使用ax的属性方法时,Pycharm才会有提示
ax: Axes = df.plot(kind='line',
                   grid=True,
                   style=['#79CDCD', '#EEB4B4', '#6CA6CD', '#FFA54F'],  # 自定义颜色
                   secondary_y=['A', 'B'],  # 将AB列放在副轴上
                   )
# 使用图表对象的方法来修改图表
ax.set_ylabel('CD scale')  # 主轴名
ax.legend(loc='upper left')  # 主轴的标签显示在左上
ax.right_ax.set_ylabel('AB scale')  # 副轴名
ax.right_ax.legend(loc='upper right')  # 副轴的标签显示在右上
# 将现有的图表对象显示出来
plt.show()

在这里插入图片描述

      4.4、条形图

            4.4.1、显示Series数据

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

# 设置中文字体为宋体,因为要在图中显示文字
matplotlib.rcParams['font.family'] = ['SimSun']
# 创建一个 2x2 的子图布局,返回的是画布和子图对象数组
fig, axes = plt.subplots(nrows=2, ncols=2)
# 创建十组数据
df = pd.DataFrame(np.random.rand(10, 4), columns=['a', 'b', 'c', 'd'])
# axes.flat返回每个子图对象,enumerate能在遍历的同时返回下标
for i, ax in enumerate(axes.flat):
    df.iloc[i].plot(kind='bar',  # 柱状图
                    ax=ax,  # 将结果赋值给画布上的子图
                    color=['#79CDCD', '#EEB4B4', '#6CA6CD', '#FFA54F'],  # 自定义颜色
                    )  # 自定义颜色
    ax.set_title('第 {} 组数据'.format(i))  # 设置子图标题
# 显示
plt.show()

在这里插入图片描述

            4.4.2、显示DateFrame数据

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

# 创建四数据
df = pd.DataFrame(np.random.rand(4, 4), columns=['a', 'b', 'c', 'd'])
df.plot(kind='bar', color=['#79CDCD', '#EEB4B4', '#6CA6CD', '#FFA54F'])
# 显示
plt.show()

在这里插入图片描述

Tip:对于Series数据,每个标签占一个bar,标签之间会有分隔,对于DataFrame数据,每组数据占一组bar,每组数据之间会有分隔

            4.4.3、堆积条形图

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

# 创建四数据
df = pd.DataFrame(np.random.rand(4, 4), columns=['a', 'b', 'c', 'd'])
df.plot(kind='bar',
        color=['#79CDCD', '#EEB4B4', '#6CA6CD', '#FFA54F'],
        stacked=True)
# 显示
plt.show()

在这里插入图片描述

            4.4.4、水平条形图

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

# 创建四数据
df = pd.DataFrame(np.random.rand(4, 4), columns=['a', 'b', 'c', 'd'])
df.plot(kind='barh',
        color=['#79CDCD', '#EEB4B4', '#6CA6CD', '#FFA54F'],
        stacked=True)
# 显示
plt.show()

在这里插入图片描述

            4.4.5、直方图

直方图常用于以下情况:
① 展示数据的分布情况:直方图可以直观地展示数据的分布特征,如数据的中心位置、离散程度、偏态和峰度等。
② 检查数据的异常值:直方图可以帮助识别数据中的异常值,例如是否有超出正常范围的极端值。
③ 分析数据的特征:直方图可以帮助理解数据的特征,如数据的集中程度、分布形态等,从而为后续的数据分析和建模提供参考。
通过观察直方图,可以快速了解数据的整体分布情况,有助于进一步的数据分析和决策

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

# 创建四数据
df = pd.DataFrame(np.random.rand(4, 4), columns=['a', 'b', 'c', 'd'])
print(df)
df.plot(kind='hist',
        color=['#79CDCD', '#EEB4B4', '#6CA6CD', '#FFA54F'])
# 显示
plt.show()

在这里插入图片描述

            4.4.6、箱式图

箱线图通常包含以下几个部分:
① 箱体(Box):箱体表示数据的四分位数范围,箱体的上边界是数据的第三四分位数(Q3:75%),下边界是数据的第一四分位数(Q1:25%),箱体内部的水平线表示数据的中位数(Q2:50%),例如65,70,72,75,78,80,82,85,88,90的Q1=1025%=2.5=>第3位:72;Q2=中位数=(75+78)/2=76.5;Q3=1075%=7.5=>第8位:85;因此箱体的范围占数据的一半25%~75%
② 上限(Whisker):上限和下限表示数据的边界,它们通常是箱体顶部和底部的最大值和最小值,但也可以根据具体的定义方式而有所不同。上限和下限之外的数据点称为离群值(Outlier)

箱线图常用于以下情况:
① 观察数据的分布情况:箱线图可以帮助识别数据的中位数、四分位数以及离群值,从而了解数据的分布特征
② 比较不同组数据的分布:箱线图可以同时展示多个组的数据分布情况,方便比较不同组之间的差异和相似性

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

# 创建十条数据
df = pd.DataFrame(np.random.rand(10, 4), columns=['a', 'b', 'c', 'd'])
print(df)
df.plot(kind='box')
# 显示
plt.show()

在这里插入图片描述

      4.5、面积图

            4.5.1、堆积型

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

# 创建十条数据
df = pd.DataFrame(np.random.rand(10, 4), columns=['a', 'b', 'c', 'd'])
print(df)
df.plot(kind='area',
        color=['#79CDCD', '#EEB4B4', '#6CA6CD', '#FFA54F'])
# 显示
plt.show()

在这里插入图片描述

            4.5.2、非堆积型

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

# 创建十条数据
df = pd.DataFrame(np.random.rand(10, 4), columns=['a', 'b', 'c', 'd'])
print(df)
df.plot(kind='area',
        color=['#79CDCD', '#EEB4B4', '#6CA6CD', '#FFA54F'],
        stacked=False)
# 显示
plt.show()

在这里插入图片描述

      4.6、饼状图

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

# 创建四条数据
df = pd.DataFrame(np.random.rand(4, 4), columns=['P1', 'P2', 'P3', 'P4'], index=['a', 'b', 'c', 'd'])
df.plot(kind='pie',
        colors=['#79CDCD', '#EEB4B4', '#6CA6CD', '#FFA54F'],  # 自定义颜色
        subplots=True,
        layout=(2, 2),
        figsize=(8, 6))
# 显示
plt.show()

在这里插入图片描述

      4.7、核密度图

核密度估计图:一种用于估计概率密度函数的非参数方法,它可以帮助我们了解数据的分布情况,是在直方图的基础上进行了平滑处理,它使用核函数(通常是高斯核函数)对每个数据点附近的概率密度进行估计,并将所有核函数的估计值进行叠加,最终得到一条连续的曲线,表示数据的概率密度函数。核密度图可以提供比直方图更平滑的数据分布曲线,帮助我们更直观地了解数据的分布特征

安装依赖(使用该模块来计算核密度):pip install scipy

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

# 创建一个 2x2 的子图布局,返回的是画布和子图对象数组
fig, axes = plt.subplots(nrows=1, ncols=2)

# 创建20条数据
df = pd.DataFrame(np.random.rand(20, 4), columns=['a', 'b', 'c', 'd'])
df2 = df.copy()

# 核密度图
df.plot(kind='kde',
        ax=axes[0],
        color=['#79CDCD', '#EEB4B4', '#6CA6CD', '#FFA54F'],
        figsize=(14, 6))

# 对应的直方图
df2.plot(kind='hist',
         bins=20,
         ax=axes[1],
         color=['#79CDCD', '#EEB4B4', '#6CA6CD', '#FFA54F'],
         figsize=(14, 6))

# 显示
plt.show()

在这里插入图片描述

5、读写文件

      5.1、CSV 是什么

        CSV(Comma-Separated Values)是一种常用的文本文件格式,用于存储表格数据。在 CSV 文件中,数据以逗号或其他分隔符(如分号、制表符等)分隔,每行代表表格中的一行数据记录,每个字段代表记录中的一个属性值,CSV 文件通常以 .csv 扩展名结尾,它是一种通用的数据交换格式,可以被几乎所有的数据处理软件和编程语言所支持

      5.2、CSV 文件的优点

        ① 简单易用:CSV 文件使用纯文本格式存储数据,易于创建和编辑,且通用性强
        ② 跨平台兼容:CSV 文件可以在不同操作系统和软件之间进行数据交换,具有较好的跨平台兼容性
        ③ 轻量级:CSV 文件相比于其他数据存储格式(如 Excel 文件)通常更加轻量级,存储效率高

      5.3、CSV 文件的缺点

        ① 不支持复杂数据结构:CSV 文件仅支持平面表格数据的存储,不支持复杂的数据结构(如嵌套表格、多表关联等)
        ② 不支持元数据:CSV 文件不支持存储数据的元数据信息,如数据类型、索引等,需要额外的处理来解决。

      5.4、读 CSV 文件 —— read_csv

        ① 常用参数

pd.read_csv(filepath_or_buffer,  # 文件名
            sep=',',  # 字段之间的分隔符,默认为逗号 ,
            delimiter=None,  # 作用同sep,若同时指定了 sep 和 delimiter,则以 delimiter 为准
            header='infer',  # 列名的行号。默认值为 'infer',表示 Pandas 将尝试自动推断列名
            names=None,  # 指定自定义的列名列表,如果 header=None,则通过 names 参数指定列名
            index_col=None,  # 指定哪一列作为索引列
            usecols=None)  # 指定要读取的列

        ② 例子

#编写person.csv文件
ID,Name,Age,City,Salary
1,Jack,28,Beijing,22000
2,Lida,32,Shanghai,19000
3,John,43,Shenzhen,12000
4,Helen,38,Hengshui,3500
import pandas as pd
from pandas import DataFrame
import numpy as np

# 直接读取,将会得到一个DataFrame对象
df1: DataFrame = pd.read_csv('./person.csv',  # 读取的文件
                             header=0,  # 将原来的列名删除
                             names=['i', 'n', 'a', 'c', 's'],  # 自定义列名
                             dtype={'s': np.float64}  # 重新指定字段的类型
                             )
print(df1)
print('-' * 30)

# 查看每一列的类型
print(df1.dtypes)
print('-' * 30)

# 选取一个字段做索引
df2 = pd.read_csv('./person.csv',  # 文件名
                  index_col=0, )  # 选取第一列来做为索引,也可以写index_col=['ID']
print(df2)
print('-' * 30)

# 从csv文件的指定行开始读取
df3 = pd.read_csv('./person.csv',  # 文件名
                  skiprows=2)  # 跳过前两行再开始读取
print(df3)
#运行结果
   i      n   a         c        s
0  1   Jack  28   Beijing  22000.0
1  2   Lida  32  Shanghai  19000.0
2  3   John  43  Shenzhen  12000.0
3  4  Helen  38  Hengshui   3500.0
------------------------------
i      int64
n     object
a      int64
c     object
s    float64
dtype: object
------------------------------
     Name  Age      City  Salary
ID                              
1    Jack   28   Beijing   22000
2    Lida   32  Shanghai   19000
3    John   43  Shenzhen   12000
4   Helen   38  Hengshui    3500
------------------------------
   2   Lida  32  Shanghai  19000
0  3   John  43  Shenzhen  12000
1  4  Helen  38  Hengshui   3500

      5.5、写 CSV 文件 —— to_csv

        ① 常用参数

df.to_csv(path_or_buf,  # 要写入的 CSV 文件的路径或者一个类文件对象
          sep=",",  # 指定字段之间的分隔符
          na_rep="",  # 用于替换缺失值的字符串
          columns=None,  # 要写入的列,可以是一个列名列表,指定写入的列顺序,也可以是一个字典,用于重命名列
          header=True,  # 是否写入列名
          index=True,  # 是否写入索引
          mode="w",  # 文件打开模式
          encoding="utf-8",  # 编码
          line_terminator=r"\n",  # 行终止符
          date_format=None,  # 日期格式
          chunksize=None,  # 写入时的分块大小
          )

        ② 例子

import pandas as pd

data = {'Name': ['Smith', 'Parker'],
        'ID': [101, 102],
        'Language': ['Python', 'JavaScript']}
df = pd.DataFrame(data)
print(df)
print('-' * 30)
# 转换为csv数据
csv_data = df.to_csv(sep='|')
print(csv_data)
#运行结果
     Name   ID    Language
0   Smith  101      Python
1  Parker  102  JavaScript
------------------------------
|Name|ID|Language
0|Smith|101|Python
1|Parker|102|JavaScript

      5.6、写 Excel 文件 —— to_excel

安装依赖:pip install openpyxl

        ① 常用参数

df.to_excel(excel_writer,  # 要写入的 Excel 文件的路径或者一个 ExcelWriter 对象
            sheet_name='Sheet1',  # 要写入的工作表的名称
            na_rep='',  # 替换缺失值的字符串
            float_format=None,  # 指定浮点数的格式
            columns=None,  # 要写入的列
            header=True,  # 指定是否写入列名
            index=True,  # 指定是否写入索引
            index_label=None,  # 指定索引列的名称
            startrow=0,  # 数据写入的起始行
            startcol=0,  # 数据写入的起始列
            engine=None,  # 使用的引擎
            merge_cells=True,  # 是否合并单元格
            encoding=None,  # 文件编码
            inf_rep='inf',  # 替换正负无穷值的字符串
            verbose=True,  # 是否显示写入过程中的详细信息
            freeze_panes=None)  # 指定要冻结的窗格

        ② 例子

import pandas as pd
from openpyxl.styles import Font, Alignment
from openpyxl.utils import get_column_letter

font = Font(name='Microsoft YaHei', size=11)  # 字体样式
alignment = Alignment(horizontal='center', vertical='center')  # 字体布局

# 创建DataFrame数据
df = pd.DataFrame({'name': ['编程帮', 'c语言中文网', '微学苑', '92python'],
                   'rank': [1, 2, 3, 4],
                   'language': ['PHP', 'C', 'PHP', 'Python'],
                   'url': ['www.bianchneg.com', 'c.bianchneg.net', 'www.weixueyuan.com', 'www.92python.com']})
# 创建ExcelWrite对象
writer = pd.ExcelWriter('./website.xlsx')
# 将数据传入
df.to_excel(writer)
# 修改xlxs中的样式
book = writer.book  # excel表
sheet = book.active  # 工作表
for row in sheet.iter_rows(min_row=1, min_col=1, max_row=sheet.max_row, max_col=sheet.max_column):
    for cell in row:
        cell.font = font  # 将字体设置为微软雅黑 11号
        cell.alignment = alignment  # 居中
for i, col in enumerate(df.columns):
    max_length = max(df[col].astype(str).map(len).max(), len(col))  # 计算每列的最大长度
    sheet.column_dimensions[get_column_letter(i + 2)].width = max_length + 8  # 设置列宽

# 保存
writer.save()

在这里插入图片描述

      5.7、读 Excel 文件 —— read_excel

        ① 常用参数

pd.read_excel(io,  # excel文件的路径
              sheet_name=0,  # excel的工作表名
              header=0,  # 指定作为列名的行,不包含列明的话可以设定header=None,header=2表示将前两行作为多重索引
              names=None,  # 自定义列名
              index_col=None,  # 指定某一列的数据来作为行索引
              usecols=None,  # 要读取的列,默认为None表示要读取所有列
              squeeze=False,  # 是否将返回的 DataFrame 对象转换为 Series 对象
              dtype=None,  # 指定列的数据类型
              engine=None,  # 使用的解析引擎
              converters=None,  # 指定列的转换函数
              true_values=None,  # 指定布尔类型的字符串表示,默认为True
              false_values=None,  # 指定布尔类型的字符串表示,默认为False
              skiprows=None,  # 跳过指定的行数
              nrows=None,  # 要读取的行数
              na_values=None,  # 缺失值的字符串表示
              parse_dates=False,  # 是否将日期型数据解析为 datetime 对象
              date_parser=None,  # 解析日期型数据的函数
              thousands=None,  # 指定千位分隔符的字符
              comment=None,  # 指定注释的字符
              skipfooter=0,  # 要忽略末尾的某几行
              convert_float=True)  # 是否将整数类型的列转换为浮点型

        ② 例子

import pandas as pd
from pandas import DataFrame

# 读取Excel文件的所有数据
df1: DataFrame = pd.read_excel('./website.xlsx',  # 路径
                               engine='openpyxl',  # 解析引擎
                               index_col="name",  # 用name这一列来作为索引
                               )
df1.columns = df1.columns.str.replace('Unnamed.*', 'col_label')  # 将excel中的index的列名为空,转换成df之后空列名变成‘Unnameed:’,因此可以重命名一下
print(df1)
print('-' * 30)

# 读取Excel文件的部分数据+双重索引
df2: DataFrame = pd.read_excel('./website.xlsx',  # 路径
                               engine='openpyxl',  # 解析引擎
                               index_col=[1, 2],  # 用两列来做索引(从0开始)
                               usecols=[1, 2, 3]  # 选取excel中的三列(从0开始)
                               )
df2.columns = df2.columns.str.replace('Unnamed.*', 'col_label')  # 将excel中的index的列名为空,转换成df之后空列名变成‘Unnameed:’,因此可以重命名一下
print(df2)
#运行结果
          col_label  rank language                 url
name                                                  
编程帮               0     1      PHP   www.bianchneg.com
c语言中文网            1     2        C     c.bianchneg.net
微学苑               2     3      PHP  www.weixueyuan.com
92python          3     4   Python    www.92python.com
------------------------------
                   name
rank language          
1    PHP            编程帮
2    C           c语言中文网
3    PHP            微学苑
4    Python    92python

6、数据表互联、分组聚合、数据透视

      6.1、数据表互联

方法描述
merge用于根据一个或多个 键(列值) 将不同的 DataFrame 中的行连接起来
concat用于沿着指定轴将多个 DataFrame 连接起来
join用于根据 DataFrame 的 索引(行标签) 连接两个 DataFrame
append用于将一个 DataFrame 添加到另一个 DataFrame 的末尾
import pandas as pd

# merge:联表(基于关键字/列)
df1 = pd.DataFrame({'key': ['A', 'B', 'C', 'D'], 'value': [1, 2, 3, 4]})
df2 = pd.DataFrame({'key': ['B', 'D', 'E', 'F'], 'value': [5, 6, 7, 8]})
merged_df = pd.merge(df1, df2, on='key', how='outer')  # outer取并集
print(merged_df)
print('-' * 30)

# concat:沿指定轴合并(纵向/横向)
df1 = pd.DataFrame({'A': ['A0', 'A1', 'A2', 'A3'], 'B': ['B0', 'B1', 'B2', 'B3']})
df2 = pd.DataFrame({'A': ['A4', 'A5', 'A6', 'A7'], 'B': ['B4', 'B5', 'B6', 'B7']})
concatenated_df1 = pd.concat([df1, df2], axis=0)
print(concatenated_df1)
print('-' * 30)
concatenated_df2 = pd.concat([df1, df2], axis=1)
print(concatenated_df2)
print('-' * 30)

# join:链表(基于index/行)
df1 = pd.DataFrame({'value1': [1, 2, 3, 4]}, index=['A', 'B', 'C', 'D'])
df2 = pd.DataFrame({'value2': [5, 6, 7, 8]}, index=['B', 'D', 'E', 'F'])
joined_df = df1.join(df2, how='outer')
print(joined_df)
print('-' * 30)

# append:纵向合并
df1 = pd.DataFrame({'A': ['A0', 'A1', 'A2', 'A3'], 'B': ['B0', 'B1', 'B2', 'B3']})
df2 = pd.DataFrame({'A': ['A4', 'A5', 'A6', 'A7'], 'B': ['B4', 'B5', 'B6', 'B7']})
appended_df = df1.append(df2)
print(appended_df)
  key  value_x  value_y
0   A      1.0      NaN
1   B      2.0      5.0
2   C      3.0      NaN
3   D      4.0      6.0
4   E      NaN      7.0
5   F      NaN      8.0
------------------------------
    A   B
0  A0  B0
1  A1  B1
2  A2  B2
3  A3  B3
0  A4  B4
1  A5  B5
2  A6  B6
3  A7  B7
------------------------------
    A   B   A   B
0  A0  B0  A4  B4
1  A1  B1  A5  B5
2  A2  B2  A6  B6
3  A3  B3  A7  B7
------------------------------
   value1  value2
A     1.0     NaN
B     2.0     5.0
C     3.0     NaN
D     4.0     6.0
E     NaN     7.0
F     NaN     8.0
------------------------------
    A   B
0  A0  B0
1  A1  B1
2  A2  B2
3  A3  B3
0  A4  B4
1  A5  B5
2  A6  B6
3  A7  B7

      6.2、分组聚合

方式描述
groupby用于对数据进行分组
agg用于对分组后的数据进行聚合操作
import pandas as pd

# 创建示例 DataFrame
df = pd.DataFrame({'A': ['foo', 'bar', 'foo', 'bar', 'foo'],
                   'B': ['one', 'one', 'two', 'two', 'one'],
                   'C': [1, 2, 3, 4, 5]})
# 按列 'A' 进行分组
grouped = df.groupby('A')
# 显示分组后的数据
for name, group in grouped:
    print(name)
    print(group)
    print('-' * 30)
# 对分组后的数据进行聚合操作,计算每个分组的平均值和总和
aggregated = grouped.agg({'C': ['mean', 'sum']})
print(aggregated)
bar
     A    B  C
1  bar  one  2
3  bar  two  4
------------------------------
foo
     A    B  C
0  foo  one  1
2  foo  two  3
4  foo  one  5
------------------------------
       C    
    mean sum
A           
bar    3   6
foo    3   9

      6.3、数据透视

数据透视:一种数据分析技术,用于对大量数据进行汇总和分析,以便更好地理解数据之间的关系和趋势。数据透视可以将复杂的数据结构简化为易于理解的形式,提供对数据的直观认识和深入洞察

数据透视表(Pivot Table):数据透视技术的一种实现形式,它通过对数据进行汇总、分组和聚合操作,以多维度、多层次的方式展示数据,从而揭示数据之间的内在关系和规律

df.pivot_table(
    index=None,  # 用于分组的列或者列名,即将要在结果中作为行索引的列。
    columns=None,  # 用于分组的列或者列名,即将要在结果中作为列索引的列。
    values=None,  # 要聚合的列或者列名,即要在结果中显示的数据。
    aggfunc="mean"  # 指定对数据进行聚合计算的函数,例如 sum、mean、count 等,默认为 numpy.mean
)
import pandas as pd

# 创建示例 DataFrame
df = pd.DataFrame({'A': ['foo', 'foo', 'foo', 'bar', 'bar', 'bar'],
                   'B': ['one', 'one', 'two', 'two', 'one', 'one'],
                   'C': [1, 2, 3, 4, 5, 6],
                   'D': [7, 8, 9, 10, 11, 12]})
print(df)
print('-' * 30)
# 使用 pivot_table 创建数据透视表
pivot = df.pivot_table(index='A',  # 对A做分组,A作为数据透视表的索引
                       columns='B',  # 对B做分组,B作为数据透视表的列
                       values='C',  # 对C列做聚合
                       aggfunc='sum')  # 统计每个分组,例如(bar,one),的C的总和
print(pivot)
     A    B  C   D
0  foo  one  1   7
1  foo  one  2   8
2  foo  two  3   9
3  bar  two  4  10
4  bar  one  5  11
5  bar  one  6  12
------------------------------
B    one  two
A            
bar   11    4
foo    3    3

7、声明

        本文参考了:
        UQI-LIUWJ 的文章 pandas 知识点补充:绘图plot
        小熊coder 的文章 Pandas教程(非常详细)
        无忘,码民 的文章 python之pandas库,快速学习

        感谢大牛们的分享和帮助!

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值