pandas的高级使用

第12章 pandas高级应用 和其它许多开源项目一样,pandas仍然在不断的变化和进步中。和本书中其它地方一样,这里的重点是放在接下来几年不会发生什么改变且稳定的功能。为了深入学习pandas的知识,我建议你学习官方文档,并阅读开发团队发布的文档更新。我们还邀请你加入pandas的开发工作:修改bug、创建新功能、完善文档。 阅读详情

pandas层次化索引

  • 导入三剑客包
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from pandas import Series,DataFrame
  • 读取外部excel文件
# header 设置为列表,表示第0、1两行同时作为多层级索引读取
pd.read_excel('datas.xlsx', sheet_name=0, header=[0,1])

1. 创建多层列索引

  • 隐式构造

    最常见的方法是给DataFrame构造函数的index参数传递两个或更多的数组

    array_ = [["一季度","一季度","一季度","二季度","二季度","二季度"],["A产品","B产品","C产品","A产品","B产品","C产品"]]
    
    #Series创建多层索引
    data1 = np.random.randint(0,100,size=6)
    DataFrame(Series(data=data1, index=array_))	==>
    		0
    一季度	A产品	43
    	B产品	93
    	C产品	82
    二季度	A产品	79
    	B产品	57
    	C产品	51
    
    #DataFrame创建多层索引
    data = np.random.randint(0,100,size=(3,6))
    index = ["小张","小王","小李"]
     隐式构造,可以直接使用一个array的表达方式类设置多层级索引
    df = DataFrame(data=data, index=index, columns=array_)
    df	==>
    	一季度	二季度
    A产品	B产品	C产品	A产品	B产品	C产品
    小张	59	40	7	25	91	21
    小王	5	70	62	48	42	84
    小李	63	4	96	31	85	50
    
    
  • 显式构造 使用pd.MultiIndex

#三种方式
1、使用数组
array_ = [["一季度","一季度","一季度","二季度","二季度","二季度"],["A产品","B产品","C产品","A产品","B产品","C产品"]]
columns1 = `pd.MultiIndex.from_arrays`(array_)
DataFrame(data=data, index=index, columns=columns1)

2、使用元组
tuple_ = [["一季度","A产品"],["一季度","B产品"],["一季度","C产品"],["二季度","A产品"],["二季度","B产品"],["二季度","C产品"]]
columns2 = `pd.MultiIndex.from_tuples`(tuple_)
DataFrame(data=data, index=index, columns=columns2)

3、使用全排列product
product_ = [["一季度","二季度"],["A产品","B产品","C产品"]]
columns3 = pd.MultiIndex.from_product(product_)
DataFrame(data=data, index=index, columns=columns3)

2. 创建多层行索引

除了列索引columns,行索引index也能用同样的方法创建多层索引

data = data.reshape((6,2))
df1 = DataFrame(data=data, index=columns, columns=index)	==>
张三	李四
期中	python	96	42
java	90	97
PHP	26	32
期末	python	50	67
java	35	23
PHP	93	99

3. 多层索引对象的索引与切片操作

Series的操作

对于Series来说,直接中括号[]与使用.loc()完全一样,推荐使用.loc中括号索引和切片。

  • 索引

    s[一级索引,二级索引]
    s.loc[一级索引,二级索引]

  • 切片

    • 变成单级索引切片

    • 使用隐式索引切片

    • 利用stack、unstack变型之后再切

#索引
s1 ==>
期中  python    26
    java      63
    PHP       85
期末  python    85
    java      80
    PHP       45
Name: 张三, dtype: int32
s1["期中","python"]
s1.loc["期中","python"]	==>26

#切片
s1["期中"]["python":"PHP"]
python    26
java      63
PHP       85
Name: 张三, dtype: int32

DataFrame的操作

  • 隐式访问与切片
df  ==>
	期中	期末
python	java	PHP	python	java	PHP
张三	99	13	68	64	3	15
李四	58	13	91	75	17	49
#访问
df.iloc[1,4]	==> 17
#切片
df.iloc[:,2:4] 	==>
	期中	期末
PHP	python
张三	68	64
李四	91	75
  • 显式访问与切片
df1 ==>

		张三	李四	王五
期中	python	99	13	15
	java	68	64	71
	PHP	3	15	34
期末	python	58	13	4
	java	91	75	61
	PHP	17	49	42
    
  #访问并赋值
df2 = df1.copy()
#变成单机索引(拷贝副本不改变原表的值)
temp = df2.loc["期中"].copy()	==>
	张三	李四	王五
python	99	13	15
java	68	64	71
PHP	3	15	34
#赋值
temp.loc["python","张三"] = 0
#将副本的值赋给单级索引
df2.loc["期中"] = temp.values

  • 行多级索引的索引和切片操作
    • 访问行 df.loc[一级行索引,二级行索引]
    • 访问元素 df.loc[(一级行索引,二级行索引),列索引]
df1 ==>
		张三	李四	王五
期中	python	99	13	15
	java	68	64	71
	PHP	3	15	34
期末	python	58	13	4
	java	91	75	61
	PHP	17	49	42
# 访问行
df1.loc["期中","python"]
# 访问元素
# ("期中","python") 可以用来访问元素,但是不能用来切片
df1.loc[("期中","python"),"张三"]
  • 列多级索引的索引和切片操作
    • . 访问列 df[一级索引,二级索引]
    • 访问元素 df.loc[行索引,(一级列索引,二级列索引)]
df  ==>
	期中			期末
	python	java PHP python	java PHP
张三	96	42	90	97	26	32
李四	50	67	35	23	93	99
#元素访问
df.loc["张三",("期中","python")]  ==>96


4、索引的堆(stack)

tack() 列索引变行索引

  • 【使用技巧】使用stack()的时候,level等于哪一个,哪一个就消失,出现在行里

  • 格式:df.stack(level=-1, dropna=True)

    • level :# level 表示层级 从外向内 依次0123… ,从内到内依次-1,-2,-3…
  • 使用

df   ==>
	期中	期末
python	java	PHP	python	java	PHP
张三	99	13	68	64	3	15
李四	58	13	91	75	17	49

# level=1  和 level=-1效果一样
df.stack(level=1)	==>
		期中	期末
张三	PHP	68	15
	java	13	3
	python	99	64
