分享

Pandas100秒处理一亿行数据

 hdzgx 2019-12-27
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 秒


#########################

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多