pandas数据处理(三)合并数据、交叉透视表

1. 数据合并

对数据合并,可以使用concat、merge、join 等方法。

1. concat 方法

一般concat 用于上下数据堆叠合并。concat 有用的三个参数:

objs: 数据
axis: {0/‘index’, 1/‘columns’}要连接的轴。0 为上下堆叠,1为左右拼接
join:{‘inner’, ‘outer’}, 默认‘outer’。join='outer’表示外连接,保留两个表中的所有信息;join="inner"表示内连接,拼接结果只保留两个表共有的信息
  1. 引入pd 以及数据
import pandas as pd
df1=pd.DataFrame({'姓名':['张三','李四','王五'],'爱好':['打球','游戏','玩'],'性别':['男', '女', '男']})
df2=pd.DataFrame({'姓名':['张三','乔治'],'爱好':['麻将','扑克']})
  1. 上下堆叠合并数据集
df3 = pd.concat([df1,df2])
'''
	姓名	爱好	性别
0	张三	打球	男
1	李四	游戏	女
2	王五	玩	男
0	张三	麻将	NaN
1	乔治	扑克	NaN
'''
  1. 左右合并
df3 = pd.concat([df1,df2], axis = 1)
'''
	姓名	爱好	性别	姓名	爱好
0	张三	打球	男	张三	麻将
1	李四	游戏	女	乔治	扑克
2	王五	玩	男	NaN	NaN
'''
  1. join 内外连接区别

outer 是默认值。 和RDB一样,outer是保留所有,inner 是保留共有的(这里是指属性共有)

df3 = pd.concat([df1,df2], join='inner')
'''
	姓名	爱好
0	张三	打球
1	李四	游戏
2	王五	玩
0	张三	麻将
1	乔治	扑克
'''

2. merge 合并

erge 实现类似于数据库的join 操作。

有两种调用方式:pd.merge()和df1.merge(df2)。

语法以及参数:

def merge(
    left: DataFrame | Series,
    right: DataFrame | Series,
    how: str = "inner",
    on: IndexLabel | None = None,
    left_on: IndexLabel | None = None,
    right_on: IndexLabel | None = None,
    left_index: bool = False,
    right_index: bool = False,
    sort: bool = False,
    suffixes: Suffixes = ("_x", "_y"),
    copy: bool = True,
    indicator: bool = False,
    validate: str | None = None,
)
'''
left、right:需要连接的两个DataFrame或Series,一左一右
how:两个数据连接方式,默认为inner,可设置inner、outer、left或right
on:作为连接键的字段,左右数据中都必须存在,否则需要用left_on和right_on来指定
left_on:左表的连接键字段
right_on:右表的连接键字段
left_index:为True时将左表的索引作为连接键,默认为False
right_index:为True时将右表的索引作为连接键,默认为False
suffixes:如果左右数据出现重复列,新数据表头会用此后缀进行区分,默认为_x和_y
'''
  1. on 指定用姓名连接
df3 = pd.merge(df1, df2, on='姓名')
'''
	姓名	爱好_x	性别	爱好_y
0	张三	打球	男	麻将
'''
  1. 直接按索引进行连接
df3 = pd.merge(df1, df2, left_index=True, right_index=True, suffixes=('_1','_2'))
'''
	姓名_1	爱好_1	性别	姓名_2	爱好_2
0	张三	打球	男	张三	麻将
1	李四	游戏	女	乔治	扑克
'''
  1. 多连接条件
df1=pd.DataFrame({'姓名':['张三','李四','王五'],'爱好':['麻将','游戏','玩'],'性别':['男', '女', '男']})
df2=pd.DataFrame({'姓名':['张三','乔治'],'爱好':['麻将','扑克']})
df3 = pd.merge(df1, df2, on=['姓名','爱好'])
'''
	姓名	爱好	性别
0	张三	麻将	男
'''
  1. 使用外连接
  • 右外
df1=pd.DataFrame({'姓名':['张三','李四','王五'],'爱好':['麻将','游戏','玩'],'性别':['男', '女', '男']})
df2=pd.DataFrame({'姓名':['张三','乔治', '王五'],'爱好':['麻将','扑克', '']})
df3 = pd.merge(df1, df2, on=['姓名'], how = 'right')
'''
	姓名	爱好_x	性别	爱好_y
0	张三	麻将	男	麻将
1	乔治	NaN	NaN	扑克
2	王五	玩	男	
'''
  • outter 外连接
