Python数据处理心得--Pandas100秒处理一亿行数据 1. 背景-为啥要用pandas 公司的日常运营数据通过大数据平台(HIVE SQL)通过汇总后,推送给业务部门进行日常分析的数据仍然非常大。从数据量从PB&TB级降到了GB级,一般主要通过Mysql进行存储&聚合分析。 日或周的数据,mysql处理还是可以的。到月数据,超过10GB(1亿行),处理起来就开始吃力,数据吞吐特别慢,内存资源占用特别严重。 使用Pandas后,普通笔记本电脑可以很轻松地处理1亿行的数据,100秒内就能完成计算, 计算实现的成本非常低。 2. Pandas介绍 很多方法可以解决这个问题,由于希望用单机版的开源软件,正好python日常用的也比较多,于是使用pandas来解决这个问题。 pandas是numpy的基础发展出来的, pandas的DataFrame数据结构相当于多个numpy series组合在一起。 为了更直观地了解pandas,打算通过一个模拟数据的分析过程来介绍pandas的用法。 使用软件的版本 anaconda3-4.1.1 (Python 3.5) Jupiter notebook (4.2.1) Pandas包 0.18.1 (anaconda自带的) 3. 生产模拟数据 我们先模拟一个一亿行的数据,然后测试用pandas的代码进行汇总分析,并且记录耗时&及内存&CUP的大致占用情况。 基本需要把数据切成小块处理,否则内存占用会特别高,内存不足,python无法运行下去。 如果电脑有32GB内存的,可以直接抽取1亿行样本数据,不用使用循环进行数据重复,这样的内存消耗是25GB。 如果用下面的循环,内存占用只有几百MB。 ############################################################################ import pandas as pd import numpy as np import csv date= ['2017-11-01', '2017-11-02','2017-11-03','2017-11-04','2017-11-05','2017-11-06','2017-11-07'] #设置日期数据,为后面的np.random.choice引用 area= ['华北', '华东', '华南','西南','华中','东北','西北'] order_type =[0, 1, 2, 3, 4 ,5 ,6 ,7 ,8, 9] col1=np.random.choice(date, 1000000, p=[0.15, 0.15, 0.15, 0.15, 0.15, 0.15, 0.1]) #随机抽样100万次,各个日常出现的概率是P。 col2=np.random.choice(area, 1000000, p=[0.2, 0.2, 0.2, 0.1, 0.1, 0.1, 0.1]) col3=np.random.choice(order_type, 1000000, p=[0.05, 0.2, 0.2, 0.1, 0.1, 0.1, 0.1, 0.05, 0.05, 0.05]) col4=np.random.choice(100, 1000000) col5=np.random.choice(10000, 1000000) df = pd.DataFrame({'date':col1, 'area':col2, 'order_type':col3, 'qty':col4, 'revenue':col5}) df=df.set_index('date') #合并各个numpy生产的随机数据成为Pandas的DataFrame with open('E:\\mess_files\\sample_data.csv','w', newline='\n') as csvfile: writer = csv.writer(csvfile) #先写入columns_name writer.writerow(['date','area','order_type','qty','revenue']) #为了减少内存占用,没有直接在上面生成1亿行数据,先生产100万,然后循环100次。 for i in range(100): i=i+1 df.to_csv ('E:\\mess_files\\sample_data.csv', encoding='gbk', header=False, mode='a') print(i*1000000) ############################################################################ 4. 数据分析代码 涉及的功能:读取数据,增加计算字段,group by ,merge( left join), index (set & reset), 输出数据(CSV & excel)。 ############################################################################ import pandas as pd import time import csv start = time.clock() #开始计时 with open('E:\\mess_files\\pd_sum.csv','w', newline='\n') as csvfile: writer = csv.writer(csvfile) #先写入columns_name writer.writerow(['date','area','order_type','qty','revenue']) #为汇总的输出,建立一个CSV文件,并包含表头字段明。 #分块(每100万行)进行数据汇总, 并循环写入csv中 reader = pd.read_csv('E:\\mess_files\\sample_data.csv', encoding='gbk',sep=',',iterator=True) i=0 while True: try: start2 = time.clock() #每次循环开始时间 # 从csv文件迭代读取 df = reader.get_chunk(1000000) mini_sum=df.groupby(['date','area','order_type']).sum() #按date, area, order_type 进行汇总 mini_sum.to_csv('E:\\mess_files\\pd_sum.csv',mode='a',header=False) #汇总结果写入CSV文件,'header=False' 避免重复写入表头。 # 计时 i=i+1 end2 = time.clock() #每次循环结束时间 print('{} 秒: completed {} rows'.format(end2 - start2, i * 1000000)) except StopIteration: print("Iteration is stopped.") #循环结束退出 break df=pd.read_csv('E:\\mess_files\\pd_sum.csv', encoding='gbk',sep=',') df=df.groupby(['date','area','order_type']).sum() df=df.reset_index() #pandas汇总时,会根据groupby的字段建立multi_index, 需要重置index。 df['date']=pd.to_datetime(df['date']) #将date列 设置为日期类型 df['avg']=df['revenue']/df['qty'] #增加一个计算字段 avg 平均客单价 df_sub=df[['date','area','qty']].groupby(['date','area']).sum().add_prefix('sum_') #建立一个新DataFrame, 用于后面的left join 计算各个order_type的占比 df_merge=pd.merge(df, df_sub, how='outer', left_on=['date','area'], right_index=True) #相当于SQL的left join df_merge['type_qty%']=df_merge['qty']/df_merge['sum_qty'] #增加计算字段 df_merge=df_merge.set_index('date') output=pd.ExcelWriter('E:\\mess_files\\output_xls.xlsx') df_merge.to_excel(output,'sheet1') output.save() #最终结果输出到excel end = time.clock() #最终使用时间计时 print('final{} 秒'.format(end - start)) ############################################################################### 使用了两台机器进行数据运算,DELL R720 2U SAS硬盘 96GB内存的服务器,Thinkpad E450 SSD硬盘 i5 8G内存的笔记本电脑。 运行时,CUP占用率服务器5%,笔记本30%, 总内存占用都是约6GB,耗时也非常接近, 每处理100万行用时在 1秒种以内, 处理1亿行数据的运算还是很轻松的。 服务器循环每次计算100万行用时 0.8秒, 总用时79.3秒。 ######################## 0.789916201370346 秒: completed 90000000 rows 0.7889745154019323 秒: completed 91000000 rows 0.7875460356832349 秒: completed 92000000 rows 0.7883160047623932 秒: completed 93000000 rows 0.7929830807664189 秒: completed 94000000 rows 0.7884885093438072 秒: completed 95000000 rows 0.8129294153000615 秒: completed 96000000 rows 0.8298620396579395 秒: completed 97000000 rows 0.787222294208533 秒: completed 98000000 rows 0.7879615432937328 秒: completed 99000000 rows 0.7891974322811279 秒: completed 100000000 rows Iteration is stopped. final79.22691993069884 秒 ######################### 笔记本电脑循环每次计算100万行用时 0.83, 总用时85.1秒。 ######################### 0.817601222058812 秒: completed 92000000 rows 0.8092709856398557 秒: completed 93000000 rows 0.8277913177203118 秒: completed 94000000 rows 0.8203788228361191 秒: completed 95000000 rows 0.8211909342874009 秒: completed 96000000 rows 0.8238487924599838 秒: completed 97000000 rows 0.825806156394961 秒: completed 98000000 rows 0.8143844225134984 秒: completed 99000000 rows 0.8465947555305036 秒: completed 100000000 rows Iteration is stopped. final85.11640178604648 秒 ######################### |
|