记sql大文件切割转存及pandas数据预处理

数据准备: sql文件太大,导入太慢,本文绕过mysql数据库导入导出,直接通过python切分sql,并将数据表结构和数据表数据文件分别存储到相应的sql文件和csv文件,供pandas数据分析用。

数据预处理: pandas处理整列数据太慢,用多线程处理,写入临时文件,在读取排序后生成最终的分析数据

一、数据准备: sql文件切割转存csv文件

mysql文件太大,导入太慢,本文绕过mysql数据库导入导出,直接将sql文件转成对应表的csv文件。

python切分sql,并将数据表结构和数据表数据文件分别存储到相应的sql文件和csv文件,供pandas数据分析用。

本文实验数据,mysqldump导出的sql文件大小5G,

  • head 提取前N行数据,编写提取规则。

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,
)
  • addtime是时间戳字段,需要转换成datetime时间, 1000w数据比较耗时间,大部分都是计算,所以采用异步多进程处理,速度显著提升
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~~~~~~~~~~~~~~~~~~~~')
  • 通过id排序
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,
)

至此数据预处理已完成,后续我们就可以做数据分析及生成报表了。

你可能感兴趣的:(数据分析,数据分析,python,sql)