python 实现对 同比、环比、占比、贡献率、拉动率 、移动均值 等的计算(附详细代码和样例)


一、概念解释

1.1 同比

同比增长计算公式:
同 比 增 长 率 = ( 本 期 数 - 同 期 数 ) ÷ 同 期 数 × 100 同比增长率=(本期数-同期数)÷同期数×100% =÷×100

例子:
比如说去年3月的产值100万,本年3月的产值300万,同比增长是怎么算的?是同比增长200%?还是同比增长300%?
本题中,同比增长率=(300-100)÷100=200%

同比增长率,一般是指和同期相比较的增长率。
某个指标的同比增长=(某个指标的值-同期这个指标的值)/同期这个指标的值
当同期数为负值的情况,公式应当完善如下:
同 比 增 长 率 = ( 本 期 数 - 同 期 数 ) ÷ ∣ 同 期 数 ∣ × 100 同比增长率=(本期数-同期数)÷ |同期数|×100% =÷×100

同比增长率=(50W-(-100W))/|-100W||×100%=150%

1.2 环比

环比计算公式:
环 比 增 长 率 = ( 本 期 数 − 上 期 数 ) / 上 期 数 × 100 环比增长率=(本期数-上期数)/上期数×100% =/×100

环比,表示连续2个统计周期(比如连续两月)内的量的变化比。
反映本期比上期增长了多少。”补充:

环比有 环比增长速度环比发展速度 两种方法。
环比即与上期的数量作比较。

  1. 环比增长速度=(本期数-上期数)÷上期数×100%
    反映本期比上期增长了多少。
  2. 环比发展速度=本期数÷上期数×100%
    环比发展速度是报告期水平与前一期水平之比,反映现象在前后两期的发展变化情况

例如:
如:本期销售额为500万,上期销售额为350万。
环比增长速度=(500-350)÷350×100%=42.86%
环比发展速度=500÷350×100%=142.86%
环比增长速度= 环比发展速度-1。

1.3 占比

占比计算公式:
占 比 = 所 求 占 比 例 数 值 ÷ 总 数 值 × 100 占比 = 所求占比例数值 ÷ 总数值×100% =÷×100

例如:
一部门总人数为250个,缺勤人数为8个,缺勤率是8/250=0.032。

占比是一个总体中各个部分的数量占总体数量的比重,用于反映总体的构成或者结构。

1.4 贡献率

贡献率计算公式:
贡 献 率 = 某 因 素 增 加 量 ( 增 量 或 增 长 程 度 ) / 总 增 加 量 ( 总 增 量 或 增 长 程 度 ) × 100 贡献率=某因素增加量(增量或增长程度)/总增加量(总增量或增长程度)×100% =/×100

上式实际上是指某因素的增长量(程度)占总增长量(程度)的比重。
贡献率常用于分析经济增长中各因素作用大小的程度。

例如:
2009年广东省生产总值39081.59亿元,比上年增长9.5%。其中,第一产业产值2006.02亿元,增长4.9%;第二产业产值19270.48亿元,增长8.7%;第三产业产值17805.09亿元,增长11.0%。那么三大产业对广东省GDP的贡献率是多少?
广东省GDP增长总额=39081.59-39081.59/(1+9.5%)=3390.05(亿元)
第一产业增长总额=2006.02-2006.02/(1+4.9%)=93.70(亿元),贡献率=93.70/3390.05=2.76%
第二产业增长总额=19270-19270/(1+8.7%)=1542.31(亿元),贡献率=1542.31/3390.05=45.50%
第三产业增长总额=17805.09-17805/(1+11.0%)=1764.46(亿元),贡献率=1764.46/3390.05=52.05%

1.5 拉动率

拉动率计算公式:
拉 动 增 长 率 = ( 某 值 今 年 量 − 某 值 去 年 量 ) / 总 值 的 去 年 量 ∗ 100 拉动增长率=(某值今年量-某值去年量) / 总值的去年量*100% =/100

拉动率 指现期某部分的增加值/总体的基期值,即部分量的增长对总量增长的一个贡献。

例如:
全省重工业今年产值=4935
全省重工业去年产值=3993
全省重工业较去年的增长=4935-3993=942
全省今年总产值=7334 亿元
全省去年总产值=6021 亿元
全省较去年去年总产值增长 = 7334 - 6021
重工业:

  1. 拉动率 =全省重工业较去年的增长 / 全省去年总产值 *100%
  2. 贡献率 = 全省重工业较去年的增长 / 全省较去年去年总产值增长 * 100%

二、python实现

2.1 同比实现

因为 同比 和 环比 的计算,都是对一个指标数据本身的计算,因此可以用同一个函数来实现。

备注:
类似的,同比 也存在这种环比补充说明的情况,本文均以 增长速度 进行 计算实现。