李四	PHP	91	49
	java	13	17
	python	58	75
    
  #level=0 和 level=-2效果一样
df3 = df.stack(level=0)
		PHP	java	python
张三	期中	68	13	99
	期末	15	3	64
李四	期中	91	13	58
	期末	49	17	75

unstack() 行索引变列索引

使用unstack()的时候,level等于哪一个,哪一个就消失,出现在列里。

#level=0
df3.unstack(level=0)	==>

	PHP	java	python
张三	李四	张三	李四	张三	李四
期中	90	35	42	67	96	50
期末	32	99	26	93	0	23

二者结合使用

df  ==>
	期中	期末
python	java	PHP	python	java	PHP
张三	96	42	90	0	26	32
李四	50	67	35	23	93	99
#列变行 行变列
df.stack(level=0).unstack(level=0)	==>
	PHP	java	python
张三	李四	张三	李四	张三	李四
期中	68	91	13	13	99	58
期末	15	49	3	17	64	75

df.stack(level=1).unstack(level=0)
	期中	期末
张三	李四	张三	李四
PHP	68	91	15	49
java	13	13	3	17
python	99	58	64	75

5、 聚合操作

所谓的聚合操作:平均数,方差,最大值,最小值……

  • 和numpy的区别

    • DataFrame的聚合,默认是列方向的聚合,可以指定axis来改变。计算的时候假如列表中有NaN时,默认当做0计算

      score.sum()

      score.sum(axis=1)

    • numpy默认是对 整个数组聚合,假如求和的数组中有nan时,只能用np.nansum(arr)来处理数组中有nan的情况

      np.nansum(arr)

pandas的拼接操作

级联:pd.concat, pd.append

先定义一个生成DataFrame的函数:

# :
def make_DataFrame(index, columns):
    all_data = []
    for idx in index:
        row_data = []
        for col in columns:
            row_data.append(col + idx)
        all_data.append(row_data)
    return DataFrame(data=all_data, index=index, columns=columns)

#简易写法
def make_df(index, columns):
    return DataFrame({i:[i+str(j) for j in index] for i in columns}, index=index)

  • 使用pd.concat()级联

    • pandas级联考虑索引, 索引对齐原则,对不齐补,numpy级联,只考虑数值

    pandas使用pd.concat函数,与np.concatenate函数类似,只是多了一些参数:

    pd.concat(objs, axis=0, join='outer', join_axes=None, ignore_index=False, keys=None, levels=None, names=None, verify_integrity=False, copy=True)
    #
    objs	df元组
    axis=0	axis控制级联方向,axis=0横向
    join='outer'	参数有outer(外联)、inner(内联)
    join_axes=None	指定以某个索引进行级联,通常和axis一起使用
    ignore_index=False	如果索引没什么实际意义 ignore_index
    keys		如果想保留原始标签,可以使用keys参数,来设置多层级索引表格。一般情况下:ignore_index对行索引重新排列,keys对列索引进行分区
    
    
    • 参数的简单使用
    df1 = make_DataFrame(index=list("1234"),columns=list("ABCD"))
    df2 = make_DataFrame(index=list("2345"), columns=list("ABCD"))
    #numpy级联,只考虑数值
    np.concatenate((df1.values, df2.values))	==>
    array([['A1', 'B1', 'C1', 'D1'],
           ['A2', 'B2', 'C2', 'D2'],
           ['A3', 'B3', 'C3', 'D3'],
           ['A4', 'B4', 'C4', 'D4'],
           ['A2', 'B2', 'C2', 'D2'],
           ['A3', 'B3', 'C3', 'D3'],
           ['A4', 'B4', 'C4', 'D4'],
           ['A5', 'B5', 'C5', 'D5']], dtype=object)
    #pandas级联
    pd.concat((df1, df2),axis=1)
    
    	A	B	C	D	A	B	C	D
    1	A1	B1	C1	D1	NaN	NaN	NaN	NaN
    2	A2	B2	C2	D2	A2	B2	C2	D2
    3	A3	B3	C3	D3	A3	B3	C3	D3
    4	A4	B4	C4	D4	A4	B4	C4	D4
    5	NaN	NaN	NaN	NaN	A5	B5	C5	D5
    #外连接取并集
    df5 = make_DataFrame(index=list("123"), columns=list("BCE"))
    pd.concat((df1,df5), join="outer", axis=1) ==>
    	A	B	C	D	B	C	E
    1	A1	B1	C1	D1	B1	C1	E1
    2	A2	B2	C2	D2	B2	C2	E2
    3	A3	B3	C3	D3	B3	C3	E3
    4	A4	B4	C4	D4	NaN	NaN	NaN
    
    # 内联取交集
    pd.concat((df1,df5), join="inner", axis=1)
    	A	B	C	D	B	C	E
    1	A1	B1	C1	D1	B1	C1	E1
    2	A2	B2	C2	D2	B2	C2	E2
    3	A3	B3	C3	D3	B3	C3	E3
    
    #指定B和C列进行级联
    pd.concat((df1,df5), join_axes=[pd.Index(["B","C"])])
    	B	C
    1	B1	C1
    2	B2	C2
    3	B3	C3
    4	B4	C4
    1	B1	C1
    2	B2	C2
    3	B3	C3
    
    #横向级联,以2和3行为基准
    pd.concat((df1, df5), join_axes=[pd.Index(["2","3"])], axis=1)
    	A	B	C	D	B	C	E
    2	A2	B2	C2	D2	B2	C2	E2
    3	A3	B3	C3	D3	B3	C3	E3
    
    #左连接
    pd.concat((df1, df5), join_axes=[df1.columns])
    A	B	C	D
    1	A1	B1	C1	D1
    2	A2	B2	C2	D2
    3	A3	B3	C3	D3
    4	A4	B4	C4	D4
    1	NaN	B1	C1	NaN
    2	NaN	B2	C2	NaN
    3	NaN	B3	C3	NaN
    
    #右连接
    pd.concat((df1, df5), join_axes=[df5.columns])
    	B	C	E
    1	B1	C1	NaN
    2	B2	C2	NaN
    3	B3	C3	NaN
    4	B4	C4	NaN
    1	B1	C1	E1
    2	B2	C2	E2
    3	B3	C3	E3
    
    # 如果索引没什么实际意义 ignore_index
    pd.concat((df1, df3), ignore_index=True)
    	0	1	2	3	4	5	6
    1	A1	B1	C1	D1	B1	C1	E1
    2	A2	B2	C2	D2	B2	C2	E2
    3	A3	B3	C3	D3	B3	C3	E3
    4	A4	B4	C4	D4	NaN	NaN	NaN
    
    # 如果想保留原始标签,可以使用keys参数,来设置多层级索引表格
    # 一般情况下:ignore_index对行索引重新排列
    #             keys对列索引进行分区
    pd.concat((df1, df3), axis=1, keys=["上学期","下学期"])
    	上学期		下学期
    	A	B	C	D	B	C	E
    1	A1	B1	C1	D1	B1	C1	E1
    2	A2	B2	C2	D2	B2	C2	E2
    3	A3	B3	C3	D3	B3	C3	E3
    4	A4	B4	C4	D4	NaN	NaN	NaN
    
    
    • 使用append()函数添加

      • 格式: df.append(other, ignore_index=False, verify_integrity=False)

    注意:append函数只是沿着axis=0的方向进行级联

    # df ==>	
    	python	JAVA	c
    李四	49	45	39
    王老五	33	24	54
    赵小六	37	57	95
    df1 =DataFrame(data=np.random.randint(0,100,size=(1,3)),index=["张三"], columns=df.columns)
    #
    df.append(df1)
    	python	JAVA	c
    李四	49	45	39
    王老五	33	24	54
    赵小六	37	57	95
    张三	58	59	6
    
    

