Python获取Hive数据计算相关性系数

需求:

1.从hive 表中获取数据。

2.计算各个指标与主分析指标间的相关系数。

3.将计算出来的相关系数,放入csv 文件,待使用。

首先,相关系数我们选择了皮尔逊相关系数,python的实现也是从网上直接找到的。

然后确定获取hive 数据的方式。公司环境没有pyspark,排除了用spark 操作hive 的方法。就想套用值之前脚本使用的,用impala 连接hive 的获取方法。结果基本开发完成,发现,一个是由于sql 数据量比较大,耗时比较长,导致总是自动断开连接,以至于跑不完程序。还有一个,由于其中的一个指标计算需要用到udf 函数,添加jar 包时,使用impala 的方式总是无法识别路径。后来认为应该是这种方式只能支持查询,无法支持这种添加临时函数的操作,没办法放弃了这一条路。

最后呢是选择了直接打开hive 的简单粗暴的模式:
os.popen("""hive -S -e '{}' """.format(sql))

ok 下面贴上我的代码,由于我是刚开始在工作中使用python,正在学习,肯定有很多不足的地方,如果能得到各位指点一二,那我真是非常感谢,不管是思路上的,还是代码上的,都希望大家不吝赐教。

#!/usr/bin/env python
# -*- coding: utf-8 -*-
import datetime
import os
import sys
import pandas as pd
from math import sqrt
from operator import itemgetter, attrgetter
#执行hivesql,os.popen() 方法用于从一个命令打开一个管道,对于我来说正好是需要sql 的一行结果作为一个整体,刚好放到一个list 中。

#输出到指定日志文件
logging.basicConfig(level=logging.INFO,
                    filename='....../cor_coe.log',
                    filemode='a',
                    format='%(asctime)s %(filename)s %(levelname)s %(message)s',
                    datefmt='[%Y-%m-%d %H:%M:%S]'
                    )

def getHiveResult(sql):
    output = os.popen("""hive -S -e '{}' """.format(sql))
    result = output.readlines()
    #形式:['字段名称\t字段名称','[第一行结果\t分隔]','[第二行结果\t分隔]'....]
    return result

#这里是因为上面的result 这个list,每个元素的最后都加上了一个\n,我要把它去掉。
def trans_list(str):
    return str.replace('\n','')

# 将'[...]' 这个字符串,转换成一个list. 
def str2list(str):
    list1 = str.split(',')
    list1[0] = list1[0].replace('[','')
    list1[-1] = list1[-1].replace(']','')
    return [float(x) for x in list1]
#皮尔逊相关系数公式:x,y 两个变量的  协方差 / 标准差的乘积
# 乘积之和函数
def multipl(a,b):

    sumofab=0.0
    for i in range(len(a)):
        temp=a[i]*b[i]
        sumofab+=temp
    return sumofab

# 皮尔逊相关系数函数
def corrcoef(x,y):
    n=len(x)
    #求和
    sum1=sum(x)
    sum2=sum(y)

    #求乘积之和
    sumofxy=multipl(x,y)

    #求平方和
    sumofx2 = sum([pow(i,2) for i in x])
    sumofy2 = sum([pow(j,2) for j in y])

    # 协方差  乘积之和 - 和的乘积
    num=sumofxy-(float(sum1)*float(sum2)/n)
    
    #标准差 * 标准差
    den=sqrt((sumofx2-float(sum1**2)/n)*(sumofy2-float(sum2**2)/n))

    return num/den
sql 就忽略了。sql 最终的结果形式是:
南京 [11,13,10.3,12.5..........]  这是一行记录,只有两个字段。
if __name__ == "__main__":
    process_start = datetime.datetime.now()
    logging.info("程序开始时间:" + str(process_start))

    # 获取脚本外的日期参数,并添加连接符
    ymd=sys.argv[1]
    y_m_d="-".join((ymd[0:4],ymd[4:6],ymd[6:8]))

    sql1 = sql1.format(DT=y_m_d)

    try:
        result = getHiveResult(sql1)
    except Exception as e:
        logging.info("调用getHiveResult()函数报错:" + traceback.format_exc())

    list_result_name = ['','name1','name2','name3','name4']

    list_result1 = result[1:]

    list_result2 = []

    list_result3 = []

    for el1 in  list_result1:
        list_result2.append(trans_list(el1)) 

    for el2 in list_result2:
        list_tmp = []
        list_tmp = el2.split('\t')

        for el3 in list_tmp:
            num = list_tmp.index(el3)
            if num >=2:
                try:
                    list_result3.append(( list_tmp[0],list_result_name[1]+"_"+list_result_name[num], round(corrcoef(str2list(list_tmp[1]),str2list(el3)),4) ))
                except Exception as e:
                    logging.info("计算皮尔逊相关系数报错:" + traceback.format_exc())

    #突然觉得python 的排序功能还挺强大的。在对我list 中的元祖排序
    list_result3 = sorted(list_result3,key=itemgetter(0,2),reverse=True)
    try:
        df = pd.DataFrame(list_result3)
    except Exception as e:
        logging.info("list_result3转化成 df 时报错:" + traceback.format_exc())

    outputpath = 'path/cor_coe_'+ymd+'.csv' 
    
    try:
        df.to_csv(outputpath,index=False,sep=',',header=['城市','相关因子','相关系数'])
    except Exception as e:
        logging.info("输出到 csv 文件报错:" + traceback.format_exc())


    print ('process_end:',datetime.datetime.now())

现在我还有一个瓶颈,就是sql 跑的太慢了,有十个sql,每个sql 涉及到的表都在千万到亿条数据左右,总共的时间需要22min左右,脚本的总时间是25min左右。已经尝试设置了很多hive 所谓的优化参数,除了合并小文件,提升了将近4分钟的速度之外,其他的调整都没有什么效果。而且从执行过程来看,并没有明显的数据倾斜,就是map 和 reduce 的过程就比较慢。如果后期找到方法之后我还会追加进来。也希望看到这篇文章的朋友能提一些宝贵的意见。

你可能感兴趣的:(Python获取Hive数据计算相关性系数)