Skip to main content

CP07 基于pandas的多文件合并

阅读:-


使用python的内置组件,可以完成很多复杂的报表制作, 但是开发的工作量比较大,如果希望用比较小的工作量

来实现一些复杂的报表开发工作,那么就要借助一款成为pandas的组件,实现相关的报表开发工作。使用pandas以后,一些利用数据仓库方案非常复杂的报表编制工作,业可以非常简单的来实现。这大概就是pandas的魅力i所在吧。

7 Pandas多文件合并(两题+附加题)

7.1 问题背景约束

随着金融大数据应用的广泛流行,可以从云化金融大数据平台上导出的所产生的数据状况数以亿计字节的信息。大量的数据被获取、交流、集聚、存储和分析,从其拥有的数据规模、数据的复杂类型来看,处理起来会带来各种问题,以及对庞大的数据解析所消耗的时间,都会造成现场处理不便,学会使用工具读写文件是我们学习的第一步。

1587293305495

在基于pandas的方案中,有一个内置的函数可以实现相关的功能:

1587293543506

7.1.1 用例描述

1.用户界面向处理组件传递参数,入参包括 需要合并的文件清单,以及期望的合并文件名称。

2.处理组件接收入参以后, 首先根据文件清单中的文件绝对路径,通过文件系统,识别需要处理的文件列表。

3.根据待处理的文件列表, 利用列表生成式 将多个CSV文件装载为DF文件,形成一个DF 的列表。

DFS= [df1, df2, df3, … , dfN]

4.将DFS 作为入参,调用利用pandas 的内置函数进行合并,经合并的结果传递给新的DF

5.将DF转换为CSV文件,文件的名称来自入参。

6.应用程序返回程序执行响应 [ 执行结果,输出结果文件信息]

其中执行结果:0 成功 1 失败

输出结果文件信息:提供输出结果文件的决对路径,举例如下:

D:\PAE\ csv-merge.xlsx

7.1.2 IPO 分析

7.1.2.1 输入数据准备

入参包括 需要合并的文件清单,以及期望的合并文件名称。

其中,

1,需要合并的文件清单,采用list格式,举例如下:

[D:\ PAE\ QLR2019020710-001.csv, D:\ PAE\ QLR2019020710-002.csv,

D:\ PAE\ QLR2019020710-003.csv]

2, 期望合并文件名称, 输出文件的名称。

举例如下:

D:\PAE\ csv-merge.xlsx

文件数据格式如下:

QLR2019020710-001.csv

QLR2019020710-002.csv

QLR2019020710-003.csv

1587293764283

7.1.2.2 处理过程(P)

详细见用例描述

7.1.2.3 输出数据(O)

应用程序返回程序执行响应 [ 执行结果,输出结果文件信息]

其中执行结果:0 成功 1 失败

输出结果文件信息:提供输出结果文件的决对路径,举例如下:

D:\PAE\ csv-merge.xlsx

7.2 用例约束

  1. 使用pandas内置组件,合并df。

  2. 使用pandas内置读取文件,python内置组件,合并df

  3. 附加题要求输出excle格式的文件合并。

7.3 内存节省方案

在前面用例的设计环节中,采用的方案是 将待合并的多个csv文件,转换为pandas的DF格式, 形成一个列表,列表的元素为 DF。 然后将list 作为输入,传递给pd.concat() 函数进行处理,因为pandas 的很多函数都能处理 list。

相关的原型代码如下:

dfs = [pd.read_csv(f) for f in filelist]

df = pd.concat(dfs)

这个方案书写的比较清晰,但是存在一个风险在于,前期把多个文件写入到内存DF中,形成一个list[]

[df1, df2, df3, … , df10]

这个方案会非常消耗内存。 如果在 每个Df都很大的情况下,可能会导致内存过度占用。所以要考虑一种节省内存的方案。

7.3.1 优化的处理过程

1、用户界面向处理组件传递参数,入参包括 需要合并的文件清单,以及期望的合并文件名称。

2,处理组件接收入参以后, 首先根据文件清单中的文件绝对路径,通过文件系统,识别需要处理的文件列表。

3,首先创建一个空的DF。

4, 根据待处理的文件列表,利用列表生成式,遍历待合并的文件。

4.1 选取一个文件,转载到内存中,以DF1的格式。

4.2 将DF和DF1进行合并操作中

4.3 关闭DF1

4.4 继续打开下一个文件,装载在内存中,以DF2格式,重复上面的处理过程。

4.5 打开最后一个文件装载为DFn, 将将DF和DFn进行合并操作中

4.6 关闭DFn

5、将DF转换为CSV文件,文件的名称来自入参。

6,应用程序返回程序执行响应 [ 执行结果,输出结果文件信息]

其中执行结果:0 成功 1 失败

输出结果文件信息:提供输出结果文件的决对路径,举例如下:

D:\PAE\ csv-merge.xlsx

大致的处理原型为:

df = pd.DataFrame([])
for f in filelist:
df = pd.concat([df,pd.read_csv(f)])

7.3.2 扩展练习

请参考优化的处理过程,完成相关的练习。

7.4 设计方案简介

7.4.1 Append方案

7.4.1.1 设计要点

1、 读取

2、 合并

3、 写入

7.4.1.2 调用关系

7.4.1.3 流穿越

1、file_data list中包含了多个df

1587348654051

2、通过append追加

1587348674216

3、写入本地

1587348690214

7.4.2 Concat方案

7.4.2.1 调用关系

1587348746971

7.4.2.2 流穿越

1、file_data list中包含了多个df

1587348777363

2、通过concat追加

1587348800235

3、写入本地

1587348816527

7.5 Append设计方案详解

1587348851932

图 7-1 APPend 方案

从上图可见,以上是基于DF的APPend方案整理的设计方案。核心的步骤分为两步。

1.将待合并的文件利用pandas的装载到内存中,以DF格式,并生成一个列表file_data[], 其中每一个元素代表了一个DF。

2.完成转换的过程。

2.1 将列表file_data[]中的元素逐个取出,追加到DF中;

2.2 对DF的格式进行调整;

2.3 将DF输出到CSV;

7.5.1 链式调用

7.5.1.1 Pipelines 处理模式

Pilelines处理模式是早期unix系统的一种处理模式,而在今天的大数据处理的项目中,Pipelines 处理模式也成为一种非常重要的编程模式。

在一个基于unix操作系统的哦计算机中,管道 pipeline是一种使用消息传递进行进程间通信的机制。管道实质是是一组透过标准的stream对象链式连接的进程。这样,因此每个进程(stdout)的输出文本直接作为输入(stdin)传递给下一个进程。 第一个进程在第二个进程启动之前未完成,但它们是同时执行的。在Unix的开发过程中,道格拉斯·麦克罗伊(Douglas McIlroy)在Unix的发源地的贝尔实验室大力提倡了“管道”概念,它通过类比物理管道命名。 这些管道的一个关键特征是它们“隐藏内部hiding of internals””(Ritchie&Thompson,1974)。 在这种机制下使得系统更清晰和简单。

1587348916708

图 7-5 A pipeline of three program processes run on a text terminal

上图是一个关于unix系统中的文本终端操作的一个案例,他使用的是一种叫做anonymous pipes的机制,在这种机制下前一个进程写的数据会通过操作系统进行缓存,直到下一个进程读出相关的进程为止, 这个单向的管道会在所有进程结束时消失。。

匿名管道的标准shell语法是列出多个命令,用竖线分隔

 process1 | process2 | process3

举例来说,要显示当前目录下的所有文件(ls) ,过滤出ls output中 包含了字符串”key”(grep),并在滚动页面(更少)中查看结果,用户在终端的命令行中键入以下内容:

ls -l | grep key | less

“ls -l”产生一个进程,其输出(stdout)通过管道输出到“grep key”进程的输入(stdin); 同样适用于“少”的过程。 每个进程都从前一个进程获取输入,并通过标准流为下一个进程生成输出。 每个“|”告诉shell通过(匿名)管道的进程间通信机制,将左侧命令的标准输出连接到右侧命令的标准输入。 管道是单向的; 数据从左到右流过管道。

7.5.1.2 DF的链式调用

df.reset_index(drop=True).to_csv(“./生成文件.csv”, encoding=‘gbk’,index=None)

在这一步的操作中,采用的就是一种链式调用的机制,非常适合进行数据ETL的处理。

DF 的索引调整

1587348948864

7.5.2 关键知识点

1587349030595

7.5.3 DF格式序列号调整

7.5.3.1 应用目的

在多df数据合并后,还是乱序的,需要重新排列下。如:pandas contact 之后,一定要记得用reset_index去处理index,不然容易出现莫名的逻辑错误。

直接contact之后,index只是重复,而不是变成我们希望的那样,这样在后续的操作中,容易出现逻辑错误。

使用result = result.reset_index(drop=True)来改变index就可以了,

7.5.3.2 语法说明

reset_index可以还原索引,从新变为默认的整型索引 DataFrame.reset_index(level=None, drop=False, inplace=False, col_level=0, col_fill=”) level控制了具体要还原的那个等级的索引 drop为False则索引列会被还原为普通列,否则会丢失

set_index():

函数原型:DataFrame.set_index(keys, drop=True, append=False, inplace=False, verify_integrity=False)

参数解释:

keys:列标签或列标签/数组列表,需要设置为索引的列

drop:默认为True,删除用作新索引的列

append:默认为False,是否将列附加到现有索引

inplace:默认为False,适当修改DataFrame(不要创建新对象)

verify_integrity:默认为false,检查新索引的副本。否则,请将检查推迟到必要时进行。将其设置为false将提高该方法的性能。

7.5.3.3 case举例

1587349087299

7.5.3.4 注意事项

在多df合并后往往需要用.set_index,作用于新生成的df,对其index重新排列放置,避免乱序逻辑错误。

7.5.4 DF对象的主要方法

7.5.4.1 应用目的

Pandas中特有数据类型如下表:

Pandas信息模型1,PandasPandas是一个强大的分析结构化数据的工具集;它的使用基础是Numpy(提供高性能的矩阵运算);用于数据挖掘和数据分析,同时也提供数据清洗功能。
2,DataFrameDataFrame是Pandas中的一个表格型的数据结构,包含有一组有序的列,每列可以是不同的值类型(数值、字符串、布尔型等),DataFrame即有行索引也有列索引,可以被看做是由Series组成的字典。
2,Series它是一种类似于一维数组的对象,是由一组数据(各种NumPy数据类型)以及一组与之相关的数据标签(即索引)组成。仅由一组数据也可产生简单的Series对象。

了解并掌握df通用,高频率方法,对我们的后续学习大有帮助。

1587349652195

图 7-6 数据处理的四个层次

报表处理是非常重要的一个数据应用处理过程,他实现了从DATA到information的处理过程, 因此是非常重要的一种应用编程技能。

7.5.4.2 DF数据容器的概念说明

容器选择:

1587349156145

图 7-6 DF作为一种数据容器

Information意涵:对原始数据所做出的统计数据,或者检索

1.列表:

s[index]:列表s第index位置的值

min(s):列表s最小值

max(s):列表s最大值

s.index(x):元素x所在位置

s.count(x):元素x个数

2.字典:

len(d):字典长度

d[key]: key对应的值

d.values(): 字典中所有值

d.items():字典中所有键和值

d.keys():字典中所有键

3.通用:

in 、 not int :判断 元素、键 是不是在列表/字典中

1587349245181

图 7-6 DF 应用的几个层次

7.5.4.3 case举例

1 DataFrame的生成

方法1:直接生成df

df=pd.DataFrame([[1,2,3],[2,2,2],[3,3,3]],index=['a','b','c'], columns=['e','f','g'])
注意value录入要加上【value】
 
可以生成空的df,默认取值为nan
df=pd.DataFrame(value,index='',columns='')

方法2:字典转化为df

dic1={'name':['小明','小红','幽鬼','敌法'],'age':[17,20,5,40],'gender':['男','女','女','男']}
df=pd.DataFrame(dic1)

方法3:读取txt/excel文件时,输出的就是df格式

df = pd.read_excel(“file_name.xlsx”)

方法4:从矩阵A转化为df

df= pd.DataFrame.from_records(A,columns=name)  

注:pd.DataFrame和pd.Series是两个不同的函数

2 获取行列名称、行高、列高
df.index    行名称
df.columns  列名称
df._info_axis_     列名称
 
(bike1,bike2)=df.shape  行、列高度
len(df)    输出的是行高
df.index.size    行高
df.columns.size   列高
3 取行、列,切片操作

取单行后是一个Series,Series有index而无columns ‘Series’ object has no attribute ‘columns’

df['x']      取列名为'x'的列,格式为series
df[['x']]    取列名为'x'的列,格式为Dataframe
df[['w','z']]    取多列时需要用Dataframe的格式
df[df.columns[0:3]]    按照索引位置来取列,其实是分两步,先用索引取列名,再用列名取列
 
df.loc['A']  取行名为'A'的行
df[0:2]    取索引对应的行
df.loc[:,['x','z'] ]          #表示选取所有的行以及columns为x,z的列
 
df['name'].values    取列名为'name'的列的值(取出来的是array而不是series)取单行后是一个Series,Series有index而无columns,可以用name来获取单列的索引
 
df.head(4)    取头四行
df.tail(3)    取尾三行
 
df.iloc[1,1]    根据绝对索引来取值,所谓绝对索引即按照0,1,2这样的人眼顺序来进行排列的原始索引  
df.iloc[0:3, [0,1]]
df.iloc[1]   绝对索引第一行
4 替换与删除
point_table.rename(columns={0:'point_key', 1:'point', 2:'count1', 3:'count2'})     #索引改名称
 
df[i]=x    #x为常数,全替换;x为向量则要求与替换行/列长度一样
 
bus=np.where(x2 < 1.5)    #np里相当于matlab里的find
df.values[bus]=1.66 * df.values[bus]   #根据绝对位置进行部分值的替换

去除nan值:

df4 = pd.read_csv('4.csv',  encoding='utf-8')
 
df4 = df4.dropna()  #去除含有nan的行
 
# 可以通过axis参数来删除含有空数据的全部列
 
df4 = df4.dropna(axis=1)
df4 = df4 .drop(['工作饱和度'], axis=1)  # 删除指定column的列

【1】pandas dataframe删除一行或一列:drop函数 https://blog.csdn.net/songyunli1111/article/details/79306639

5 拼接与拆分

注意: df.append 生成了新的对象 list.append 直接修改原对象

df.append()
 
纵向(上下)拼接和横向(左右)拼接:
axis=0为纵向拼接
concat([df1,df2]) 等价于 df1.append(df2)
 
在axis=1 时为横向拼接 ,此时有
concat([df1,df2],axis=1) 等价于 merge(df1,df2,left_index=True,right_index=True,how='outer')

如果要合并多个Dataframe,可以用list把几个Dataframe装起来,然后使用concat转化为一个新的Dataframe

df=pd.concat([train1, train2, train3, train4],axis=1,ignore_index=False)

拆分

df.groupby['columns_name']
6 计算

使用sum默认对每列求和,sum(1)为对每行求和 两个series可以直接进行加减乘除计算

7 排序
8 DataFrame在IDLE里的查看

pd.set_option(‘display.width’, 200) # 横向最多显示多少个字符, 一般80不适合横向的屏幕,平时多用200.

pd.set_option(‘display.max_columns’, 12) pd.set_option(‘display.max_rows’, 10) # 显示的最大行数和列数

pd.set_option(‘colheader_justify’, ‘left’) 显示的单元格内容靠左边还是右边

9 多重索引
temp_df = temp_df.reset_index()    取消多重索引

【1】 DataFrame多重索引 https://blog.csdn.net/kylinxjd/article/details/98621546

10 插入行/列
train['工作饱和度'] = saturation_str   # 增加一列
train.insert(4, '工作饱和度', saturation_str)   # 插入一列

7.5.4.4 注意事项

需要详细理解记忆,df各语法特点与应用场景,根据实际需求选择最适合的方法。

7.5.4.5!!!loc-索引的不同选择

对象选择已经有许多用户请求的添加,以支持更明确的基于位置的索引。Pandas现在支持三种类型的多轴索引。

  • .loc主要是基于标签的,但也可以与布尔数组一起使用。当找不到物品时.loc会提高KeyError。允许的输入是:

  • 单个标签,例如5'a'(注意,它5被解释为索引的 标签。此用法不是索引的整数位置。)。

  • 列表或标签数组。['a', 'b', 'c']

  • 带标签的切片对象'a':'f'(注意,相反普通的Python片,开始和停止都包括在内,当存在于索引中!见有标签切片端点都包括在内。)

  • 布尔数组

  • 一个callable带有一个参数的函数(调用Series或DataFrame)并返回有效的索引输出(上面的一个)。

版本0.18.1中的新功能。

标签选择中查看更多信息。

.iloc是基于主要的整数位置(从0length-1所述轴的),但也可以用布尔阵列使用。 如果请求的索引器超出范围,.iloc则会引发IndexError,但允许越界索引的切片索引器除外。(这符合Python / NumPy 切片 语义)。允许的输入是:

  • 一个整数,例如5
  • 整数列表或数组。[4, 3, 0]
  • 带有整数的切片对象1:7
  • 布尔数组。
  • 一个callable带有一个参数的函数(调用Series或DataFrame)并返回有效的索引输出(上面的一个)。

版本0.18.1中的新功能。

有关详细信息,请参阅按位置选择高级索引高级层次结构

.loc.iloc以及[]索引也可以接受一个callable索引器。在Select By Callable中查看更多信息。

从具有多轴选择的对象获取值使用以下表示法(使用.loc作为示例,但以下也适用.iloc)。任何轴访问器可以是空切片:。假设超出规范的轴是:,例如p.loc['a']相当于 。p.loc['a', :, :]

对象类型索引
系列s.loc[indexer]
数据帧df.loc[row_indexer,column_indexer]

7.6 Concat设计方案详解

7.6.1 领域对象模型

1587349938726

图 7-2 concat方案

从上图可见,concat() 方法可以理解连接方法,是pandas内置的函数,他的输入对象是两个DF,输出对象是一个DF,所以在这里,我们可以通过迭代调用的方式,实现这种多个DF的合并处理。

另外,这里,我们应用的是一种内存节省的算法,通过迭代的方式实现了多个DF1的合并。

1.6.2 关键知识点

pandas的concat方案合并1.DF之间合并pd.concat()
2.两种方案比较比较两种方案的优劣

7.6.3 DF之间合并与两种方案比较

7.6.3.1 应用目的

实际应用场景,df之间的合并,由data转向information

7.6.3.2 语法说明

1、concat
pd.concat(objs, axis=0, join='outer', join_axes=None, ignore_index=False,keys=None, levels=None, names=None, verify_integrity=False)

objs: series,dataframe或者是panel构成的序列list axis:需要合并链接的轴,0是行,1是列 join: 连接的方式 :inner,outer

2、append
df1.append(df2)

7.6.3.3 case举例

1.相同字段的表首尾相接

1587349986217

import pandas
pd.concat([df1,df2,df3])

相接的时候在加上一个层次的keys来识别数据源自于哪张表,可以增加keys参数:

import pandas
pd.concat([df1,df2,df3],keys=["df1","df2","df3"])

1587350001808

2.行对齐进行拼接

1587350022110

pd.concat([df1,df4],axis=1)

3.join属性:’inner’是两表的交集,“outer”是两表的并集

1587350041270

pd.concat([df1, df4], axis=1, join='inner')

4.join_axes:可以指定根据那个轴来对齐数据

1587350058050

pd.concat([df1, df4], axis=1, join_axes=[df1.index])

5.无视index:两个表的index都没有实际含义,使用ignore_index参数,合并的两个表就根据列字段对齐,然后合并并得到新的index

1587350084054

5.append:append是series和dataframe的方法,使用它就是默认沿着(axis = 0)列进行拼接

1587350099690

df1.append(df2)

6.Dataframe中加入新的行

1587350164929

7.表格列字段不同的表合并

1587350183898

df1.append(dicts, ignore_index=True)

7.6.3.4 注意事项

Concat可以根据配置选择多种df组合方式,但需注意index的序号重排列。Append只能上下连接,请根据实际情景进行选择。

7.7 总结

本章中,我们提供了两种方法来实现CSV合并。我们发现利用Pandas方案,可以很好的处理dataset类型的数据,是一种强大的报表中间件。

分享到微博
Starter
MicroServ
Tutorials
Report
Blog