簡體   English   中英

創建一個循環以找出前20天內的銷售數量

[英]creating a loop to find out number of sales within the first 20 days

我是py的新手,無法弄清楚如何在首次銷售后20天找到銷售電話的數量。 問題是讓我計算出在開始的20天內至少撥打了10個電話的銷售人員的百分比。 每行都是一個銷售電話,銷售人員用col id表示,銷售電話的時間記錄在call_starttime

df非常簡單,看起來像這樣

    id      call_starttime  level
0   66547   7/28/2015 23:18 1
1   66272   8/10/2015 20:48 0
2   66547   8/20/2015 17:32 2
3   66272   8/31/2015 18:21 0
4   66272   8/31/2015 20:25 0

我已經計算出每個id的convos數量,並且可以過濾掉未進行至少10次電話銷售的任何人

目前正在使用的代碼是

df_withcount=df.groupby(['cc_user_id','cc_cohort']).size().reset_index(name='count')
df_20andmore=df_withcount.loc[(df_withcount['count'] >= 20)]

我希望輸出結果可以告訴我ID(銷售人員)在最初20天內至少撥打了10次電話的數量。 到目前為止,我只能弄清楚該如何在整個時間內至少撥打10個電話

我假設call_starttime列為 DateTime類型。

讓我們從一個簡化的解決方案開始,僅檢查第二個呼叫(而不檢查10個后續呼叫)。

我略微更改了您的測試數據,以便id = 66272的人在第一個電話(8​​月10日和19日)之后的20天內擁有第二個電話:

      id      call_starttime  level
0  66547 2015-07-28 23:18:00      1
1  66272 2015-08-10 20:48:00      0
2  66547 2015-08-20 17:32:00      2
3  66272 2015-08-19 18:21:00      0
4  66272 2015-08-31 20:25:00      0

第一步是定義一個函數,說明當前人員是否處於“活動狀態”(他從第一個呼叫開始的20天之內進行了第二個呼叫):

def active(grp):
    if grp.shape[0] < 2:
        return False  # Single call
    d0 = grp.call_starttime.iloc[0]
    d1 = grp.call_starttime.iloc[1]
    return (d1 - d0).days < 20

此功能將應用於每組行(針對每個人)。

要獲取有關每個人的活動的詳細信息,可以運行:

df.groupby('id').apply(active)

對於我的樣本數據,結果是:

id
66272     True
66547    False
dtype: bool

但是,如果你有興趣只在活躍的人的數量 ,使用np.count_nonzero以上的結果:

np.count_nonzero(df.groupby('id').apply(active))

對於我的樣本數據,結果為1

如果您想要活躍的人的百分比 ,請將該數字除以df.id.unique()。size (乘以100,以百分比表示結果)。

現在,如何更改此解決方案以檢查一個人在最初的20天內是否至少撥打了10次電話:

唯一的區別是, 活動函數應該比較調用09的日期。

因此,此功能應更改為:

def active(grp):
    if grp.shape[0] < 10:
        return False  # Too little calls
    d0 = grp.call_starttime.iloc[0]
    d1 = grp.call_starttime.iloc[9]
    return (d1 - d0).days < 20

我假設源行按call_starttime排序 如果不是這種情況,請在之前調用sort_values(by ='call_starttime')

根據您的評論進行編輯

我想出了另一種解決方案,包括按級別列分組,對源數據排序沒有要求,並且在此期間的初始天數和調用次數都易於進行參數化。

測試數據框:

      id      call_starttime  level
0  66547 2015-07-28 23:18:00      1
1  66272 2015-08-10 19:48:00      0
2  66547 2015-08-20 17:32:00      1
3  66272 2015-08-19 18:21:00      0
4  66272 2015-08-29 20:25:00      0
5  66777 2015-08-30 20:00:00      0

級別0包含一個在開始的20天內(8月10日,19日和29日)有3個呼叫的人。 但是請注意,最后一次呼叫的時間比第一次呼叫晚,因此實際上這兩個TimeStamp相隔19天以上 ,但是由於我的解決方案清除了時間部分,因此考慮最后一次呼叫。

從定義函數開始:

def activity(grp, dayNo):
    stDates = grp.dt.floor('d')  # Delete time component
    # Leave dates from starting "dayNo" days
    stDates = stDates[stDates < stDates.min() + pd.offsets.Day(dayNo)]
    return stDates.size

給出第一天天內特定人員的呼叫數量( call_starttime值組)。

下一個要定義的功能是:

def percentage(s, callNo):
    return s[s >= callNo].size * 100 / s.size

計算s (當前級別Series )中大於等於callNo的值的百分比。

第一處理步驟是計算一個系列 -呼叫數,所定義的“起動期間”內,對於每個電平 / ID:

calls = df.groupby(['level', 'id']).call_starttime.apply(activity, dayNo=20)

結果(針對我的數據)為:

level  id   
0      66272    3
       66777    1
1      66547    1
Name: call_starttime, dtype: int64

要獲取最終結果(假設需要進行3次調用,則為每個級別的百分比),請運行:

calls.groupby(level=0).apply(percentage, callNo=3)

請注意,上面的level = 0是對MultiIndex級別的引用,而不是對列名的引用。

結果(再次用於我的數據)為:

level
0    50.0
1     0.0
Name: call_starttime, dtype: float64

級別0擁有一個滿足條件的人員(此級別共有2位人員),所以該百分比為50,而在級別1則沒有人滿足條件,因此該百分比為0

請注意,使用dayNocallNo參數可以很容易地進行參數化,涉及每個人的“初始時間段”的長度以及該時間段內要撥打的電話數。

上面描述的計算是針對3個調用的,但是在您的情況下, 請將callNo更改為您的值,即10

如您所見,該解決方案很短(只有8行代碼),比其他解決方案要短得多,並且“ Pandasonic”要多得多。

如果你喜歡一個“簡潔”的編碼風格,你也可以做一個單一的 (雖然顯著鏈接)指令的整個計算:

df.groupby(['level', 'id']).call_starttime\
    .apply(activity, dayNo=20).rename('Percentage')\
    .groupby(level=0).apply(percentage, callNo=3)

我添加了.rename('Percentage')來更改結果Series的名稱。

我使用了Person類來幫助解決此問題。

  1. 創建一個數據框
  2. 將call_start_time從字符串更改為TimeDelta格式
  3. 在FIRST call_start_time之后的20天檢索
  4. 創建了Person類來跟蹤days_count和id
  5. 創建了一個列表來保存Person對象,並使用dataframe中的數據填充這些對象
  6. 如果從開始日期到結束日期的20天內,銷售人員達到10次以上的銷售量,則打印人員對象列表

我已經測試過我的代碼,並且效果很好。 可以進行改進,但是我的主要重點是實現良好的工作解決方案。 如果您有任何疑問,請告訴我。

import pandas as pd
from datetime import timedelta
import datetime
import numpy as np

# prep data for dataframe
lst = {'call_start_time':['7/28/2015','8/10/2015','7/28/2015','7/28/2015'],
        'level':['1','0','1','1'],
        'id':['66547', '66272', '66547','66547']}

# create dataframe
df = pd.DataFrame(lst)

# convert to TimeDelta object to subtract days
for index, row in df.iterrows():
    row['call_start_time'] = datetime.datetime.strptime(row['call_start_time'], "%m/%d/%Y").date()

# get the end date by adding 20 days to start day
df["end_of_20_days"] = df["call_start_time"] + timedelta(days=20)

# used below comment for testing might need it later
# df['Difference'] = (df['end_of_20_days'] - df['call_start_time']).dt.days

# created person class to keep track of days_count and id
class Person(object):
    def __init__(self, id, start_date, end_date):
        self.id = id
        self.start_date = start_date
        self.end_date = end_date
        self.days_count = 1

# create list to hold objects of person class
person_list = []

# populate person_list with Person objects and their attributes
for index, row in df.iterrows():
    # get result_id to use as conditional for populating Person objects
    result_id = any(x.id == row['id'] for x in person_list)

    # initialize Person objects and inject with data from dataframe
    if len(person_list) == 0:
        person_list.append(Person(row['id'], row['call_start_time'], row['end_of_20_days']))
    elif not(result_id):
        person_list.append(Person(row['id'], row['call_start_time'], row['end_of_20_days']))
    else:
        for x in person_list:
            # if call_start_time is within 20 days time frame, increment day_count to Person object
            diff = (x.end_date - row['call_start_time']).days
            if x.id == row['id'] and diff <= 20 :
                x.days_count += 1
                break

# flag to check if nobody hit the sales mark
flag = 0

# print out only person_list ids who have hit the sales mark
for person in person_list:
    if person.days_count >= 10:
        flag = 1
        print("person id:{} has made {} calls within the past 20 days since first call date".format(person.id, person.days_count))

if flag == 0:
    print("No one has hit the sales mark")

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM