1

环境准备:sublime+ipython

打开代码编辑器sublime——本质上,txt文本编辑器也可以写代码,并保存为以.py为后缀的python文件,但专业的代码编辑器可以实现语法高亮、自动补全等功能,并支持项目管理,大大提高编写代码的效率和代码的管理。因此,选择一款合适的代码编辑器便不可少

打开终端并进入ipython模式——ipython可以帮助我进行探索和试误,利用魔术命令%paste(执行剪贴板中的python代码)更是可以帮助我快速查看某段代码的执行效果

如果说普通的代码编辑器支持的是“编辑-编译-运行”的工作模式,那么ipython鼓励的则是“执行-探索”的工作模式。

开始写代码

分析任务:一家电商公司的收入来自不同的部门,每个部门下又有不同的商品类目。收入的波动来自于不同部门或类目的收入涨跌。为了快速定位每天的收入波动来自哪个部门以及哪个类目,需要搭建模型进行自动化分析。

我们的目标是利用python实现收入波动的分析模型(Analysis Model for Income Fluctuation)。
首先,我们需要清晰定义实现最终目标的每个步骤。

  1. 计算各个部门的收入变化值(观察日收入-对比日收入)以及整体的收入变化值;

  2. 计算各个部门收入变化值占比整体收入变化值的比例,取绝对值;其中,占比最大的就是对整体收入变化影响最大的部门,可以取经验值10%,即占比大于10%的部门就是对整体收入变化影响最大的部门;

  3. 计算上述步骤得到的影响最大的部门下每个类目收入变化值和每个部门的收入变化值;

  4. 计算每个类目收入变化值占比部门整体收入变化值的比例,取绝对值,找出影响最大的类目。

现在我们用python来实现上述步骤:

导入所需模块和数据:

import pandas as pd

df=pd.read_excel('/Users/xiangzhendong/Downloads/income_data.xls')

利用数据框(dataframe)的透视表(pivot_table)方法按部门聚合昨日和前日的收入数据:

df_pivot=df.pivot_table('income',index='department',columns='date',aggfunc='sum')

计算每个部门的收入变化值以及每个部门的变化值占比整体变化值的比例:

df_pivot['change_amt']=df_pivot['2016-11-16']-df_pivot['2016-11-15']

df_pivot['change_pct']=abs(df_pivot['change_amt']/df_pivot['change_amt'].sum())

此时,我们的df_pivot数据框多了change_amt和change_pct两列。如果我们要选出change_pct大于10%的部门,可以这样写:

result=df_pivot[df_pivot['change_pct']>=0.1]

对整体变化影响最大部门已经找出来了,接下来寻找每个部门下对部门整体变化影响最大的类目。不难发现,寻找的逻辑其实是一模一样的。在编写代码的过程中,我们要注意识别做事的模式,创造工具简化同类操作。

此时,我们可以创建一个寻找对整体变化影响最大的成分的函数:

def max_change(df, rows):

    df_pivot=df.pivot_table('income',index=rows,columns='date',aggfunc='sum')

    df_pivot['change_amt']=df_pivot['2016-11-16']-df_pivot['2016-11-15']

    df_pivot['change_pct']=abs(df_pivot['change_amt']/df_pivot['change_amt'].sum())

    return df_pivot[df_pivot['change_pct']>=0.1]    

这里,我们创建了max_change函数,它有两个参数,一个是待分析的数据源(df),一个是细分项(rows),例如部门或类目。函数内部的操作与之前的代码完全一致。有了这个函数,我们只要给到数据源和细分项,就能得到影响最大的细分项。

细心的读者一定发现这里还有一个问题没有解决,那就是日期:这里日期是写死的,并不能根据每天的日期来自动更新,显然不符合自动化的原则。

datetime模块可以解决这个问题。我们来认识下datetime如何处理日期。

In [1]: today=datetime.date.today()

In [2]: print today
2016-11-23

In [3]: today.ctime()
Out[3]: 'Wed Nov 23 00:00:00 2016'

