Python 基础 | pandas 中 dataframe 的整合与形变 (merge & reshape)
目录
行的 unionpd.concat
df.append
列的 joinpd.concat
pd.merge
df.join
行列转置pivot
stack&unstack
melt
本文示例数据下载 https://pan.baidu.com/s/1lQIpvwThXRkUJ16Fl4ERNA , 密码: vwy3importpandasaspd
# 数据是之前在 cnblog 上抓取的部分文章信息
df=pd.read_csv('./data/SQL 测试用数据_20200325.csv',encoding='utf-8')
# 为了后续演示, 抽样生成两个数据集
df1=df.sample(n=500,random_state=123)
df2=df.sample(n=600,random_state=234)
# 保证有较多的交集
# 比例抽样是有顺序的, 不加 random_state, 那么两个数据集是一样的
行的 union
pandas 官方教程
pd.concat
pd.concat 主要参数说明:
要合并的 dataframe, 可以用 [] 进行包裹, e.g. [df1,df2,df3];
axis=0,axis 是拼接的方向, 0 代表行, 1 代表列, 不过很少用 pd.concat 来做列的 join
join='outer'
ignore_index: bool = False, 看是否需要重置 index
如果要达到 union all 的效果, 那么要拼接的多个 dataframe, 必须:
列名名称及顺序都需要保持一致
每列的数据类型要对应
如果列名不一致就会产生新的列
如果数据类型不一致, 不一定报错, 要看具体的兼容场景
df2.columns
输出:Index(['href','title','create_time','read_cnt','blog_name','date','weekday','hour'],dtype='object')
# 这里故意修改下第 2 列的名称
df2.columns=['href','title_2','create_time','read_cnt','blog_name','date','weekday','hour']
print(df1.shape,df2.shape)
# inner 方法将无法配对的列删除
# 拼接的方向, 默认是就行(axis=0)
df_m=pd.concat([df1,df2],axis=0,join='inner')
print(df_m.shape)
输出:(500,8)(600,8)
(1100,7)
# 查看去重后的数据集大小
df_m.drop_duplicates(subset='href').shape
输出:(849,7)
df.append
和 pd.concat 方法的区别:
append 只能做行的 union
append 方法是 outer join
相同点:
append 可以支持多个 dataframe 的 union
append 大致等同于pd.concat([df1,df2],axis=0,join='outer')
df1.append(df2).shape
输出:(1100,9)
df1.append([df2,df2]).shape
输出:
(1700, 9)
列的 join
pd.concat
pd.concat 也可以做 join, 不过关联的字段不是列的值, 而是 index
也因为是基于 index 的关联, 所以 pd.concat 可以对超过 2 个以上的 dataframe 做 join 操作# 按列拼接, 设置 axis=1
# inner join
print(df1.shape,df2.shape)
df_m_c=pd.concat([df1,df2],axis=1,join='inner')
print(df_m_c.shape)
输出:(500,8)(600,8)
(251,16)
这里是 251 行, 可以取两个 dataframe 的 index 然后求交集看下set1=set(df1.index)
set2=set(df2.index)
set_join=set1.intersection(set2)
print(len(set1),len(set2),len(set_join))
输出:500600251
pd.merge
pd.merge 主要参数说明:
left, join 操作左侧的那一个 dataframe
right, join 操作左侧的那一个 dataframe, merge 方法只能对 2 个 dataframe 做 join
how: join 方式, 默认是 inner,str = 'inner'
on=None 关联的字段, 如果两个 dataframe 关联字段一样时, 设置 on 就行, 不用管 left_on,right_on
left_on=None 左表的关联字段
right_on=None 右表的关联字段, 如果两个 dataframe 关联字段名称不一样的时候就设置左右字段
suffixes=('_x', '_y'), join 后给左右表字段加的前缀, 除关联字段外print(df1.shape,df2.shape)
df_m=pd.merge(left=df1,right=df2\
,how='inner'\
,on=['href','blog_name']
)
print(df_m.shape)
输出:(500,8)(600,8)
(251,14)
print(df1.shape,df2.shape)
df_m=pd.merge(left=df1,right=df2\
,how='inner'\
,left_on='href',right_on='href'
)
print(df_m.shape)
输出:(500,8)(600,8)
(251,15)
# 对比下不同 join 模式的区别
print(df1.shape,df2.shape)
# inner join
df_inner=pd.merge(left=df1,right=df2\
,how='inner'\
,on=['href','blog_name']
)
# full outer join
df_full_outer=pd.merge(left=df1,right=df2\
,how='outer'\
,on=['href','blog_name']
)
# left outer join
df_left_outer=pd.merge(left=df1,right=df2\
,how='left'\
,on=['href','blog_name']
)
# right outer join
df_right_outer=pd.merge(left=df1,right=df2\
,how='right'\
,on=['href','blog_name']
)
print('inner join 左表∩右表:'+str(df_inner.shape))
print('full outer join 左表∪右表:'+str(df_full_outer.shape))
print('left outer join 左表包含右表:'+str(df_left_outer.shape))
print('right outer join 右表包含左表:'+str(df_right_outer.shape))
输出:
(500, 8) (600, 8)
inner join 左表∩右表:(251, 14)
full outer join 左表∪右表:(849, 14)
left outer join 左表包含右表:(500, 14)
right outer join 右表包含左表:(600, 14)
df.join
df.join 主要参数说明:
other 右表
on 关联字段, 这个和 pd.concat 做列 join 一样, 是关联 index 的
how='left'
lsuffix='' 左表后缀
rsuffix='' 右表后缀print(df1.shape,df2.shape)
df_m=df1.join(df2,how='inner',lsuffix='1',rsuffix='2')
df_m.shape
输出:(500,8)(600,8)
(251,16)
行列转置
pandas 官方教程# 数据准备
importmath
df['time_mark']=df['hour'].apply(lambdax:math.ceil(int(x)/8))
df_stat_raw=df.pivot_table(values=['read_cnt','href']\
,index=['weekday','time_mark']\
,aggfunc={'read_cnt':'sum','href':'count'})
df_stat=df_stat_raw.reset_index()
df_stat.head(3)
如上所示, df_stat 是两个维度 weekday,time_mark
以及两个计量指标 href, read_cnt
pivot
# pivot 操作中, index 和 columns 都是维度
res=df_stat.pivot(index='weekday',columns='time_mark',values='href').reset_index(drop=True)
res
stack&unstack
stack 则是将层级最低 (默认) 的 column 转化为 index
unstack 默认是将排位最靠后的 index 转成 column(column 放到下面)
# pandas.pivot_table 生成的结果如下
df_stat_raw
# unstack 默认是将排位最靠后的 index 转成 column(column 放到下面)
df_stat_raw.unstack()
# unstack 也可以指定 index, 然后转成最底层的 column
df_stat_raw.unstack('weekday')
# 这个语句的效果是一样的, 可以指定 `index` 的位置
# stat_raw.unstack(0)
# stack 则是将层级醉倒的 column 转化为 index
df_stat_raw.unstack().stack().head(5)
# 经过两次 stack 后就成为多维表了
# 每次 stack 都会像洋葱一样将 column 放到左侧的 index 来(放到 index 序列最后)
df_stat_raw.unstack().stack().stack().head(5)
输出:weekday time_mark
10href4
read_cnt2386
1href32
read_cnt31888
2href94
dtype:int64
pd.DataFrame(df_stat_raw.unstack().stack().stack()).reset_index().head(5)
melt
melt 方法中 id_vals 是指保留哪些作为维度(index), 剩下的都看做是数值(value)
除此之外, 会另外生成一个维度叫 variable, 列转行后记录被转的的变量名称
print(df_stat.head(5))
df_stat.melt(id_vars=['weekday']).head(5)
df_stat.melt(id_vars=['weekday','time_mark']).head(5)
来源: https://www.cnblogs.com/dataxon/p/12634897.html