数据合并
两表合并
已知a c两个都含有数据的xlsx文件
要求:将a文件数据写入c数据
只用pandas包实现
为什么不直接df01.to_excel()到c文件的路径?
答:pandas中的to_excel方法会重写覆盖,做不到在c文件中继续写入的功能,所以先合并成总的DataFrame再to_excel重写覆盖进去。
实现逻辑一:
data1+data2合并 --> 重写覆盖
1,拿出a文件数据df01,拿出c文件数据df02
2,concat方法,合并2个df,合并后的DataFrame赋值为df03
3,df03.to_excel()
缺点: 数据文件很大 或者 很多文件都同时插入同一个文件时,执行耗时长。
不是加个mode='a’的参数就可以了么?
答:虽然to_excel和to_csv的两者非常相似,但是在参数方面还是有细微的区别,to_csv里面有mode='a’参数,而to_excel中没有mode参数。
实现逻辑二:
将要写入的文件进行 excel --> csv --> excel 操作,目的是借用to_csv的mode参数。
1,拿出c文件数据df02写入到一个新的csv文件,命名为f,(直接Excel里面,另存为,可能会出问题)
2,从a文件拿出数据df01利用to_csv写入到f文件中
3,将f文件,另存为.xlsx格式的文件就行。
或者你代码直接read_csv(记得加参数encoding='gbk'这样不会报错!)再to_excel都行。
下面提供,实现逻辑一,的解决方案:
import pandas as pd
'''
将一个Excel文件写入另一个Excel文件中
执行逻辑:
创建一个需要写入的文件
在已创建的文件into_file中写入,从open_file中拿出的数据
执行过程:
只用pandas , 因为pandas的to_excel相当于重写覆盖
所以需要把两个文件都打开变成2个Dataframe然后进行合并后,重写覆盖进要写入的文件中
'''
def write_excel_xls(open_file,into_file):
'''
:param open_file: 要拿出用于写入的文件
:param into_file: 要写入的汇总文件
:param combined: 合并后的文件
:return:
'''
open_path = 'C:\\Users\\Administrator\\Desktop\\{}.xlsx'.format(open_file)
into_path = 'C:\\Users\\Administrator\\Desktop\\{}.xlsx'.format(into_file)
open_data = pd.read_excel(open_path,header=None)
into_data = pd.read_excel(into_path,header=None)
# lens = df[0].shape
open_row =open_data[0].shape[0]
into_row =into_data[0].shape[0]
print(open_data)
print('{}文件的行数为{}'.format(open_file,open_row))
print(into_data)
print('{}文件的行数为{}'.format(into_file,into_row))
print('合并后的表如下所示:')
combined = pd.concat([into_data,open_data],ignore_index=True)
print(combined)
combined.to_excel(into_path,index=False,header=None)
print("xls格式表格写入数据成功!")
write_excel_xls('a','c')
如果你要合并到的那个Excel文件(假设文件名叫c)有索引,那么用pandas打开c文件的read_excel的参数header=None这一行不要。
如果你的Excel还有其他别的小需求,可以参考下面这个我写的博客。
pandas对Excel或者CSV或者数据库操作和参数,看这里
用xlrd包实现
Python 在已存在的excel表格中写入数据
xlrd模块详解
xlrd模块我不是很熟悉,花费了一番时间功夫的摸索,还是被我搞定了!
需要注意的是:
打开的工作簿工作表示谁?
写入的工作表sheet的对象是谁?
对哪个sheet对象执行write操作?
哪个工作簿workbook的哪个path进行save?
不然你很容易搞不清楚,从而得到的结果会出现问题,可能还是重写覆盖或者别的问题。
实现逻辑:
1,读取d文件(要写入的文件)的行数
2,读取a文件(sheetobj.get_rows得到一个可迭代对象)
3,将这个可迭代对象,逐行,从d文件的末尾写下去
4,保存d文件即可。
import copy
import xlrd
from xlutils import copy
def write_excel_xls(read_file,write_file):
read_path = 'C:\\Users\\Administrator\\Desktop\\{}.xlsx'.format(read_file)
write_path = 'C:\\Users\\Administrator\\Desktop\\{}.xlsx'.format(write_file)
#拿出数据
r_book = xlrd.open_workbook(read_path)
#获取sheet表的数据,return一个可迭代对象
sheets = r_book.sheet_by_index(0).get_rows()
#获取要写入的工作表的总行数
r_book02 = xlrd.open_workbook(write_path)
row = r_book02.sheet_by_index(0).nrows
#得到可写入的sheet对象w_sheet
w_book02 = copy.copy(r_book02)
w_sheet02 = w_book02.get_sheet(0) # w_sheet = w_book.sheets()[0]
i = 0
for k in sheets:
#在指定 行列 写入数据
print(k)
w_sheet02.write(row+i, 0, k[0].value) # 像表格中写入数据(对应的行和列)
w_sheet02.write(row+i, 1, k[1].value) # 像表格中写入数据(对应的行和列)
w_sheet02.write(row+i, 2, k[2].value) # 像表格中写入数据(对应的行和列)
i += 1
w_book02.save(write_path) # 保存工作簿
print('写入{}条数据成功!'.format(i))
write_excel_xls('a','d')
普通的文件读写
普通文件读写,很久没写了,常用的还是会一些,对于编码乱码这方面,还是让我很头痛!
资料查了半天
我觉得,直接open一个xlsx文件应该是不行的,无论你把编码格式改成什么都不行。
但是打开txt文件可行,或者导入csv模块去打开csv文件那就有点绕远了。
实现逻辑:
将要写入的文件进行 excel --> txt --> excel 操作,目的是借助‘a’参数不会重写覆盖,以及不出现中文乱码。
(如果有能直接open一个excel文件,并且不出现乱码的方法,麻烦知道的大佬评论指点一下,谢谢!)
1,将a文件另存为txt文件
2,用read()读取a文件里的数据
3,将读取的数据通过write()方法写入到另外一个txt文件中(如果是有数据的excel,麻烦转换成txt这样就可以用'a'参数做到不会重写覆盖)
4, 借用pandas将txt文件转成xlsx文件,先读取read_table(记得加参数encoding='gb18030'这样不会乱码报错!)再to_excel即可,
直接txt另存为,改编码格式,得到的xlsx文件虽然显示上没问题,但是工作簿里会提示你修复啥的,可能会有些小问题。
import pandas as pd
def write_to_txt(read_file,write_file):
read_path = 'C:\\Users\\Administrator\\Desktop\\{}.txt'.format(read_file)
write_path = 'C:\\Users\\Administrator\\Desktop\\{}.txt'.format(write_file)
with open(read_path,encoding='gb18030', errors='ignore') as f:
a = f.read()
with open(write_path,'a') as writer:
writer.write(a)
write_to_txt('a','f')
df = pd.read_table('C:\\Users\\Administrator\\Desktop\\f.txt',encoding='gb18030')
print(df)
df.to_excel('C:\\Users\\Administrator\\Desktop\\f01.xlsx')
总结
以上4种逻辑,借助csv或者txt转换格式的太麻烦了。
所以相对比较方便的是:
1,pandas包先合并再重写覆盖。
2,xlrd模块,进行工作簿工作表直接逐行继续写入操作。
这2个里面,
方法1需要合并操作,然后再进行重写覆盖操作。
方法2用for循环去取迭代器的数据,逐行写入。
所以,相对来看应该方法2会更快一些。
多表数据合并
比如,上面这种,pick文件夹里面,一堆的文件夹,一堆的文件夹里面又是一堆的文件夹或者是xlsx文件
我的最终目的是要把pick文件夹里所有的xlsx文件 全部写到一个total.xlsx文件中。
那么我该怎么构建逻辑呢?
首先有了上述,两表合并的函数之后,我们只需要再写一个遍历文件夹去找文件的方法就行了
一旦找到一个xlsx文件,就执行两表合并的函数方法
当然,文件量一大,效率肯定会降低,不过可以用多进程,或者异步这些来提速,下面我先介绍一般的逻辑构建。
代码由一个查找文件函数,和一个写入文件函数组成。(写入函数我这里用的是pandas包合并,你也可以换成xlrd包的那个函数会快一些)
import pandas as pd
import os
# import company
total_dir_path = 'C:\\Users\\Administrator\\Desktop\\12.18-12.25\\pick'
# total_list = os.listdir(total_dir_path)
# print(total_list)
target_file_path = 'C:\\Users\\Administrator\\Desktop\\b.xlsx'
def find_file_to_work(total_dir_path,target_file_path):
total_list = os.listdir(total_dir_path)
print('该目录下的文件夹(包)总数为:{}'.format(len(total_list)))
print(total_dir_path)
for i in total_list:
print(i)
test_path = total_dir_path+'\\{}'.format(i)
condition = os.path.isfile(test_path)
print(condition)
if condition:
write_excel_xls(test_path,target_file_path)
print('一个文件写入成功!')
else:
dir_path = test_path
find_file_to_work(dir_path,target_file_path)
def write_excel_xls(open_file_path,target_file_path):
# open_path = 'C:\\Users\\Administrator\\Desktop\\{}.xlsx'.format(open_file)
# into_path = 'C:\\Users\\Administrator\\Desktop\\{}.xlsx'.format(into_file)
open_data = pd.read_excel(open_file_path,header=None)
into_data = pd.read_excel(target_file_path,header=None)
# lens = df[0].shape
open_row =open_data[0].shape[0]
into_row =into_data[0].shape[0]
print(open_data)
print('{}文件的行数为{}'.format(open_file_path,open_row))
print(into_data)
print('{}文件的行数为{}'.format(target_file_path,into_row))
print('合并后的表如下所示:')
combined = pd.concat([into_data,open_data],ignore_index=True)
print(combined)
combined.to_excel(target_file_path,index=False,header=None)
print("xls格式表格写入数据成功!")
find_file_to_work(total_dir_path,target_file_path)
一般逻辑这样写出来,我拿去执行,200多个文件写入同一个文件,花了大概有 7 8 分钟肯定有的,最终得到了一张5万多条的总数据表。 我忘了加时间函数去测一测时间了。。。因为太慢了。。懒得跑第二遍了= =。
但是用多进程、多线程、或者协程,来进行优化操作呢?
逻辑是这样的,进程(线程),在抢占资源过程中,会发生数据覆盖造成的数据丢失。所以这种情景下,并不怎么适合进程线程,协程反而更适合些。
然而用异步协程,在这种逻辑下,在实际意义上也优化不了多少。
python uvloop异步框架学习
最新Python异步编程详解
异步代码如下:
import asyncio
import time
import os
import xlrd
from xlutils import copy
total_dir_path = 'C:\\Users\\Administrator\\Desktop\\12.18-12.25\\pick'
file_list = []
def find_file_to_work(total_dir_path,file_list):
total_list = os.listdir(total_dir_path)
print('该目录下的文件夹(包)总数为:{}'.format(len(total_list)))
print(total_dir_path)
for i in total_list:
print(i)
test_path = total_dir_path+'\\{}'.format(i)
condition = os.path.isfile(test_path)
print(condition)
if condition:
file_list.append(test_path)
print('文件写入成功!')
else:
dir_path = test_path
find_file_to_work(dir_path,file_list)
print(file_list)
print(len(file_list))
f_list =file_list
return f_list
async def write_excel_xls(read_path):# 通过async def定义的函数是原生的协程对象
# 拿出数据
write_path = 'C:\\Users\\Administrator\\Desktop\\xxx.xlsx'
r_book = xlrd.open_workbook(read_path)
# 获取sheet表的数据,return一个可迭代对象
sheets = r_book.sheet_by_index(0).get_rows()
# 获取要写入的工作表的总行数
r_book02 = xlrd.open_workbook(write_path)
row = r_book02.sheet_by_index(0).nrows
# 得到可写入的sheet对象w_sheet
w_book02 = copy.copy(r_book02)
w_sheet02 = w_book02.get_sheet(0) # w_sheet = w_book.sheets()[0]
i = 0
for k in sheets:
# 在指定 行列 写入数据
print(k)
w_sheet02.write(row + i, 0, k[0].value) # 像表格中写入数据(对应的行和列)
w_sheet02.write(row + i, 1, k[1].value) # 像表格中写入数据(对应的行和列)
w_sheet02.write(row + i, 2, k[2].value) # 像表格中写入数据(对应的行和列)
i += 1
w_book02.save(write_path) # 保存工作簿
print('写入{}条数据成功!'.format(i))
async def main():
start = time.time()
await asyncio.wait([
write_excel_xls(i) for i in find_file_to_work(total_dir_path,file_list)])
end = time.time()
print("Complete in {} seconds".format(end - start))
loop = asyncio.get_event_loop()
loop.run_until_complete(main())
但是我们可以换个角度,逐层优化。
这样逐层优化,比如共有200个文件,你可以20个一组,这样就分出10份,然后这10份再合并到总的数据表中,那么这第一层的耗费时间为max_time1,第二层的耗费时间为max_time2,因为异步的原理,实际执行过程并不会去等一层完成了再完成下一层,但是我们可以估计出最大的耗费时间为total_time = max_time1+max_time2
从一定程度上来看,还是得到了很大的优化,按这样的分法,大概提速了近6.6倍时间。当然分的方案可以自己写逻辑代码。
设计了好久。。跑出来的数据还是有问题,不知道哪里出错了T^T
下次有空了再回过头来补充好了,脑壳疼。。