各个含report_id的表在进行表间连接时要保证report_id 不重复,即不存在一对多的关系。因此要先消除一对多关系,一种方法就是行转列unstack(),另一种就是简单的去除重复值。
PS:在索引设置的步骤,发现若先对各个dataframe reset_index(),就只能用merge指定依’report_id’合并,不能使用join()。是因为join()默认以index作为对齐的列,索引重置后join报错:ValueError: columns overlap but no suffix specified: 列重叠但未指定后缀。
博客中介绍了两种方式的代码及结果。
待处理数据表说明:
【例表部分数据如图一,码住的字段不用管,每个report_id对应有5种subtype导致有5条数据,现要进行行转列。】
pandas中的Series对象有一个方法叫做unstack,调用一个具有二级索引的Series对象的unstack方法,会得到一个DataFrame对象。其索引就是Series对象的一级索引,列就是Series对象的二级索引。
下图是unstack()能实现的效果:
参考:https://www.cnblogs.com/traditional/p/11967360.html这篇对行转列、列转行写的十分详细。
product_db=pymysql.connect(host='**', port=**,user="**", password="**", database="**", charset='utf8' )
sql='''
select t.*
from default_info t
'''
df=pd.read_sql(sql,product_db)
df.head() # 默认查看前五行
从图二的效果图可以看出只适用于三列的data,所以处理图一的四个数据列需要四次unstack,然后使用join或者merge合并。
以default_count这列为例:
unstack_count_df=df.set_index(['report_id','default_subtype'])['default_count'].unstack().add_prefix('default_subtype_').add_suffix('_count')
unstack_count_df.head()
代码拆分一下:
1、 将"report_id"和"default_subtype"设置为索引, 然后取出"default_count"这一列, 得到对应的具有二级索引的 Series 对象 :
df.set_index(['report_id','default_subtype'])['default_count']
PS:如何看取出一列数据后是什么类型 一般python使用type函数查看数据类型,但是会报错: 所以使用
isinstance() isinstance(df.set_index(['report_id','default_subtype'])['default_count'], pd.Series)
2、调用具有二级索引的Series的unstack, 会得到一个DataFrame 并会自动把一级索引变成DataFrame的索引, 二级索引变成DataFrame的列
unstack_count_df.unstack()
add_prefix('default_subtype_').add_suffix('_count')
加前缀后缀方便连接。
merge_df=unstack_count_df.join(unstack_month_df).join(unstack_overdue_sum_df).join(unstack_overdue_mon_df)
这个DataFrame的索引和列都有一个名字
索引的名字叫"report_id", 列的名字叫"default_subtype", 因为原来Series的两个索引就叫"report_id"和"default_subtype"
可以通过rename_axis(index=, columns=)
来给坐标轴重命名
#join()后列和行都有名字,修改列名,索引名不改(原来的索引有名字, 那么reset_index之后, 列名就是原来的索引名)
merge_df=merge_df.rename_axis(columns=None).reset_index()
这里详见:pandas行转列、列转行、以及一行生成多行
Pandas reset_index()是一种重置数据帧索引的方法。
reset_index()方法将范围从0到数据长度的整数列表设置为索引。
用法:
DataFrame.reset_index(level=None, drop=False, inplace=False,
col_level=0, col_fill=”)参数:
level:int,字符串或列表以选择并从索引中删除传递的列。 drop:布尔值,如果为False,则将替换的索引列添加到数据中。
inplace:布尔值,如果为True,则对原始 DataFrame 本身进行更改。 col_level:选择在哪个列级别插入标签。
col_fill:对象,以确定如何命名其他级别。返回类型:
DataFrame
unstack_count_df.unstack().reset_index()
# 假设两个reset_index()之后的df1,df2
# 两个df依report_id连接,outer表示两个df的report_id取并集
out=df2.merge(df1,on='report_id',how='outer')
out.head()
# 索引列的名字去掉就和前一种方法的输出相同了
df=out.rename_axis(columns=None)
- merge 默认的合并方式:inner,交集
- merge outer,并集,NaN补全
- merge left,左边为准,NaN补全
- merge right,右边为准,NaN补全
如果你的数据有重复,或是只有某些无关紧要的数据列不同,还有另一种方法去除一对多:
【按照report_id和first_month排序,去重时选择保留第一个,就会report_id 相同的各行中保留日期最早的一条,达到去除一对多的目的。】
biz_df=biz_df.sort_values(by=['report_id','first_month'])
biz_df.drop_duplicates(['report_id'],keep='first',inplace=True) # 最早日期
排坑:
drop_duplicates()这里的inplace默认是false,设置为True就会在原dataframe上改,就不要写成df=df.drop_duplicates([‘report_id’],keep=‘first’,inplace=True)
会将df变成NoneType。