# 同比计算函数
def yearOnYear(temp_data,zhibiao_freq):
    '''
    temp_data,要计算的原始数据序列
    zhibiao_freq,指标更新频率
    '''
    result = [] # 存放计算结果(嵌套列表)
    
    # 判断指标的加工周期
    if zhibiao_freq == '年':
        rel_delta = relativedelta(years=1)
    if zhibiao_freq == '季': 
        rel_delta = relativedelta(months=3)
    if zhibiao_freq == '月':
        rel_delta = relativedelta(months=1)

    # 起止日期时间
    min_riqi = min(temp_data.index)
    max_riqi = max(temp_data.index)

    # 对范围内日期数据进行同比加工计算,单位(%)
    flag_riqi = min_riqi

    tongbi_delta = relativedelta(years=1)
    # 同比计算
    while flag_riqi <= max_riqi-tongbi_delta:
        temp_riqi = flag_riqi+tongbi_delta
        # 当期值
        try:
            dangqi = float(temp_data.loc[temp_riqi])
        except:
            dangqi = None

        # 上期值
        try:
            shangqi =float( temp_data.loc[flag_riqi])
        except:
            shangqi = None

        if dangqi and shangqi:
            value = format((dangqi - shangqi)/ abs(shangqi) *100,'.2f')
        else:
            value = None
        result.append([temp_riqi,value]) # 指标结果
        flag_riqi = flag_riqi+rel_delta # 更新日期
            
    result = pd.DataFrame(result,columns=['日期','指标值'])  
    result = result.set_index('日期')
    return result

2.2 环比实现

# 环比计算函数
def monthOnMonth(temp_data,zhibiao_freq):
 '''
 temp_data,要计算的原始数据序列
 zhibiao_freq,指标更新频率
 '''
 result = [] # 存放计算结果(嵌套列表)
 
 # 判断指标的加工周期
 if zhibiao_freq == '年':
     rel_delta = relativedelta(years=1)
 if zhibiao_freq == '季': 
     rel_delta = relativedelta(months=3)
 if zhibiao_freq == '月':
     rel_delta = relativedelta(months=1)

 # 起止日期时间
 min_riqi = min(temp_data.index)
 max_riqi = max(temp_data.index)

 # 对范围内日期数据进行同比加工计算,单位(%)
 flag_riqi = min_riqi
 
 # 环比计算
 while flag_riqi < max_riqi:
     temp_riqi = flag_riqi+rel_delta
     # 当期值
     try:
         dangqi = temp_data.loc[temp_riqi]
     except:
         dangqi = None

     # 上期值
     try:
         shangqi = temp_data.loc[flag_riqi]
     except:
         shangqi = None

     if dangqi and shangqi:
         value = format(str((dangqi - shangqi)/ abs(shangqi)) *100,'.2f')
     else:
         value = None
     result.append([temp_riqi,value]) # 指标结果
     
     flag_riqi = flag_riqi+rel_delta # 更新日期
         
 result = pd.DataFrame(result,columns=['日期','指标值'])   
 result = result.set_index('日期')
 return result

2.3 累计值 获得 当期值

# 当期值函数
def currentPeriod(temp_data,zhibiao_freq):
    '''
    temp_data,要计算的原始数据序列
    zhibiao_freq,指标更新频率
    '''
    result = [] # 存放计算结果(嵌套列表)
    # 判断指标的加工周期
    if zhibiao_freq == '年':
        rel_delta = relativedelta(years=1)
    if zhibiao_freq == '季': 
        rel_delta = relativedelta(months=3)
    if zhibiao_freq == '月':
        rel_delta = relativedelta(months=1)

    # 起止日期时间
    min_riqi = min(temp_data.index)
    max_riqi = max(temp_data.index)

    # 对范围内日期数据进行同比加工计算,单位(%)
    flag_riqi = min_riqi
    while flag_riqi < max_riqi:
        temp_riqi = flag_riqi+rel_delta
        # 当期值
        try:
            # dangqi = temp_data['index_val'][temp_riqi]
            dangqi = float(temp_data.loc[temp_riqi])
        except:
            dangqi = None

        # 上期值
        try:
            # shangqi = temp_data['index_val'][flag_riqi]
            shangqi = float(temp_data.loc[flag_riqi])
        except:
            shangqi = None
                
        if (temp_riqi.month)==1 and dangqi:
            value = format(dangqi,'.2f')
                
        elif dangqi and shangqi:
                
            value = format((dangqi - shangqi),'.2f')
        else:
            value = None
        #result.append([temp_riqi,zhibiao_code,yuanxing_name,value,zhibiao_freq]) # 指标结果
        result.append([temp_riqi,value]) # 指标结果
        flag_riqi = temp_riqi # 更新日期
    result = pd.DataFrame(result,columns=['日期','指标值'])   
    result = result.set_index('日期')
    return result

2.4 当期值 计算 累计值