合并:pd.merge, pd.join

  • merge与concat的区别在于,merge需要依据某一共同【列】来进行合并

  • 使用pd.merge()合并时,会自动根据两者相同column名称的那一列,作为key来进行合并。

    注意:每一列元素的顺序不要求一致

  • merge()的要求:

    • 以【列】(内容)合并参考项
    • 内容【必须】是散列值(离散型)
    • 参与合并参考的列 必须要满足 一对一、一对多、多对多关系中一种
  • 格式:pd.merge(left, right, how=‘inner’, on=None, left_on=None, right_on=None, left_index=False, right_index=False, sort=False, suffixes=(’_x’, ‘_y’), copy=True, indicator=False)


#读取外部文件数据
index_col = [0] 设置第一列为作为行索引读取
header = [0] 设置第一行为列索引读取
【注意】版本不同,要确认参数名称是否有变化 比如sheet_name\sheetname

tb1 = pd.read_excel('data/关系表.xlsx',sheetname=1)

tb2 = pd.read_excel('data/关系表.xlsx',sheetname=2)

tb3 = pd.read_excel('data/关系表.xlsx',sheetname=3)

tb4 = pd.read_excel('data/关系表.xlsx',sheetname=4)

#各个标的数据
td1  ==>
	手机型号	参考价格
0	windowsPhone	2500
1	iPhone	7500
2	Android	4000
td2   ==>
	手机型号	重量
0	windowsPhone	0.50
1	iPhone	0.40
2	Android	0.45
3	other	0.60

tb3		==>
	经销商	发货地区	手机型号
0	dancer	beijing	iPhone
1	lucy	beijing	Android
2	tom	guangzhou	iPhone
3	petter	shenzhen	windowsPhone
4	mery	guangzhou	Android


tb4 	==>		
	发货地区	手机型号	价格
0	beijing	iPhone	7000
1	beijing	windowsPhone	2300
2	beijing	Android	3600
3	guangzhou	iPhone	7600
4	guangzhou	windowsPhone	2800
5	guangzhou	Android	4200
6	shenzhen	iPhone	7400
7	shenzhen	windowsPhone	2750
8	shenzhen	Android	3900

  • 代码实现
 #默认会把相同的列标签的列作为合并参考,进行合并
  #如果存在多个列都可以合并,则同时以多列作为合并参考
pd.merge(tb1, tb2)		==>
手机型号	参考价格	重量
0	windowsPhone	2500	0.50
1	iPhone	7500	0.40
2	Android	4000	0.45

#how inner 取交集
#     outer 取并集 如果存在不同项目,以NaN填充
#     left  以left参数指定的表为准   
#     right 以right参数指定的表为准
pd.merge(tb1, tb2, how="right")		==>
手机型号	参考价格	重量
0	windowsPhone	2500.0	0.50
1	iPhone	7500.0	0.40
2	Android	4000.0	0.45
3	other	NaN	0.60

#使用on=显式指定哪一列为key,当有多个key相同时使用
#suffixes 当列冲突时,即有多个列名称相同时,需要使用on=来指定哪一个列作为key,配合suffixes指定冲突列名
可以使用suffixes=自己指定后缀
pd.merge(tb3, tb4, on="手机型号", suffixes=["_上半年","_下半年"])		==>
经销商	发货地区_上半年	手机型号	发货地区_下半年	价格
0	dancer	beijing	iPhone	beijing	7000
1	dancer	beijing	iPhone	guangzhou	7600


#这里把表5的数据的列索引改为‘型号’再和表一进行合并
tb5 = tb2.copy()
tb5.columns = ["型号","重量"]
# left_on right_on 用于当合并的列名称不一样时,可以分别指定参考的列的列标签
pd.merge(tb1, tb5, left_on="手机型号", right_on="型号").drop(labels=["型号"],axis=1)	==>
手机型号	参考价格	重量
0	windowsPhone	2500	0.50
1	iPhone	7500	0.40
2	Android	4000	0.45

#set_index 把某一列设置为DataFrame的行索引
tb6 = tb5.copy()
tb6 = tb6.set_index("型号")	==>
		重量
型号	
windowsPhone	0.50
iPhone	0.40
Android	0.45
other	0.60
#right_index 指定右表的行索引为合并列的标签
pd.merge(tb1, tb6, left_on="手机型号", right_index=True)

pd.merge(tb6, tb1, left_index=True, right_on="手机型号")

案例分析:美国各州人口数据分析

  • 读取数据
import numpy as np
import pandas as pd
from pandas import Series,DataFrame
#表一
abb = pd.read_csv('data/state-abbrevs.csv')
abb.head()		===>
state	abbreviation
0	Alabama	AL
1	Alaska	AK
2	Arizona	AZ
3	Arkansas	AR
4	California	CA

#表二
area = pd.read_csv('data/state-areas.csv')
area.head()	==>
	state	area (sq. mi)
0	Alabama	52423
1	Alaska	656425
2	Arizona	114006
3	Arkansas	53182
4	California	163707

#表三
pop = pd.read_csv('data/state-population.csv')
pop.head()
state/region	ages	year	population
0	AL	under18	2012	1117489.0
1	AL	total	2012	4817528.0
2	AL	under18	2010	1130966.0
3	AL	total	2010	4785570.0
4	AL	under18	2011	1125763.0

  • 合并pop与abbrevs两个DataFrame,分别依据state/region列和abbreviation列来合并。为了保留所有信息,使用外合并。
pop_abb = pd.merge(pop, abb, how="outer", left_on="state/region", right_on="abbreviation")
pop_abb.head()		表一和表三合并 ==>
	state/region	ages	year	population	state	abbreviation
0	AL	under18	2012	1117489.0	Alabama	AL
1	AL	total	2012	4817528.0	Alabama	AL
2	AL	under18	2010	1130966.0	Alabama	AL
3	AL	total	2010	4785570.0	Alabama	AL
4	AL	under18	2011	1125763.0	Alabama	AL
## 对比pop_abb表中,相同的两列的信息是否一致
pop_abb["state/region"].unique()
pop_abb["abbreviation"].unique()
# 2. 查看不同的信息出现的次数
pop_abb["state/region"].value_counts()
pop_abb["abbreviation"].value_counts()

# 可以使用info函数,查看一个DataFrame的整体信息
pop_abb.info()

#经过比较决定去除abbreviation的那一列(axis=1)
# 删除一列,改变输入的内存,注意不要多次运行,只运行一次
pop_abb.drop(labels="abbreviation",axis=1, inplace=True)
  • 使用.isnull().any(),只有某一列存在一个缺失数据,就会显示True。
#获取行bool_list 用来过滤缺失值
bool_list = pop_abb.isnull().any(axis=1)
empty_df = pop_abb.loc[bool_list]	==>
	state/region	ages	year	population	state	abbreviation
2448	PR	under18	1990	NaN	NaN	NaN
2449	PR	total	1990	NaN	NaN	NaN
2450	PR	total	1991	NaN	NaN	NaN
2451	PR	under18	1991	NaN	NaN	NaN
2452	PR	total	1993	NaN	NaN	NaN
#找到有哪些state/region使得state的值为NaN,使用unique()查看非重复值
# 如果返回的是True,说明该列都是空置
empty_df["state"].isnull().all()
empty_df["state/region"].unique()
PR_COND = pop_abb["state/region"] == "PR"
USA_COND = pop_abb["state/region"] == "USA"
#给PR州赋值 
pop_abb.loc[PR_COND,"state"] = "Puerto Rico"
pop_abb.loc[USA_COND,"state"] = "USA"

#检测列方向是否还有空值
pop_abb.isnull().any()		==>
state/region    False
ages            False
year            False
population       True	#为空的行删除
state           False
abbreviation     True
dtype: bool
#检测人口空值 
pop_abb.loc[pop_abb.isnull().any(axis=1)] 

#检测表2和pop_abb表的不同
area["state"].size	==>52
pop_abb["state/region"].unique().size	==>53
#左联两个表
total = pd.merge(pop_abb, area, how="left")
# 先查看列是否存在缺失
total.isnull().any()
# 查找包含空值的行
total.loc[total.isnull().any(axis=1)]
# 获取所有包含空值的行索引
drop_index = total.loc[total.isnull().any(axis=1)].index
# 删除包含空值的行
total.drop(labels=drop_index, axis=0, inplace=True)
total.isnull().any()	#此时总表里没有空值

  • 找出2010年的全民人口数据,对查询结果进行处理,以state列作为新的行索引:set_index ,计算人口密度。注意是Series/Series,其结果还是一个Series。 排序,并找出人口密度最高的五个州sort_values()
#常规做法
year_conditon = total["year"] == 2010
total_2010 = total.loc[year_conditon]
total_2010_result = total_2010.loc[total_2010["ages"] == "total"]
#把州名设置为行索引
total_2010_result.set_index("state",inplace=True)


#使用query语句简化版,query直接接收一个字符串表达式  多个条件使用&连接 
rest1 = total_2010.query('year == 2010 & ages == "total"').set_index("state")
#计算人口密度
ret1 = rest1["population"]/rest1["area (sq. mi)"]

#绘直方图
import matplotlib.pyplot as plt
%matplotlib inline
plt.figure(figsize=(24,8))
ret1.plot(kind="bar")


#排序,并找出人口密度最高的五个州sort_values()
#ascending 默认为升序,改为降序切片取前五个
ret3 = ret1.sort_values(ascending=False)[:5]
ret3.plot(kind="bar")


pandas 数据处理

1.删除数据

  • 删除数据三个方式

    • drop(labels, axis) 删除指定的行或列
    • dropna(axis, how) 删除包含空值的 一行或一列
    • drop_duplicated() 删除重复的行
  • 使用duplicated()函数查看重复的行

使用duplicated()函数检测重复的行,返回元素为布尔类型的Series对象,每个元素对应一行,如果该行不是第一次出现,则元素为True

  • 格式: df.duplicated(subset=None, keep=‘first’)
    • 默认把第一次出现的值保留 keep=“first”
    • 保留最后一次出现的 keep=“last”
condition = df.duplicated(keep="last")  ==>
0     True
1    False
2     True
3    False
4    False
5     True
6    False
7    False
dtype: bool
#利用condition过滤出行索引
df.loc[condition].index			==>
Int64Index([0, 2, 5], dtype='int64')
#删除相同的数据
df.drop(labels=df.loc[condition].index)
  • 使用drop_duplicates()函数删除重复的行
    • 格式:df.drop_duplicates(subset=None, keep=‘first’, inplace=False)
      • inplace 直接改变df,只能使用一次
# 如果需要对级联后的表进行去重, 最好把索引进行重排操作
df3 = pd.concat((df,df), ignore_index=True)
df3.drop_duplicates()		==>
	name	语文	数学	英语
0	王伟	67	76	65
1	张小凡	87	54	87
2	陆雪琪	56	98	67
3	黎明	56	67	65
4	碧瑶	54	56	90

2、映射