df1=pd.DataFrame({'姓名':['张三','李四','王五'],'爱好':['麻将','游戏','玩'],'性别':['男', '女', '男']})
df2=pd.DataFrame({'姓名':['张三','乔治', '王五'],'爱好':['麻将','扑克', '']})
df3 = pd.merge(df1, df2, on=['姓名'], how = 'outer')
'''
	姓名	爱好_x	性别	爱好_y
0	张三	麻将	男	麻将
1	李四	游戏	女	NaN
2	王五	玩	男	
3	乔治	NaN	NaN	扑克
'''
  • 左外
df1=pd.DataFrame({'姓名':['张三','李四','王五'],'爱好':['麻将','游戏','玩'],'性别':['男', '女', '男']})
df2=pd.DataFrame({'姓名':['张三','乔治', '王五'],'爱好':['麻将','扑克', '']})
df3 = pd.merge(df1, df2, on=['姓名'], how = 'left')
'''
	姓名	爱好_x	性别	爱好_y
0	张三	麻将	男	麻将
1	李四	游戏	女	NaN
2	王五	玩	男	
'''
  1. 连接指示: 会加一列_merge 标识连接后是左表内容还是右表内容
df1=pd.DataFrame({'姓名':['张三','李四','王五'],'爱好':['麻将','游戏','玩'],'性别':['男', '女', '男']})
df2=pd.DataFrame({'姓名':['张三','乔治', '王五'],'爱好':['麻将','扑克', '']})
df3 = pd.merge(df1, df2, on=['姓名'], how = 'left', indicator=True)
'''
	姓名	爱好_x	性别	爱好_y	_merge
0	张三	麻将	男	麻将	both
1	李四	游戏	女	NaN	left_only
2	王五	玩	男		both
'''
  1. 方法调用也可以通过 df 直接merge
df1=pd.DataFrame({'姓名':['张三','李四','王五'],'爱好':['麻将','游戏','玩'],'性别':['男', '女', '男']})
df2=pd.DataFrame({'姓名':['张三','乔治', '王五'],'爱好':['麻将','扑克', '']})
df3 = df1.merge(df2, on=['姓名'], how = 'left', indicator=True)
'''
结果同5
'''

3. join

看出join其实是省略了参数的merge,默认情况下是把行索引相同的数据合并到一起。参数如下:

    def join(
        self,
        other: DataFrame | Series | list[DataFrame | Series],
        on: IndexLabel | None = None,
        how: str = "left",
        lsuffix: str = "",
        rsuffix: str = "",
        sort: bool = False,
        validate: str | None = None,
    )

测试:

df1=pd.DataFrame({'姓名':['张三','李四','王五'],'爱好':['麻将','游戏','玩']}, index = [1, 2, 3])
df2=pd.DataFrame({'姓名':['张三','乔治', '王五'],'爱好':['麻将','扑克', '']}, index = [1, 2, 3])
df3 = df1.join(df2, lsuffix = '1', rsuffix = '2')
'''
	姓名1	爱好1	姓名2	爱好2
1	张三	麻将	张三	麻将
2	李四	游戏	乔治	扑克
3	王五	玩	王五	
'''

2. 交叉表、透视表

1. 交叉表crosstab

用于计算一列数据对于另外一列数据的分组个数(用于统计分组频率的特殊透视表), 一般用于探索两列数据之间的关系。

def crosstab(
    index,
    columns,
    values=None,
    rownames=None,
    colnames=None,
    aggfunc=None,
    margins: bool = False,
    margins_name: str = "All",
    dropna: bool = True,
    normalize=False,
) -> DataFrame:
index:类似数组、系列或数组/系列值的列表,行中分组依据的值
columns:类似数组、系列或数组/系列值的列表,列中要作为分组依据的值
values:类似数组,可选,要根据因素聚合的值数组,需要指定 aggfunc
rownames:序列,默认 None ,如果传递,必须匹配传递的行数组的数量
colnames:序列,默认 None ,如果传递,必须匹配传递的列数组的数量
aggfunc:function,可选,如果指定,则还需要指定值
margins:bool, 默认False 添加行/列边距(小计)
margins_name:str,默认为“All”,当边距为 True 时将包含总计的行/列的名称
dropna:bool, 默认为True,不包含条目均为 NaN 的列
normalize:bool, {‘all’, ‘index’, ‘columns’}, or {0,1}, 默认为False,通过将所有值除以值的总和来归一化
“all”或 True:将对所有值进行归一化
index:将对每一行进行归一化
columns:将对每一列进行归一化
若margins 为 True,也将标准化边距值
返回:数据的 DataFrame 交叉表  
  1. 求count
a = np.array(["foo", "foo", "foo", "foo", "bar", "bar", "bar", "bar", "foo", "foo", "foo"], dtype=object)
b = np.array(["one", "one", "one", "two", "one", "one", "one", "two", "two", "two", "one"], dtype=object)
c = np.array(["dull", "dull", "shiny", "dull", "dull", "shiny", "shiny", "dull", "shiny", "shiny", "dull"], dtype=object)
count = pd.crosstab(a, [b, c], rownames=['a'], colnames=['b', 'c'])  
count

结果:

  1. 求sum
# 算数运算,先求和。 默认按照列求和
sum = count.sum()
sum
'''
b    c    
one  dull     4
     shiny    3
two  dull     2
     shiny    2
dtype: int64
'''

# 按行求和
sum = count.sum(axis=1)
sum
'''
a
bar    4
foo    7
dtype: int64
'''
  1. 求比例
# 进行相除操作,得出比例
pro = count.div(sum, axis=0)
pro

  1. 画图
pro.plot(kind='bar', stacked=True)

2. 透视pivot

​ 透视表是将原有的DataFrame的列分别作为行索引和列索引,然后对指定的列应用聚集函数,是一种可以对数据动态排布并且分类汇总的表格格式。

    def pivot_table(
        self,
        values=None,
        index=None,
        columns=None,
        aggfunc="mean",
        fill_value=None,
        margins=False,
        dropna=True,
        margins_name="All",
        observed=False,
        sort=True,
    ) -> DataFrame:
        from pandas.core.reshape.pivot import pivot_table
values:要聚合的列,可选,默认对所有列操作
index:column, Grouper, array, or list of the previous 如果传递数组,它必须与数据的长度相同。该列表可以包含任何其他类型(列表除外)。在数据透视表索引上分组的键。如果传递一个数组,它的使用方式与列值相同
column:column, Grouper, array, or list of the previous 如果传递一个数组,它必须和数据一样长。该列表可以包含任何其他类型(列表除外)。在数据透视表列上分组的键。如果传递一个数组,它的使用方式与列值相同
aggfunc:function, list of functions, dict, 默认为numpy.mean 如果传递函数列表,则生成的数据透视表将具有分层列,其顶层是函数名称(从函数对象本身推断)如果传递dict,则键是列聚合和值是函数或函数列表
fill_value:scalar,默认 None 用于替换缺失值的值(在聚合后的结果数据透视表中)
margins:bool, 默认False 添加所有行/列(例如小计/总计)
dropna:bool, 默认为True,不包含条目均为 NaN 的列。如果为 True,则在计算边距之前将忽略任何列中具有 NaN 值的行
margins_name:str,默认为“All” 当边距为 True 时将包含总计的行/列的名称
observed:bool,默认为 False 这仅适用于任何groupers 是分类的。若为True:仅显示分类groupers 的观察值。否则显示分类groupers 的所有值。
sort:bool, default True 指定结果是否应该排序

测试数据:

df = pd.DataFrame({"A": ["aaa", "aaa", "aaa", "aaa", "aaa","aa", "aa", "aa"],
                   "B": ["bbb", "bbb", "bbb", "bb", "bb", "bbb", "bbb", "bb"],
                   "C": ["small", "large", "large", "small","small", "large", "small", "small"],
                   "D": [1, 2, 2, 3, 3, 4, 5, 6],
                   "E": [2, 4, 5, 5, 6, 6, 8, 9]})
df

结果:

  • 求和
d1 = pd.pivot_table(df, values='D', index=['A', 'B'], columns=['C'], aggfunc=np.sum)   # 通过求和来聚合值
d1

结果:

  • 可以使用fill_value参数填充缺失的值
d2 = pd.pivot_table(df, values='D', index=['A', 'B'], columns=['C'], aggfunc=np.sum, fill_value=0)   # 可以使用fill_value参数填充缺失的值
d2  

  • 对多个列取平均值进行聚合
d3 = pd.pivot_table(df, values=['D', 'E'], index=['A', 'C'], aggfunc={'D': np.mean, 'E': np.mean})   # 通过对多个列取平均值进行聚合
d3 

  • 为任何给定值列计算多种类型的聚合
d4 = pd.pivot_table(df, values=['D', 'E'], index=['A', 'C'], aggfunc={'D': np.mean, 'E': [min, max, np.mean]})   # 可以为任何给定值列计算多种类型的聚合
d4

  • 默认mean 求均值
d4 = df.pivot_table(['D'], index=['A'])  
d4
'''
	D
A	
aa	5.0
aaa	2.2
'''
posted @ 2023-02-07 22:26  QiaoZhi  阅读(626)  评论(0编辑  收藏  举报