首页 > 解决方案 > Python(Pandas)中每周时间范围内数据的特定聚合

问题描述

我目前正在解决一个问题,我无法找出提出解决方案的最佳方法,也许你们可以帮助我。

我有一个来自客户关系呼叫中心的呼叫数据集,我需要以特定方式对其进行聚合。该公司正在调查新客户的行为,他们认为新客户往往比老客户更频繁地打电话(这是意料之中的,但我需要使其可视化)。所以我需要从某个时期进入公司的客户那里知道,呼叫中心在同一时期以及以后的时期内接到了多少新客户的电话。

基本上,从第 1 周订阅的客户那里,有多少人在第 1 周打电话,有多少人在第 2 周打电话,等等。

这是数据集的先睹为快:

数据集的基础知识

date_ref是通话日期。cred_date是订阅日期。

我遇到了一个使用带有熊猫的布尔索引的解决方案,男孩,代码看起来很难看!我也不太相信这是否可靠。这是我到目前为止所做的:

# Aggregation functions to be passed to groupby
aggregation = {
    'n_creds': ('account_id', pd.Series.nunique),
    'n_calls': ('date_ref', 'count')
}

# Groupby splitting dates in weeks and with specified aggregations
mcases_agg = mcases_ready.groupby(pd.Grouper(key = 'cred_date', freq = 'W')).agg(**aggregation)
mcases_idx_list = mcases_agg.index.tolist()

n_calls_list = []
for i, _ in enumerate(mcases_idx_list):
    if i == 0:
        df = mcases[mcases['cred_date'] <= mcases_idx_list[i]]
        n_calls_from_cred_this_week = df[(df['date_ref'] >= mcases_idx_list[i]) & \  
                                         (df['date_ref'] < (mcases_idx_list[i + 1]))]['account_id'].nunique()
        n_calls_list.append(n_calls_from_cred_this_week)
    
    elif i != len(mcases_idx_list) - 1:
        df = mcases[mcases['cred_date'] <= mcases_idx_list[i]]
        n_calls_from_cred_this_week = df[(df['date_ref'] >= mcases_idx_list[i]) & \ 
                                         (df['date_ref'] < (mcases_idx_list[i + 1]))]['account_id'].nunique()
        n_calls_list.append(n_calls_from_cred_this_week)
    
    else:    
        df = mcases[mcases['cred_date'] <= mcases_idx_list[i]]
        n_calls_from_cred_this_week = df[(df['date_ref'] >= mcases_idx_list[i])]['account_id'].nunique()
        n_calls_list.append(n_calls_from_cred_this_week)

如果你们遇到过类似的问题,我想听听社区的意见,你们是如何解决的我不熟悉。

谢谢!

标签: pythondatetimedata-scienceaggregation

解决方案


在稍微打破了我的头之后,我为我的问题找到了一个更好的解决方案(证明疲惫的大脑资源有限)。

  1. 首先,我计算了每次调用 ( date_ref) 和订阅日期 ( cred_date) 之间的天数,并将其保存到新列中interval_cred_call

    mcases['interval_cred_call'] = (mcases['date_ref'] - mcases['cred_date']).dt.days

  2. 根据这个值,我为每周时间的垃圾邮件创建了特定的列,如果调用小于 7 天并保存到列,则将调用分类为布尔Week #1值,然后在 7 到 14 天之间并将其保存到列Week #2,依此类推......

  3. 然后,我使用一个函数自动化了迭代值的任务,这可能会导致 pd.DataFrame 或水平条形图。

下面是我编写的函数:

def n_call_timewindow(df, n_days = 100, plot = False):
    '''
    This function calculates the number of calls (cases) after n_days // 7 entrance in the cred database and returns a pd.DataFrame with columns being the weeks ahead of entrance.
    
    Parameters:
 
    ** n_days: 
    Number of days to be included in the analysis. Please observe that the output will be in weeks, therefore the number of days will be divided by 7, and remainders will be discarded.
    
    ** plot (default, False)
    If set to True, will plot a horizontal bar chat instead of showing a pd.DataFrame.\n
    ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    '''
    df = df.copy()
    
    week = n_days // 7
    for i in range(0, week + 1):
        if i == 0:
            df[f'Semana #{i + 1}'] = (df['interval_cred_call'] <= (i + 7)).astype(int)
        else:
            df[f'Semana #{i + 1}'] = ((df['interval_cred_call'] > (i * 7)) & 
                                             (df['interval_cred_call'] <= ((i + 1) * 7))).astype(int)

    
    df = df.iloc[:, -(week + 1):-1]
    
    if plot == True:
        fig, ax = plt.subplots(1, figsize = (15, 5))
        fig.suptitle('Total de chamados realizados após Credenciamento\n(por semana, a partir da entrada na base)',
                     fontsize = 20, color = 'darkgreen')
        fig.tight_layout()
        df.sum().plot(kind = 'barh', alpha = .8, width = .8, color = 'limegreen', zorder = 2).invert_yaxis()
        ax.grid(b = True, axis = 'x', alpha = .2, zorder = 1)
        ax.tick_params(axis='both', colors='gray', labelsize = 14, labelcolor = 'dimgray')
        ax.spines['left'].set_color('lightgray')
        ax.spines['bottom'].set_visible(False)
        ax.spines['top'].set_visible(False)
        ax.spines['right'].set_visible(False)
        
        return f'{fig}'

    return df

在设置参数plot = True时,结果如下:

在此处输入图像描述


推荐阅读