数据准备: sql文件太大,导入太慢,本文绕过mysql数据库导入导出,直接通过python切分sql,并将数据表结构和数据表数据文件分别存储到相应的sql文件和csv文件,供pandas数据分析用。
数据预处理: pandas处理整列数据太慢,用多线程处理,写入临时文件,在读取排序后生成最终的分析数据
一、数据准备: sql文件切割转存csv文件
mysql文件太大,导入太慢,本文绕过mysql数据库导入导出,直接将sql文件转成对应表的csv文件。
python切分sql,并将数据表结构和数据表数据文件分别存储到相应的sql文件和csv文件,供pandas数据分析用。
本文实验数据,mysqldump导出的sql文件大小5G,
head -100 sql文件
> tmp.sql
windows 我装的git,所以在git bash终端下可以使用head命令
本操作是通过mysqldump导出的数据文件,内容为表结构和数据
几处标识:
Table structure for table `test1`
Dumping data for table `test1`
INSERT INTO `test1` VALUES
sqlfile = '111.sql'
# sql文件路径
base_path = Path('D:/pd-data/test/')
find_tpl_structure = '-- Table structure for table '
find_tpl_structure_len = len(find_tpl_structure)
find_tpl_data = '-- Dumping data for table '
find_tpl_data_len = len('-- Dumping data for table ')
curflag = None # 当前是start1 start2
curtable = '' # table name
curtype = '' # structure or data
curcontent = [] # 存储的内容
time_s = time.time()
# 写入文件 structure存sql, data存csv
def save_file(table, ftype, data):
types = {'structure': '.sql', 'data': '.csv'}
if table != '' and type != '' and table != []:
nfile = base_path.joinpath('csv/{}_{}{}'.format(curtable, curtype, types[ftype]))
if ftype == 'data':
with open(nfile, 'a', newline='') as fs:
ff = csv.writer(fs)
ff.writerows(data)
else:
with open(nfile, 'w+', encoding='utf-8') as fs:
fs.writelines(data)
print('{} ok'.format(nfile))
with open(base_path.joinpath(sqlfile), 'r', encoding='utf-8') as f:
for i, line in enumerate(f):
# 标识启动时才可存储内容
if curflag == 'start2' or curflag == 'start1':
if curflag == 'start2':
if line.startswith('INSERT INTO '):
x = eval('[{}]'.format(line.strip()[22 + len(curtable):-1]))
total += len(x)
# curcontent.extend(x)
save_file(curtable, curtype, x)
print(total)
else:
curcontent.append(line)
# 表结构 开始位置: 保存数据文件,开启下一个表结构
if line.startswith(find_tpl_structure):
# 表数据结束
# save_file(curtable, curtype, curcontent)
curcontent = []
# 表结构开始
curflag = 'start1'
curtype = 'structure'
curtable = line.strip()[find_tpl_structure_len + 1:-1]
# 表数据 开始位置: 保存结构文件,开启下一个表数据
if line.startswith(find_tpl_data):
# 表结构结束
save_file(curtable, curtype, curcontent)
curcontent = []
# 表数据开始
curflag = 'start2'
curtype = 'data'
total = 0
curtable = line.strip()[find_tpl_data_len + 1:-1]
time_e = time.time()
print('runtime - {}s'.format(time_e - time_s))
二、数据预处理
data = pd.read_csv(
p.joinpath('deal_all.csv'),
header=0,
names=['id','name','addtime','dtype'],
)
df = data[data['addtime'].dt.year.isin([2016, 2017, 2018]) & ~data['dtype'].isin([0,2,3])]
df.to_csv(
p.joinpath('deal_2016_2017_2018.csv'),
index=False,
header=False,
)
import numpy as np
import pandas as pd
from concurrent.futures import ProcessPoolExecutor
# 自定义转换函数
def timestampTostr(x):
return pd.to_datetime(x, unit='s', utc=False).tz_localize('Asia/Shanghai')
# 处理数据
def worker(chunk):
chunk['addtime'] = chunk['addtime'].apply(timestampTostr)
return chunk
# 写入csv文件
def writecsv(r):
global total
total += r.result().shape[0]
print('Total:', total)
r.result().to_csv(
p.joinpath('deal_2016_2017_2018.tmp.csv'),
index=False,
header=False,
mode='a' # 追加模式
)
if __name__ == '__main__':
# 加载数据
data = pd.read_csv(
p.joinpath('deal_2016_2017_2018.csv'),
header=0,
names=['id','name','addtime','dtype'],
iterator=True,
chunksize=5000,
# nrows=1000000,
low_memory=False,
# 数据量小的时候可以使用,大数据加载特别慢
# converters={
# 'addtime': timestampTostr,
#}
)
futures = []
total = 0
with ProcessPoolExecutor(max_workers=50) as executer:
for chunk in deal:
future = executer.submit(worker, chunk)
future.add_done_callback(writecsv)
print('end~~~~~~~~~~~~~~~~~~~~')
deal = pd.read_csv(
p.joinpath('deal_2016_2017_2018.csv'),
header=0,
names=['id','name','addtime','dtype'],
low_memory=False,
)
deal.sort_values('did', inplace=True)
deal.to_csv(
p.joinpath('deal_2016_2017_2018_end.csv'),
index=False,
header=False,
)
至此数据预处理已完成,后续我们就可以做数据分析及生成报表了。