In [4]: today.timetuple()
Out[4]: time.struct_time(tm_year=2016, tm_mon=11, tm_mday=23, tm_hour=0, tm_min=0, tm_sec=0, tm_wday=2, tm_yday=328, tm_isdst=-1)

In [5]: today.toordinal()
Out[5]: 736291

In [6]: today.year
Out[6]: 2016

In [7]: today.month
Out[7]: 11

In [8]: today.day
Out[8]: 23

因此,今天、昨天和前天的写法如下:

today="%s"%(datetime.date.today())

yesterday="%s"%(datetime.date.today()-datetime.timedelta(days=1))

qiantian="%s"%(datetime.date.today()-datetime.timedelta(days=2))

max_change函数也相应地写成:

def max_change(df, rows):
    
        df_pivot=df.pivot_table('income',index=rows,columns='date',aggfunc='sum')
    
        df_pivot['change_amt']=df_pivot[qiantian]-df_pivot[yesterday]
    
        df_pivot['change_pct']=abs(df_pivot['change_amt']/df_pivot['change_amt'].sum())
    
        return df_pivot[df_pivot['change_pct']>=0.1]  

如果我们想要知道对整体影响最大的部门是什么,可以这样来调用函数:

result=max_change(df, 'department')

如果我们要知道影响最大的部门下哪个类目影响最大,可以这样来调用函数:

result_lm=max_change(df[df['department']==result.index[0]],'item_cats')

result.index会返回影响最大的部门的名称的列表,通过列表索引来引用它们。由于有多个部门,这里我们需要用for循环来遍历列表,最后将每次遍历返回的数据框合并:

def max_lm(result,df):
    frames=[]

    for i in range(len(result)):
        result_lm=max_change(df[df['department']==result.index[i]],'item_cats')
        result_lm['department']=result.index[i]    #将部门名称添加到数据框中
        frames.append(result_lm)
    
    return pd.concat(frames)

调用上述函数得到每个部门下影响最大的类目:

final=max_lm(result,df)

如果我们想把结果导出到excel表中,可以这样写:

writer=pd.ExcelWriter('output_today.xlsx')

result.to_excel(writer, sheet_name='max_departments')
final.to_excel(writer, sheet_name='max_itemcats')

writer.save()

总结

  1. 准备好python开发环境,即 “代码编辑器+ipython”;

  2. 写代码前清晰定义实现最终目标的每个步骤;

  3. 写代码的过程中识别做事的模式,创造工具简化复用性操作;

  4. 利用for循环遍历列表。

最终代码

import pandas as pd 
import datetime

today="%s"%(datetime.date.today())
yesterday="%s"%(datetime.date.today()-datetime.timedelta(days=1))
qiantian="%s"%(datetime.date.today()-datetime.timedelta(days=2))
print("昨天和前天的日期分别是:")
print(yesterday,qiantian)

df=pd.read_excel('/Users/xiangzhendong/Downloads/income_data.xls')

def max_change(df, rows):
    df_pivot=df.pivot_table('income',index=rows,columns='date',aggfunc='sum')
    df_pivot['change_amt']=df_pivot[yesterday]-df_pivot[qiantian]
    df_pivot['change_pct']=abs(df_pivot['change_amt']/df_pivot['change_amt'].sum())
    return df_pivot[df_pivot['change_pct']>=0.1]

result=max_change(df,'department')
print(result)

def max_lm(result,df):
    frames=[]

    for i in range(len(result)):
        result_lm=max_change(df[df['department']==result.index[i]],'itemcats')
        result_lm['department']=result.index[i]
        frames.append(result_lm)
    
    return pd.concat(frames)

final=max_lm(result, df)
print(final)

writer=pd.ExcelWriter('output_today.xlsx')

result.to_excel(writer, sheet_name='max_departments')
final.to_excel(writer, sheet_name='max_itemcats')

writer.save()

xiangzhendong
17 声望6 粉丝

要保持好奇心,并问很多问题;要真实,并忠实于自己。