# 当月值计算月度累计值,季度值计算季度累计值(季度累计值暂时未编码)
def monthToMonthAddUp(temp_data,zhibiao_freq):
  '''
  temp_data,要计算的原始数据序列
  zhibiao_freq,指标更新频率
  '''
  result = temp_data.copy()
  
  # 判断指标的加工周期
  if zhibiao_freq == '年':
      rel_delta = relativedelta(years=1)
  if zhibiao_freq == '季': 
      rel_delta = relativedelta(months=3)
  if zhibiao_freq == '月':
      rel_delta = relativedelta(months=1)
      
  min_riqi = min(temp_data.index)
  max_riqi = max(temp_data.index)
  
  # num = 0 # 数据加工对应的位置
  for year in range(min_riqi.year,max_riqi.year+1):
      temp = temp_data.loc[str(year)]
      count = 0 # 判断月份数据是否匹配和完整标志
      if zhibiao_freq == "月":
          for y in temp.index:
              if y.month != count+1 or any(temp.loc[y].isnull()) :
                  print('缺失的时间数据:',y)
                  temp.iloc[count:max(temp.index).month] = None
                  break
              else:
                  temp.iloc[count] = round(sum(temp.iloc[:y.month]),2)
              count += 1
          result.loc[str(year)] = temp
      if zhibiao_freq == "季":
          print("请进行程序设计!")
          
  result = pd.DataFrame(result)
  result.columns = ['指标值']
  result.index.name = '日期'
  return result
···

### 2.5 移动均值
```python
# 移动均值 函数
def moveAverage(temp_data,zhibiao_freq,move_num):
  '''
  temp_data,序列
  zhibiao_freq,指标加工频率
  move_num,移动均值计算的期数
  '''
  move_num = move_num -1
  result =[]  # 存放计算结果(嵌套列表)
  # 判断指标的加工周期
  if zhibiao_freq == '年':
      rel_delta_move = relativedelta(years=move_num)
      rel_delta = relativedelta(years=1)
  if zhibiao_freq == '季': 
      rel_delta_move = relativedelta(months=3*move_num)
      rel_delta = relativedelta(months=3)
  if zhibiao_freq == '月':
      rel_delta_move = relativedelta(months=move_num)
      rel_delta = relativedelta(months=1)
      
  # 起止日期时间
  min_riqi = min(temp_data.index)
  max_riqi = max(temp_data.index)

  # 对范围内日期数据进行移动均值计算
  flag_riqi = min_riqi 
  flag_que = False # 是否确实数据,默认False
  while flag_riqi <= max_riqi-rel_delta_move:
      temp_riqi = flag_riqi + rel_delta_move
      temp = temp_data.loc[flag_riqi:temp_riqi]
      if any(temp.isnull()) or len(temp) != move_num+1:
          flag_que = True # 存在确实数据
          #print("日期段存在缺失数据",flag_riqi,temp_riqi)
          result.append([temp_riqi,None])
      else:
          fenzi_list = [float(i) for i in temp]
          result.append([temp_riqi,round(sum(fenzi_list)/move_num,2)])
      flag_riqi += rel_delta
  if flag_que:
      print("指标存在缺失数据")
  result = pd.DataFrame(result,columns = ["日期","指标值"])
  result = result.set_index('日期')
  return result

2.6 月度累计值 计算 当季值

# 月度累计值 计算 当季值
def monthaddupToSeason(temp_data):
    '''
    temp_data,要计算的原始数据序列
    '''
    result = [] # 存放加工处理结果
    
    min_riqi = min(temp_data.index)
    max_riqi = max(temp_data.index)
    
    rel_delta = relativedelta(months=3) # 日期间隔
    
    # 开始标记日期进行设定
    while min_riqi.month not in [3,6,9,12]:
        min_riqi = min_riqi + relativedelta(months=1)
        
    # 对范围内日期数据进行处理
    flag_riqi = min_riqi
    while flag_riqi < max_riqi:
        temp_riqi = flag_riqi+rel_delta
        # 当期值
        try:
            # dangqi = temp_data['index_val'][temp_riqi]
            dangqi = float(temp_data.loc[temp_riqi])
        except:
            dangqi = None

        # 上期值
        try:
            # shangqi = temp_data['index_val'][flag_riqi]
            shangqi = float(temp_data.loc[flag_riqi])
        except:
            shangqi = None
            
        if (temp_riqi.month)==3 and dangqi:
            value = format(dangqi,'.2f')
                
        elif dangqi and shangqi:
            value = format((dangqi - shangqi),'.2f')
        else:
            value = None
        result.append([temp_riqi-relativedelta(months=2),value]) # 指标结果
        flag_riqi = temp_riqi # 更新日期
        
    result = pd.DataFrame(result,columns=['日期','指标值'])
    result = result.set_index('日期') 
    return result

2.7 贡献率

因为 占比、贡献率、拉动率 的计算,都是对两个指标数据本身的计算,因此可以用同一个函数来实现。

备注:
这里 贡献率拉动率 的计算以 同比贡献率同比拉动率 进行计算实现;
还有 环比贡献率 和 环比拉动率 一说。不过实现同理啦。

# 贡献率计算函数
def contributionRate(temp_data_fenzi,temp_data_fenmu,zhibiao_freq):
    '''
    temp_data_fenzi,要计算的原始数据序列
    temp_data_fenmu,要计算的原始数据序列
    zhibiao_freq,指标更新频率
    '''
    result = [] # 存放计算结果(嵌套列表)
    
    # 判断指标的加工周期
    if zhibiao_freq == '年':
        rel_delta = relativedelta(years=1)
    if zhibiao_freq == '季': 
        rel_delta = relativedelta(months=3)
    if zhibiao_freq == '月':
        rel_delta = relativedelta(months=1)

    # 起止日期时间
    min_riqi = min(temp_data_fenmu.index)
    max_riqi = max(temp_data_fenmu.index)

    # 对范围内日期数据进行占比加工计算,单位(%)
    flag_riqi = min_riqi
    
    tongbi_delta = relativedelta(years=1)
    while flag_riqi <= max_riqi-tongbi_delta:
        temp_riqi = flag_riqi+tongbi_delta
                
        # 分子增量值计算
        # 当期值
        try:
            fenzi_dangqi = float(temp_data_fenzi.loc[temp_riqi])
        except:
            fenzi_dangqi = None
        # 上期值
        try:
            fenzi_shangqi = float(temp_data_fenzi.loc[flag_riqi])
        except:
            fenzi_shangqi = None
        # 分子增量结果
        if fenzi_dangqi and fenzi_shangqi:
            fenzi = format(fenzi_dangqi - fenzi_shangqi,'.2f')
        else:
            fenzi = None
            
        # 分母值增量值计算 
        # 当期值
        try:
            fenmu_dangqi = float(temp_data_fenmu.loc[temp_riqi])
        except:
            fenmu_dangqi = None
        # 上期值
        try:
            fenmu_shangqi = float(temp_data_fenmu.loc[flag_riqi])
        except:
            fenmu_shangqi = None
        # 分母增量结果
        if fenmu_dangqi and fenmu_shangqi:
            fenmu = format(fenmu_dangqi - fenmu_shangqi,'.2f')
        else:
            fenmu = None
            
        # 结果值计算
        if fenzi and fenmu:
            value = format(float(fenzi)/ float(fenmu) *100,'.2f')
        else:
            value = None

        result.append([temp_riqi,value]) # 指标结果
        flag_riqi = flag_riqi + rel_delta # 更新日期
        
    result = pd.DataFrame(result,columns=['日期','指标值'])
    result = result.set_index('日期') 
    return result

2.8 拉动率

# 拉动率 计算函数
def pullRate(temp_data_fenzi,temp_data_fenmu,zhibiao_freq):
    '''
    temp_data_fenzi,要计算的原始数据序列
    temp_data_fenmu,要计算的原始数据序列
    zhibiao_freq,指标更新频率
    '''
    result = [] # 存放计算结果(嵌套列表)
    
    # 判断指标的加工周期
    if zhibiao_freq == '年':
        rel_delta = relativedelta(years=1)
    if zhibiao_freq == '季': 
        rel_delta = relativedelta(months=3)
    if zhibiao_freq == '月':
        rel_delta = relativedelta(months=1)

    # 起止日期时间
    min_riqi = min(temp_data_fenmu.index)
    max_riqi = max(temp_data_fenmu.index)

    # 对范围内日期数据进行占比加工计算,单位(%)
    flag_riqi = min_riqi
    
    tongbi_delta = relativedelta(years=1)
    while flag_riqi <= max_riqi-tongbi_delta:
        temp_riqi = flag_riqi+tongbi_delta
                
        # 分子增量值计算
        # 当期值
        try:
            fenzi_dangqi = float(temp_data_fenzi.loc[temp_riqi])
        except:
            fenzi_dangqi = None
        # 上期值
        try:
            fenzi_shangqi = float(temp_data_fenzi.loc[flag_riqi])
        except:
            fenzi_shangqi = None
        # 分子增量结果
        if fenzi_dangqi and fenzi_shangqi:
            fenzi = format(fenzi_dangqi - fenzi_shangqi,'.2f')
        else:
            fenzi = None
            
        # 分母值计算 
        try:
            fenmu = float(temp_data_fenmu.loc[flag_riqi])
        except:
            fenmu = None
                
        # 结果值计算
        if fenzi and fenmu:
            value = format(float(fenzi)/ float(fenmu) *100,'.2f')
        else:
            value = None

        result.append([temp_riqi,value]) # 指标结果
        flag_riqi = flag_riqi + rel_delta # 更新日期
        
    result = pd.DataFrame(result,columns=['日期','指标值'])
    result = result.set_index('日期') 
    return result

2.9 占比

# 占比 计算函数
def proportion(temp_data_fenzi,temp_data_fenmu,zhibiao_freq):
    '''
    temp_data_fenzi,要计算的原始数据序列
    temp_data_fenmu,要计算的原始数据序列
    zhibiao_freq,指标更新频率
    '''
    result = [] # 存放计算结果(嵌套列表)
    
    # 判断指标的加工周期
    if zhibiao_freq == '年':
        rel_delta = relativedelta(years=1)
    if zhibiao_freq == '季': 
        rel_delta = relativedelta(months=3)
    if zhibiao_freq == '月':
        rel_delta = relativedelta(months=1)

    # 起止日期时间
    min_riqi = min(temp_data_fenmu.index)
    max_riqi = max(temp_data_fenmu.index)
    
    flag_riqi = min_riqi
    while flag_riqi <= max_riqi:
        # 分子值 
        try:
            fenzi = float(temp_data_fenzi.loc[flag_riqi])
        except:
            fenzi = None
        # 分母值   
        try:
            fenmu = float(temp_data_fenmu.loc[flag_riqi])  
        except:
            fenmu = None

        # 结果值计算
        if fenzi and fenmu:
            value = format(fenzi/ fenmu *100,'.2f')
        else:
            value = None

        result.append([flag_riqi,value]) # 指标结果
        flag_riqi = flag_riqi+rel_delta # 更新日期
            
    result = pd.DataFrame(result,columns=['日期','指标值'])
    result = result.set_index('日期') 
    return result

2.10 同期差值

# 同期差值 计算函数
def samePeriodDiff(temp_data_fenzi,temp_data_fenmu,zhibiao_freq):
    '''
    temp_data_fenzi,要计算的原始数据序列
    temp_data_fenmu,要计算的原始数据序列
    zhibiao_freq,指标更新频率
    '''
    result = [] # 存放计算结果(嵌套列表)
    
    # 判断指标的加工周期
    if zhibiao_freq == '年':
        rel_delta = relativedelta(years=1)
    if zhibiao_freq == '季': 
        rel_delta = relativedelta(months=3)
    if zhibiao_freq == '月':
        rel_delta = relativedelta(months=1)

    # 起止日期时间
    min_riqi = min(temp_data_fenmu.index)
    max_riqi = max(temp_data_fenmu.index)
    
    flag_riqi = min_riqi
    while flag_riqi <= max_riqi:
        # 分子值
        try:
            fenzi = float(temp_data_fenzi.loc[flag_riqi])
        except:
            fenzi = None
        # 分母值   
        try:
            fenmu = float(temp_data_fenmu.loc[flag_riqi])
        except:
            fenmu = None

        # 结果值计算
        if fenzi and fenmu:
            value = format(fenzi- fenmu ,'.2f')
        else:
            value = None

        result.append([flag_riqi,value]) # 指标结果
        flag_riqi = flag_riqi+rel_delta # 更新日期
        
    result = pd.DataFrame(result,columns=['日期','指标值'])
    result = result.set_index('日期') 
    return result

2.11 月度/季度数据 在 一年中的均值

# 月度/季度数据 在 一年中的均值 计算函数
def monthInYearMean(temp_data,zhibiao_freq):
    '''
    temp_data,要计算的原始数据序列
    zhibiao_freq,指标更新频率
    '''
    result = temp_data.copy()
    
    min_riqi = min(temp_data.index)
    max_riqi = max(temp_data.index)
    
    for year in range(min_riqi.year,max_riqi.year+1):
        temp = temp_data.loc[str(year)]
        temp = temp.iloc[[not f for f in temp.isnull()]]
        temp = [float(f) for f in temp]
        try:
            result.loc[str(year)] = sum(temp)/len(temp)
        except:
            result.loc[str(year)] = None

    result = pd.DataFrame(result)
    result.columns = ['指标值']
    result.index.name = '日期'
    return result

2.12 弹性系数

# 弹性系数 计算函数
def elasticCoefficient(temp_data_fenzi,temp_data_fenmu,zhibiao_code,yuanxing_name,zhibiao_freq):
    '''
    temp_data_fenzi,要加工计算的原始数据-分子位置
    temp_data_fenmu,要加工计算的原始数据-分母位置
    yuanxing_name,原型的指标名称
    zhibiao_code,指标对应的编码
    zhibiao_freq,指标更新频率
    ''' 
    # 弹性系数:"当期及同比及占比"
    fenzi = monthaddupToSeason(temp_data_fenzi)
    fenzi = yearOnYear(fenzi,zhibiao_freq)
    fenmu = currentPeriod(temp_data_fenmu,zhibiao_freq)
    fenmu = yearOnYear(fenmu['指标值'],zhibiao_freq)
    for ind in fenmu.index:
        try:
            fenmu.loc[ind,'指标值'] = float(fenzi.loc[ind,'指标值']) / float(fenmu.loc[ind,'指标值'])
        except:
            fenmu.loc[ind,'指标值'] = None
    return fenmu

2.13 1-占比

# 1-占比  计算函数
def oneToShare(temp_data_fenzi,temp_data_fenmu,zhibiao_freq):
    """
    temp_data_fenzi,要加工计算的原始数据-分子位置
    temp_data_fenmu,要加工计算的原始数据-分母位置
    zhibiao_freq,指标更新频率
    """
    result = proportion(temp_data_fenzi,temp_data_fenmu,zhibiao_freq)
    for i in range(len(result)):
        if result['指标值'].iloc[i]:
            result['指标值'].iloc[i] = 100 - float(result['指标值'].iloc[i])
    return result

2.14 数据进行拼接求行和

# 对 需求加工字典 中对应的原始数据指标名称 对应的数据进行拼接求行和
def windDataConcatSum(databaseData,names_list):
    """
    databaseData : 万德入库的数据
    names_list : 需要提取对应的wind指标名称字符串,多个名称以 \n 作为分隔 
    """
    result = pd.DataFrame() # 结果存放
    
    # 将数据进行拼接          
    for fenzi_name in names_list:
        if sum(databaseData['index_nm'] == fenzi_name) == 0:
            print("指标 %s 还未入库,请先入库"%fenzi_name)
            return result,None
        t_data = databaseData['index_val'][databaseData['index_nm'] == fenzi_name]
        t_data = pd.DataFrame({"stat_dt":t_data.index,fenzi_name:t_data.values})
        if result.empty:
            result = t_data
        else:
            result = pd.merge(result,t_data,left_on=['stat_dt'],right_on=['stat_dt'],how='outer')
    zhibiao_freq = databaseData.loc[databaseData['index_nm']==names_list[0].strip(),:]['frequency_type'].iloc[0] # 指标加工频率

    result = result.set_index('stat_dt')
    result.sort_index(inplace=True)
    result.index.name = "日期"
    result = pd.DataFrame((result).sum(axis=1)) 
    
    return result,zhibiao_freq

2.15 数据库中的原始数据提取 和 处理

# 数据库中的原始数据提取 和 处理
def dataBaseExtract(username,password,host,database,tablename):
    '''
    engine = create_engine('dialect+driver://username:password@host:port/database')
    dialect -- 数据库类型
    driver -- 数据库驱动选择
    username -- 数据库用户名
    password -- 用户密码
    host 服务器地址
    port 端口
    database 数据库
    '''
    # 读取 公司数据库中的wind原始数据
    gongsi_engine = create_engine('postgresql+psycopg2://{username}:{password}@{host}:5432/{database}'.format(
        username=username,password=password,host=host,database=database))

    # 从公司数据库读取 原始的入库 数据表
    try:
        databaseData = pd.read_sql("select * from biz_temp.%s"%(tablename),con=gongsi_engine) 
        databaseData['index_nm'] = [name.strip() for name in databaseData['index_nm']]
        databaseData['stat_dt'] = pd.to_datetime(databaseData['stat_dt'])
        databaseData = databaseData.set_index('stat_dt') # 导入库中的wind数据      
    except:
        print("请返回数据库,查看数据库表的字段名称是否匹配.......")
    return databaseData 

2.16 提取 和 对应的 wind 或 统计局原始 数据返回

# 需求加工字典表 中的信息进行提取 和 对应的 wind 或 统计局原始 数据返回
def requestDictDataInfo(req_data,wind_data,nation_data,cateCal_dict,req_row_num):
    """
    req_data, 需求加工字典表
    wind_data, 入库的wind数据 
    nation_data,入库的统计局数据
    req_row_num,要加工计算的指标 对应的需求加工字典中的 所在行数
    """
    calculate_class = req_data['计算类别'].iloc[req_row_num]
    zhibiao_code = req_data['指标编码'].iloc[req_row_num] 
    yuanxing_name = req_data['原型指标名称'].iloc[req_row_num] 
    
    move_num = req_data['移动均值期数'].iloc[req_row_num]
    
    if str(move_num) != "nan":
        move_num = int(move_num)

    # 要加工的分子对应wind指标名称
    try:
        fenzi_origin_names = req_data['计算分子对应wind指标名称'].iloc[req_row_num].strip().split('\n')
    except:
        # print("%s 该指标暂时不满足数据要求!"%yuanxing_name)
        return ['','',zhibiao_code,yuanxing_name,'',calculate_class,move_num]
    
    # 将分子数据进行拼接
    if calculate_class == "北京市统计局":
        temp_data_fenzi,zhibiao_freq = windDataConcatSum(nation_data,fenzi_origin_names)
    else:
        temp_data_fenzi,zhibiao_freq = windDataConcatSum(wind_data,fenzi_origin_names)

    if len(temp_data_fenzi)==0:
        print(fenzi_origin_names," 中存在指标还未入库")
    
    # zhibiao_freq = databaseData.loc[databaseData['index_nm']==fenzi_origin_names[0],:]['frequency_type'][0] # 指标加工频率
    
    if cateCal_dict[calculate_class] == "双指标":
        # 要加工的分母对应wind指标名称
        fenmu_origin_names = req_data['计算分母对应wind指标名称'].iloc[req_row_num].strip().split('\n') 
        # 将分母数据进行拼接 
        temp_data_fenmu,zhibiao_freq= windDataConcatSum(wind_data,fenmu_origin_names)
        return [temp_data_fenzi,temp_data_fenmu,zhibiao_code,yuanxing_name,zhibiao_freq,calculate_class,move_num]
    elif cateCal_dict[calculate_class] == "双库指标":
        # 要加工的分母对应的 北京市统计局指标名称
        fenmu_origin_names = req_data['计算分母对应wind指标名称'].iloc[req_row_num].strip().split('\n') 
        # 将分母数据进行拼接 
        temp_data_fenmu,zhibiao_freq= windDataConcatSum(nation_data,fenmu_origin_names)
        return [temp_data_fenzi,temp_data_fenmu,zhibiao_code,yuanxing_name,zhibiao_freq,calculate_class,move_num]

    return [temp_data_fenzi,"",zhibiao_code,yuanxing_name,zhibiao_freq,calculate_class,move_num]

2.17 指定指标数据提取

# 提取  加工字典表中,不需要加工的 wind 指标 或者 统计局的指标
def windOrNationFeature(req_data,databaseData,req_row_num):
    """
    req_data, 加工字典数据表
    databaseData, 入库的数据表 数据
    zhibiao_code,指标编码
    yuanxing_name,原型中的指标名称
    zhibiao_freq,指标频率
    req_row_num,对应的加工字典的 第几行,
    """
    # 要加工的分子对应wind指标名称
    fenzi_origin_names = req_data['计算分子对应wind指标名称'].iloc[req_row_num].strip().split('\n')
    # 将分子数据进行拼接
    result,zhibiao_freq = windDataConcatSum(databaseData,fenzi_origin_names)
    result.columns = ["指标值"]
    
#     result.loc[:,"指标编码"] = zhibiao_code
#     result.loc[:,"原型指标名称"] = yuanxing_name
#     result.loc[:,'频率'] = zhibiao_freq
        
#     columns=['指标编码','原型指标名称','指标值','频率']
#     result = result[columns]
    return result

2.18 进度

# 进度  计算函数
def progressSpeed(temp_data_fenzi,temp_data_fenmu,zhibiao_freq):
    '''
    temp_data_fenzi,要计算的原始数据序列
    temp_data_fenmu,要计算的原始数据序列
    zhibiao_freq,指标更新频率
    '''
    result = temp_data_fenzi.copy()
    
    min_riqi = min(temp_data_fenzi.index)
    max_riqi = max(temp_data_fenzi.index)
    
    for year in range(min_riqi.year,max_riqi.year+1):
        fenzi = temp_data_fenzi.loc[str(year)]
        try:
            fenmu = temp_data_fenmu.loc[str(year)]
        except:
            result.loc[str(year)] = None
            continue
        for t in fenzi.index:
            try:
                result.loc[t] = round(float(fenzi.loc[t].values[0])/float(fenmu.iloc[0,0])*100,2)
            except:
                result.loc[t] = None

    result = pd.DataFrame(result)
    result.columns = ['指标值']
    result.index.name = '日期'
    return result

2.19 汇总函数

# 指标加工类型 汇总函数
def FeatureCalculate(req_data , wind_data , nation_data , req_row_num ,
                     temp_data_fenzi,temp_data_fenmu,zhibiao_code,yuanxing_name,zhibiao_freq,cal_class,move_num=0):
    '''
    req_data, 需求加工字典表
    wind_data, 入库的wind数据 
    nation_data,入库的统计局数据
    req_row_num,要加工计算的指标 对应的需求加工字典中的 所在行数
    
    temp_data_fenzi,要加工计算的原始数据-分子位置
    temp_data_fenmu,要加工计算的原始数据-分母位置
    zhibiao_code,指标对应的编码
    yuanxing_name,原型中的指标名称名称
    zhibiao_freq,指标更新频率
    cal_class,指标加工类型
    move_num , 移动均值 移动期数
    '''
    if cal_class == "wind":
        result = windOrNationFeature(req_data,wind_data,req_row_num)
    elif cal_class == "北京市统计局":
        result = windOrNationFeature(req_data,nation_data,req_row_num)
    elif cal_class=="环比":
        result = monthOnMonth(temp_data_fenzi,zhibiao_freq)
    elif cal_class=="同比":
        result = yearOnYear(temp_data_fenzi,zhibiao_freq)
    elif cal_class == "当期值":
        result = currentPeriod(temp_data_fenzi,zhibiao_freq)
    elif cal_class == "当期及同比":
        result = currentPeriod(temp_data_fenzi,zhibiao_freq)
        result = yearOnYear(result['指标值'],zhibiao_freq)
    elif cal_class == "累计值":
        result = monthToMonthAddUp(temp_data_fenzi,zhibiao_freq)
    elif cal_class == "移动均值":
        result = moveAverage(temp_data_fenzi,zhibiao_freq,move_num)
    elif cal_class == "当期及移动均值":
        result = currentPeriod(temp_data_fenzi,zhibiao_freq)
        result = moveAverage(result['指标值'],zhibiao_freq,move_num)
    elif cal_class == "同比及移动均值":
        result = yearOnYear(temp_data_fenzi,zhibiao_freq)
        result = moveAverage(result['指标值'],zhibiao_freq,move_num)
    elif cal_class == "当期及同比及移动均值":
        result = currentPeriod(temp_data_fenzi,zhibiao_freq)
        result = yearOnYear(result['指标值'],zhibiao_freq)
        result = moveAverage(result['指标值'],zhibiao_freq,move_num)
        
    elif cal_class == "占比":   # 涉及双指标
        result = proportion(temp_data_fenzi,temp_data_fenmu,zhibiao_freq)
    elif cal_class == "1-占比":
        result = oneToShare(temp_data_fenzi,temp_data_fenmu,zhibiao_freq)
    elif cal_class == "同期差值":
        result = samePeriodDiff(temp_data_fenzi,temp_data_fenmu,zhibiao_freq)
    elif cal_class == "同比及同期差值":
        fenzi_data = yearOnYear(temp_data_fenzi,zhibiao_freq)
        result = samePeriodDiff(fenzi_data,temp_data_fenmu,zhibiao_freq)         
    elif cal_class == "贡献率":
        result = contributionRate(temp_data_fenzi,temp_data_fenmu,zhibiao_freq)    
    elif cal_class == "拉动率":
        result = pullRate(temp_data_fenzi,temp_data_fenmu,zhibiao_freq) 
    elif cal_class == "弹性系数":# 弹性系数:"当期及同比及占比"
        result = elasticCoefficient(temp_data_fenzi,temp_data_fenmu,zhibiao_code,yuanxing_name,zhibiao_freq)
    elif cal_class == "月度占比年度均值":
        result = proportion(temp_data_fenzi,temp_data_fenmu,zhibiao_freq)
        result = monthInYearMean(result['指标值'],zhibiao_freq)
    elif cal_class == "进度":
        result = progressSpeed(temp_data_fenzi,temp_data_fenmu,zhibiao_freq)
    else:
        return None

    result.loc[:,"指标编码"] = zhibiao_code
    result.loc[:,"原型指标名称"] = yuanxing_name
    result.loc[:,'频率'] = zhibiao_freq
        
    columns=['指标编码','原型指标名称','指标值','频率']
    result = result[columns]
    return result

三、 具体实现案例

import pandas as pd
import datetime
from dateutil.relativedelta import *
import pandas as pd
import time

################################# 主程序  ####################################
if __name__=='__main__':
    # 初始化变量名     
    # 从公司数据库读取需要的数据表
    username = "xxxxxx"   #
    password = "xxxxxx"
    host = "xxxxxxxxxx"
    database = "xxxxxxxxx"
    wind_tablename = "xxxxxxxxxx"   # wind 入库的数据表名
    nation_tablename = "xxxxxxxxx" # 北京市统计局入库的数据表名
    
    # 本地数据库信息
    
    
    # 需求加工字典表 全地址名称
    req_data_name = r'./宏观经济数据库表/宏观经济分析指标基需求加工字典.xls'
    
    # 从公司数据库读取 原始的入库 数据表
    wind_data = dataBaseExtract(username,password,host,database,wind_tablename) # wind入库的数据
    nation_data = dataBaseExtract(username,password,host,database,nation_tablename)# 北京市统计局入库的数据

    # 读取 需求加工字典数据
    req_data = pd.read_excel(req_data_name)
    
    cateCal_dict = {
        '环比':                '单指标',
        '当期及同比':          '单指标',
        '当期及同比及移动均值':'单指标',
        '当期及移动均值':      '单指标',
        '当期值':              '单指标',
        '累计值':              '单指标',
        '同比':                '单指标',
        '同比及移动均值':      '单指标',
        '移动均值':            '单指标',
        '占比':                '双指标',
        '弹性系数':            '双指标',
        '同比及同期差值':      '双指标',
        '1-占比':              '双指标',
        '贡献率':              '双指标',
        '拉动率':              '双指标',
        '同期差值':            '双指标',
        '月度占比年度均值':    '双指标',
        'wind':                '单指标',
        '北京市统计局':        '单指标',
        '进度':               '双库指标'
    }
    all_yuanxing_data = pd.DataFrame() # 存放所有原型中的数据,纵向拼接
    
    time_start = time.time() # 程序开始计时
    for req_row_num in range(len(req_data)): 
        try:
            # 提取需要的基础数据信息
            temp_data_fenzi,temp_data_fenmu,zhibiao_code,yuanxing_name,zhibiao_freq,cal_class,move_num = \
                requestDictDataInfo(req_data,wind_data,nation_data,cateCal_dict,req_row_num)
            if str(cal_class)=="nan":
                continue
            #  需要的指标信息
            one_yuanxing_data = FeatureCalculate(req_data , wind_data , nation_data , req_row_num ,
                         temp_data_fenzi,temp_data_fenmu,zhibiao_code,yuanxing_name,zhibiao_freq,cal_class,move_num)
            if req_row_num%50 == 0:
                print("加工到 %s 行了,对应的指标编码为:%s"%(req_row_num+2,zhibiao_code))
                
            # 数据拼接
            if all_yuanxing_data.empty:
                all_yuanxing_data = one_yuanxing_data
            else:
                all_yuanxing_data = pd.concat([all_yuanxing_data,one_yuanxing_data])
        except:
            print('忽略了需求表中第%s行的数据,对应的指标编码为:%s'%(req_row_num+2,zhibiao_code))
        time_end = time.time() # 程序结束时间
    print('\n运行结束,程序耗时:%s'%(time_end-time_start))
    

req_data数据样例
req_data
result_tongbi 加工结果样例:
在这里插入图片描述

四、小感

本来以为 同比、环比、占比、贡献率、拉动率 这些日常见到的名词,应该挺简单的,动手一整理,发现其中还是有很多的“坑坑道道”,

  • 2
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

积跬步,慕至千里

你的鼓励将是我创作的最大动力!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值