pandas的高级使用

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
冬瓜    白        2329
白菜    白        301816
萝卜    红        5032
辣椒    红        183619
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)

pandas的高级使用_第1张图片
继续分析房价的例子,通过计算相关系数,只看几个与房价相关性较大的数据

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的高级使用_第2张图片

你可能感兴趣的:(爬虫与数据分析,pandas的高级使用)