映射的含义:创建一个映射关系列表,把values元素和一个特定的标签或者字符串绑定 ,包含三种操作:

  • replace()函数:替换元素(DataFrame\Series的函数)
  • 最重要:map()函数:新建一列(Series的函数)
  • rename()函数:替换索引(DataFrame的函数)

1) replace()函数:替换元素

  • 格式
df.replace(to_replace=None, value=None, inplace=False, limit=None, regex=False, method='pad', axis=None)
method:对指定的值使用相邻的值填充
limit:设定填充次数
  • DataFrame操作
df			==>
	A	B	C	D	E
0	lucy	65	43.0	6.836381	22.0
1	mery	57	NaN	NaN	85.0
2	tom	66	80.0	2.858967	11.0
3	jack	42	66.0	8.044660	NaN
4	rose	79	17.0	0.047589	31.0

# 单值替换
df.replace(to_replace="lucy", value="魏淑芬")
# 列表替换
df.replace(to_replace=["lucy","mery",np.nan], value=["魏淑芬","王可",0])
# 字典替换
# 1. 要替换的值,字典里没有 , 默认保留原始值
# 2. 字典里存在的值,在要替换的 值里没有, 所以,根据以上的特征,我们可以直接维护一个字典,对所有的表进行替换
df.replace(to_replace={
    "lucy":"魏淑芬",
    "mery":"王小可",
    "noname":"不知道"
})


  • Series替换操作
    • 单值替换
      • 普通替换
      • 字典替换
    • 多值替换
      • 列表替换
      • 字典替换(推荐)

2) map()函数:新建一列

s.map(arg, na_action=None)

map函数并不是DataFrame的函数,而是Series的函数, 所以map函数主要用于某一列数据的映射处理

注意

  • map()中不能使用sum之类的函数,for循环
  • map(字典) 字典的键要足以匹配所有的数据,否则出现NaN

map函数可以接收如下三种值:

  • 字典 一般用于处理离散型数据
  • lambda 表达式 可以处理离散型和连续型数据
  • function 自定义函数
df     ===>
	name	语文	数学	英语
0	王伟	67	76	65
1	张小凡	87	54	87
2	陆雪琪	56	98	67
3	黎明	56	67	65
4	碧瑶	54	56	90


#接收字典
map_dic = {
    "黎明":"Tom",
    "碧瑶":"Green",
    "陆雪琪":"Rose",
    "王伟":"Jery",
    "张小凡":"Lucy",
    "张学友":"Friend"
}
# 新增一列
df["english_name"] = df["name"].map(map_dic)
# 修改一列
df["name"] = df["name"].map(map_dic)

#1. 字典里面的键值对如果多于要映射的列的数据,可以维护一个大字典,对多列数据进行映射处理
df["name"].map(map_dic)
# 2. 字典里面的键值对少于要映射的列的数据, 没有对应映射数据将会返回一个NaN,可以使用函数,如果字典里有对应的映射值就返回映射至,否则返回原始值
map_dic = {
    "黎明":"Tom",
    "碧瑶":"Green"
}
df["name"].map(map_dic)


#接收函数
def function1(x):
    return map_dic.get(x,x)
df["name"].map(function1)
def map_score(x):
    if x >=90:
        return "A"
    elif x>=80:
        return "B"
    elif x >= 70:
        return "C"
    elif x >= 60:
        return "D"
    else:
        return "E"
  df["语文"] = df["语文"].map(map_score)


# lambda 函数
df["英语"].map(lambda x:x-10)

3)transform()和map()类似

  • 格式
 s.transform(func, *args, **kwargs)

4) rename()函数:替换索引

df.rename(index=None, columns=None, **kwargs)

仍然是新建一个字典,使用rename()函数替换行索引

  • mapper 替换所有索引
  • index 替换行索引
  • columns 替换列索引
  • level 指定多维索引的维度
#原数据
df	==>
name	语文	数学	英语	english_name
0	王伟	67	76	65	Jery
1	张小凡	87	54	87	Lucy
2	陆雪琪	56	98	67	Rose
3	黎明	56	67	65	Tom
4	碧瑶	54	56	90	Green

# 改变列索引
df.rename(columns={
    "name":"姓名"
})

#改变行索引
df.rename(index={
    0:"first"
})

#mapper用于指定替换行和列索引的字典,axis用于指定替换的是行索引还是列索引
df.rename(mapper={
    0:"first",
    "name":"姓名"
},axis=1)

# level 用于指定多层级索引的替换层级
df1 = pd.concat((df, df), axis=1, keys=["上学期","下学期"])
df1.rename(mapper={
    "上学期":"第一学期",
    "name":"姓名"
}, axis=1, level=1)

3. 使用聚合操作对数据异常值检测和过滤

异常值界定不同业务有不同的标准

假设某一个数据的绝对值 > 3*该列的标准差 就被认定为异常数据

df = DataFrame(data = np.random.randn(10000,3), columns=list("ABC"))

# describe() 函数查看数据集的基本数学指标
df.describe()		==>
	A	B	C
count	10000.000000	10000.000000	10000.000000
mean	-0.002205	-0.002600	-0.000615
std	1.010709	1.000173	1.013830
min	-4.053966	-4.535207	-3.455074
25%	-0.684367	-0.690652	-0.688193
50%	-0.009133	0.000911	0.014746
75%	0.675410	0.675980	0.695004
max	3.808636	3.865321	4.074260
#最大值
df["A"].max()
#标准差	#接近1,使用std()函数可以求得DataFrame对象每一列的标准差
df["A"].std()
# 确定异常值的检测条件
condition = np.abs(df) > 3*df.std() 		==>
	A	B	C
0	False	False	False
1	False	False	False
2	False	False	False
''''''
# 获取满足条件的行
bool_list = condition.any(axis=1)
# 获取满足条件的行的索引
drop_index = df[bool_list].index
# 根据满足条件的行的索引,删除行
df.drop(labels=drop_index)

4、排序

  • 使用.take()函数排序:f.take(indices, axis=0, convert=True, is_copy=True, **kwargs)
    • take()函数接受一个索引列表,用数字表示
    • eg:df.take([1,3,4,2,5])

可以借助np.random.permutation()函数随机排序

df = DataFrame(data=np.random.randint(0,10,size=(5,5)), columns=list("ABCDE"))
	A	B	C	D	E
0	2	2	6	4	1
1	7	1	6	7	7
2	2	5	4	1	7
3	3	0	1	2	9
4	9	0	5	7	5
#列方向取
df.take([0,1,0,1],axis=1)	==>

A	B	A	B
0	2	2	2	2
1	7	1	7	1
2	2	5	2	5
3	3	0	3	0
4	9	0	9	0

# 使用permutation函数随机生成数组
np.random.permutation(5)		生成随机排序数组==>
array([0, 1, 2, 4, 3])
df.take(np.random.permutation(5),axis=1)
##
df.take(indices,axis)
np.random.permutation()  # 随机排序
np.random.randint()      # 随机抽样

5. 数据分类处理【重点】

数据聚合是数据处理的最后一步,通常是要使每一个数组生成一个单一的数值。

数据分类处理:

  • 分组:先把数据分为几组
  • 用函数处理:为不同组的数据应用不同的函数以转换数据
  • 合并:把不同组得到的结果合并起来

数据分类处理的核心:

 groupby()函数
  groups属性查看分组情况
  • 根据item分组,查看结果

总结:数据类型是离散的可以分组,连续的没有意义

  • 获取weight的总和

  • 把总和跟df进行merge合并

  • 使用列表进行多列分组,得到的结果是多层级索引

df = pd.read_excel('cai.xlsx')
	item	color	price	weight
0	萝卜	红	0.5	50
1	白菜	白	0.3	30
2	白菜	青	1.0	16
3	萝卜	青	1.0	32
4	辣椒	青	2.0	36
5	白菜	红	3.0	18
6	冬瓜	青	1.5	29
7	辣椒	红	4.0	18
8	辣椒	黄	0.5	19
9	冬瓜	白	2.0	23

# 分组 根据item列进行分组
ret = df.groupby("item")		==>
<pandas.core.groupby.DataFrameGroupBy object at 0x000000000A6FA390>

# 查看分组情况
ret.groups	==>
{'冬瓜': Int64Index([6, 9], dtype='int64'),
 '白菜': Int64Index([1, 2, 5], dtype='int64'),
 '萝卜': Int64Index([0, 3], dtype='int64'),
 '辣椒': Int64Index([4, 7, 8], dtype='int64')}

# 查看不同菜品的总重量
# 可以直接对分组对象做聚合操作
ret.sum()["weight"]
item
冬瓜    52
白菜    64
萝卜    82
辣椒    73
Name: weight, dtype: int64
#每种蔬菜均价
ret.mean()["price"]    
item
冬瓜    1.750000
白菜    1.433333
萝卜    0.750000
辣椒    2.166667
Name: price, dtype: float64
# 聚合之前,先确认要聚合的列是否能运算
df.dtypes
# 同时查看价格的平均值和重量的总和
ret.agg({"price":"mean", "weight":"sum"})

# 多层级索引分组,可以用于查看两个列之间的对应关系
df.groupby(["color","item"]).sum()["weight"]
df.groupby(["item","color"]).sum()["weight"]
item  color
冬瓜    白        23
      青        29
白菜    白        30
      红        18
      青        16
萝卜    红        50
      青        32
辣椒    红        18
      青        36
      黄        19
Name: weight, dtype: int64
        

6.0 高级数据聚合

使用groupby分组后,也可以使用transform和apply提供自定义函数实现更多的运算

  • df.groupby(‘item’)[‘price’].sum() <==> df.groupby(‘item’)[‘price’].apply(sum)
  • transform和apply都会进行运算,在transform或者apply中传入函数即可
  • transform和apply也可以传入一个lambda表达式
df.groupby('item').sum()["price"]		==>
item
冬瓜    3.5
白菜    4.3
萝卜    1.5
辣椒    6.5
Name: price, dtype: float64
df.groupby('item').apply(sum)["price"]	==>
item
冬瓜    3.5
白菜    4.3
萝卜    1.5
辣椒    6.5
Name: price, dtype: float64

 #使用函数       
def function(items):
    result = 0
    for item in items:
        result += item
    return result
r1 = df.groupby("item")["price"].apply(function)
item
冬瓜    3.5
白菜    4.3
萝卜    1.5
辣椒    6.5
Name: price, dtype: float64
 #
r2.name = "price_sum"
pd.concat((df, r2),axis=1)		==>
item	color	price	weight	price_sum
0	萝卜	红	0.5	50	1.5
1	白菜	白	0.3	30	4.3
2	白菜	青	1.0	16	4.3
3	萝卜	青	1.0	32	1.5
4	辣椒	青	2.0	36	6.5
5	白菜	红	3.0	18	4.3
6	冬瓜	青	1.5	29	3.5
7	辣椒	红	4.0	18	6.5
8	辣椒	黄	0.5	19	6.5
9	冬瓜	白	2.0	23	3.5

 注意
transform 会自动匹配列索引返回值,不去重
apply 会根据分组情况返回值,去重

7、统计函数

corr相关性函数

DataFrame.corr(method='pearson', min_periods=1)
参数说明:

method:可选值为{‘pearson’, ‘kendall’, ‘spearman’}

               pearson:Pearson相关系数来衡量两个数据集合是否在一条线上面,即针对线性数据的相关系数计算,针对非线性                                           数据便会有误差。

                kendall:用于反映分类变量相关性的指标,即针对无序序列的相关系数,非正太分布的数据

                spearman:非线性的,非正太分析的数据的相关系数

min_periods:样本最少的数据量

返回值:各类型之间的相关系数DataFrame表格。

为区分不同参数之间的区别,我们实验如下:


from pandas import DataFrame
import pandas as pd
x=[a for a in range(100)]
#构造一元二次方程,非线性关系
def y_x(x):
    return 2*x**2+4
y=[y_x(i) for i in x]
 
data=DataFrame({'x':x,'y':y})
 
#查看下data的数据结构
data.head()
Out[34]: 
   x   y
0  0   4
1  1   6
2  2  12
3  3  22
4  4  36
 
data.corr()
Out[35]: 
          x         y
x  1.000000  0.967736
y  0.967736  1.000000
 
data.corr(method='spearman')
Out[36]: 
     x    y
x  1.0  1.0
y  1.0  1.0
 
data.corr(method='kendall')
Out[37]: 
     x    y
x  1.0  1.0
y  1.0  1.0

因为y经由函数构造出来,x和y的相关系数为1,但从实验结构可知pearson系数,针对非线性数据有一定的误差。

接下来是房价分析的例子:

corr_matrix = housing.corr()
corr_matrix["median_house_value"].sort_values(ascending=False)	==>

out:
median_house_value 1.000000
median_income 0.687160
total_rooms 0.135097
housing_median_age 0.114110
households 0.064506
total_bedrooms 0.047689
population -0.026920
longitude -0.047432
latitude -0.142724
Name: median_house_value, dtype: float64


可以看出,房价与收入有比较强的相关性,而与纬度的相关性很低。

scatter_matrix

pandas.plotting.scatter_matrix(frame, alpha=0.5, figsize=None, ax=None, grid=False, diagonal=‘hist’, marker=’.’, density_kwds=None, hist_kwds=None, range_padding=0.05, **kwds)
画任意两列数值属性的散点图,最后画一个散点图的矩阵,对角线为分布直方图。

 df = DataFrame(np.random.randn(1000, 4), columns=['A','B','C','D'])
  scatter_matrix(df, alpha=0.2)

在这里插入图片描述
继续分析房价的例子,通过计算相关系数,只看几个与房价相关性较大的数据

from pandas.tools.plotting import scatter_matrix
attributes = ["median_house_value", "median_income", "total_rooms",
"housing_median_age"]
scatter_matrix(housing[attributes], figsize=(12, 8))

在这里插入图片描述

pandas之表连接与高级查询 表间的左右连接和内连接,高级查询语句truncate、字符串查询函数str.contains、query函数等 阅读详情

相关推荐

使用列索引名称和元组索引访问Python中的列数据

当我们想要访问DataFrame中的特定列数据时,可以使用列索引名称或元组索引来实现。首先,让我们看一下如何使用列索引名称来访问列数据。假设我们有一个名为"df"的DataFrame,其中包含了姓名、年龄和城市的数据列。接下来,让我们看一下如何使用元组索引来访问列数据。元组索引是指使用列的位置索引来访问数据。通过使用列索引名称和元组索引,我们可以轻松地访问DataFrame中的列数据。这将返回一个包含"姓名"和"年龄"列数据的DataFrame对象。使用列索引名称和元组索引访问Python中的列数据。

uote_e的博客 234

高手系列!数据科学家私藏pandas高阶用法大全 ⛵

本文汇总介绍了21个 Pandas 进阶用法,能保持代码整洁优雅,更能提高代码效率!这篇是从数据科学家朋友那里搞到的私藏,快一起薅羊毛~

ShowMeAI研究中心 1万+

pandas高级使用

和其它许多开源项目一样,pandas仍然在不断的变化和进步中。和本书中其它地方一样,这里的重点是放在接下来几年不会发生什么改变且稳定的功能。为了深入学习pandas的知识,我建议你学习官方文档,并阅读开发团队发布的文档更新。我们还邀请你加入pandas的开发工作:修改bug、创建新功能、完善文档。

youbingchen的博客 127

50 个 Pandas 高级操作,建议收藏!

↓推荐关注↓转自:https://zhuanlan.zhihu.com/p/568250201在数据分析和数据建模的过程中需要对数据进行清洗和整理等工作,有时需要对数据增删字段。下面为大家介绍Pandas对数据的实际业务需求往往需要按照一定的条件甚至复杂的组合条件来查询数据,接下来为大家介绍如何发挥Pandas数据筛选的无限可能,随心所欲地取用数据。

AI大模型资料分享员 1884

从0到1学Pandas(四):Pandas 高级应用

本文聚焦 Pandas 高级应用,深入探讨其与 NumPy、Matplotlib 等库的集成方法,展现多工具协同处理数据的优势。同时,从数据类型优化、向量化操作等方面讲解性能提升技巧,介绍 apply 函数、窗口函数等高级处理方法。通过金融、用户行为、销售数据分析三个实际案例,展示 Pandas 在实战中的应用,帮助读者掌握高效数据处理技能,提升在实际项目中解决复杂问题的能力。

邓邓子的博客 815

第一章、isaacsim 及 isaaclab 安装教程

本专栏所有内容将根据上述资源地址展开,请结合食用~

m0_47719040的博客 4780

50个Pandas高级操作,建议收藏!

在数据分析和数据建模的过程中需要对数据进行清洗和整理等工作,有时需要对数据增删字段。下面为大家介绍Pandas对数据的实际业务需求往往需要按照一定的条件甚至复杂的组合条件来查询数据,接下来为大家介绍如何发挥Pandas数据筛选的无限可能,随心所欲地取用数据。

2401_86168842的博客 1209

UE5高斯泼溅落地全链路:从PLY导入到实时渲染的工程实践

3D高斯泼溅(3D Gaussian Splatting)正从NeRF后处理技术演进为新一代隐式几何渲染范式,其核心在于以可微椭球体替代传统三角面片,通过协方差矩阵与球谐系数实现高质量体素化渲染。该技术突破点云精度瓶颈,但与UE5现有资产管线存在根本性不兼容——静态网格导入器无法解析scale/rot/sh系数等非标顶点语义,标准光栅化管线亦无法执行高斯核采样计算。XV3DGS-UEPlugin通过自定义资产类型、StructuredBuffer GPU数据流与专用材质节点,将高斯泼溅重构为可编辑、可LOD

weixin_33692177的博客 359

Pandas50个高级操作,秀起来!

今天给大家分享一篇Pandas高级操作汇总。在数据分析和数据建模的过程中需要对数据进行清洗和整理等工作,有时需要对数据增删字段。下面为大家介绍Pandas对数据的复杂查询、数据类型转换、数据排序、数据的修改、数据迭代以及函数的使用。实际业务需求往往需要按照一定的条件甚至复杂的组合条件来查询数据,接下来为大家介绍如何发挥Pandas数据筛选的无限可能,随心所欲地取用数据。切片([ ])、.loc[ ]和.iloc[ ]均支持上文所介绍的逻辑表达式。以下是.loc[ ]和.lic[ ]示例:​​​​​​​。

2401_86168842的博客 1395

MR2数据集实战:5步搞定多模态谣言检测模型训练(附完整代码)

本文详细介绍了如何使用MR2多模态数据集构建高精度谣言检测系统,涵盖环境配置、数据准备、多模态特征工程、模型架构设计、训练调优及部署优化等5个关键步骤。通过双线性融合技术处理文本、图像和网页三模态数据,解决特征对齐和模态冲突等工程难题,并提供完整代码实现和性能优化方案。

weixin_42657024的博客 239

计量经济学——事件研究法/事件分析法

计量经济学——事件研究法/事件分析法

weixin_46189461的博客 6752

Pandas的高级索引

Pandas的高级索引有3种 loc 标签索引 DataFrame 不能直接切片,可以通过loc来做切片 loc是基于标签名的索引,也就是我们自定义的索引名 示例代码: ser_obj = pd.Series(range(5), index = ['a', 'b', 'c', 'd', 'e']) df_obj = pd.DataFrame(np.random.randn(5,4), columns = ['a', 'b', 'c', 'd']) # 标签索引 loc # Series print(s

python_studying的博客 409

04-协议基础03:USB 2.0信号与电气特性

USB 2.0使用两根差分信号线D+/D-进行数据传输,支持低速(1.5Mbps)、全速(12Mbps)和高速(480Mbps)三种速率。USB总线为主从模式,所有事务由Host发起。端电阻值作用HostRpd(D+)15KΩ±5%下拉,默认低电平HostRpd(D-)15KΩ±5%下拉,默认低电平全速设备Rpu(D+)1.5KΩ±5%上拉到3.3V,标识全速低速设备Rpu(D-)1.5KΩ±5%上拉到3.3V,标识低速USB 2.0硬件要点。

内核笔记 104

Pandas高级功能

可以使用agg方法应用自定义的聚合函数。# 定义自定义聚合函数# 应用自定义聚合函数Pandas的高级功能为我们提供了强大而灵活的数据处理和分析工具。通过掌握这些高级功能,我们可以更高效地处理复杂的数据集,挖掘数据背后的价值。无论是数据清洗、转换,还是数据分析和可视化,Pandas都能成为我们的得力助手。希望本文能够帮助大家更好地理解和应用Pandas的高级功能,在数据科学的道路上取得更大的进步。在实际应用中,不断实践和探索Pandas的各种功能是非常重要的。

得塔云的博客 605

【WRF-Urban】使用 CGLC-MODIS-LCZ_100m 数据集运行 WRF 时的城市参数化问题

【WRF-Urban】使用 CGLC-MODIS-LCZ_100m 数据集运行 WRF 时的城市参数化问题

WW、forever的博客 711

A Macro- and Micro-Hierarchical Transfer Learning Frameworkfor Cross-Domain Fake News Detection

近年来,社交媒体上假新闻的快速和广泛传播对人们的日常生活构成了越来越大的威胁[6, 14, 19]。为了有效打击假新闻,自动检测假新闻变得至关重要[39]。新闻内容[11, 16, 20, 27]和用户互动(即用户互动)[1, 24, 34]。基于这些类型的数据,提出了单领域假新闻检测,它从新闻文章、用户互动或两者中提取有效特征,以识别单个新闻领域内新闻的真实性(即新闻是真是假)(例如,政治新闻或娱乐新闻)。

qq_52053775的博客 155

Pandas使用教程 - Pandas 与 Excel 高级操作

借助xlsxwriter# 定义一个格式对象# 设置 Sales 列的格式(假设 Sales 在第一列)# 添加公式,计算利润print("自定义格式和公式已写入 formatted.xlsx")通过这种方式,可以在写入时设置列宽、单元格格式以及添加公式,满足业务需求。本文详细介绍了 Pandas 与 Excel 高级操作的核心技术,包括如何高效读取多个工作表、优化数据类型和内存使用、使用 ExcelWriter 写入多工作表、以及如何定制输出格式与公式。

闲人编程的博客 1539

C#上位机3D可视化:HelixToolkit.Wpf集成点云/模型(机器人臂姿态实时监控)

核心控件是3D可视化的核心,需搭配和网格辅助定位;模型加载:按关节拆分机械臂模型,通过组合平移+旋转实现姿态控制;姿态更新:将机器人关节角度转换为3D模型的旋转变换,工业场景需从控制器实时获取角度;点云渲染:通过实现点云加载,需注意坐标系转换和性能优化。

这里只有干货:从 Modbus 通信到 MES 对接,从 YOLO 训练到工控机部署,带你搞定工业软件开发全流程。 716

Pandas 高级用法大全

这份列表旨在覆盖 Pandas 的绝大多数高级特性。精通这些工具将使你能够应对几乎所有的数据处理和分析挑战。建议针对性地学习和实践你感兴趣或需要的模块。这份列表假定你已掌握 Pandas 的基础知识(创建 Series/DataFrame、基本选择、常用函数如。好的,这次我将尽可能全面地列举 Pandas 中的高级用法和不常用的但功能强大的特性,涵盖更多细节和场景。

zhangyunchou2015的博客 855

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

Pandas高级

qq_75259736的博客 110

迈瑞BS系列全自动生化分析仪LIS协议接口手册(内含HL7和ASTM)

迈瑞BS系列全自动生化分析仪LIS协议接口手册,内含HL7和ASTM)

Pandas高级操作

读书笔记

zhaoleiedu的博客 1192

pandas 高级

目录前言1.数据集成1.1 concat数据串联1.2 插入1.3 Join SQL风格合并2.数据清洗2.1 重复数据过滤2.2 空数据过滤2.3 指定行或者列进行删除2.4 异常值3.数据转换 前言 本文其实属于:Python的进阶之道【AIoT阶段一】的一部分内容,本篇把这部分内容单独截取出来,方便大家的观看,本文介绍 pandas 高级,读本文之前建议先修:pandas 入门,后续还会发出一篇 pandas 进阶供读者进行进一步的学习了解。

佛系更新 3239

八、Pandas高级操作

《八、Pandas高级操作》密码:gag4)

厚积而薄发 328

数据科学必修课:Python pandas库的20个高级技巧

在数据科学和数据分析领域,Python的pandas库已经成为处理结构化数据的标准工具。虽然许多数据科学家和分析师都熟悉pandas的基本操作,但该库中隐藏着许多强大的高级功能,可以显著提高数据处理的效率和灵活性。本文将介绍20个pandas高级技巧,帮助你提升数据处理和分析的能力,让你的代码更加简洁、高效且专业。

exlink2012的专栏 807
上一篇: pandas的基本使用
下一篇: 交叉表和透视表
Are you ready
博客等级 码龄8年 312粉丝 33原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值