【问题标题】:funnel analysis with pandas (large data set)使用 pandas 进行漏斗分析(大数据集)
【发布时间】:2014-09-18 02:51:05
【问题描述】:

我正在尝试使用 pandas 数据框进行一些基本的漏斗分析。意思是,我有一个包含用户sessions 的数据框,它由一系列events 组成。我希望能够按session 分组,确定哪些sessions 包含给定的event ordering(事件A 后跟事件B),然后按date 分组,并随着时间的推移获得这些计数。

例如,给定我的数据框:

sessions = ['a', 'a', 'a', 'b', 'b', 'b', 'b', 'c', 'c', 'd', 'd', 'd']
events = ['dog', 'cat', 'tree', 'tree', 'dog', 'frog', 'cat', 'dog', 'cat', 'tree', 'cat', 'dog']
d1 = datetime(2014,8,1)
d2 = datetime(2014,8,2)
d3 = datetime(2014,8,3)
dates = [d1, d1, d1, d1, d1, d1, d1, d2, d2, d1, d1, d1]
dic = {'sessions':sessions, 'events':events, 'dates':dates}
df_tot = pd.DataFrame(dic)

制作:

    sessionDate  events  sessions
0   2014-08-01   dog     a
1   2014-08-01   cat     a
2   2014-08-01   tree    a
3   2014-08-01   tree    b
4   2014-08-01   dog     b
5   2014-08-01   frog    b
6   2014-08-01   cat     b
7   2014-08-02   dog     c
8   2014-08-02   cat     c
9   2014-08-01   tree    d
10  2014-08-01   cat     d
11  2014-08-01   dog     d

我想获得以下事件排序dog 然后cat

             reachedFirstEvent   reachedSecondEvent  total
2014-08-01   1                   2                   3
2014-08-02   0                   1                   1

我的第二个问题是,我的实际数据框中有 300 万行。所以我建立了一个黑客在一起的解决方案。它可以工作,但速度很慢。关于如何执行此操作或加快我的代码的任何想法?

def find_funnels_ex(dlist,event_list):

        m = -1
        for i in range(0,len(event_list)):

            j = np.where(dlist == event_list[i])[0] #get all indices where cat
            j = j[j>=m] #select only indices greater than min dog index
            if j.size == 0:
                return i
            else:
                m = np.min(j)

        return i+1

sessions = ['a', 'a', 'a', 'b', 'b', 'b', 'b', 'c', 'c', 'd', 'd', 'd']
events = ['dog', 'cat', 'tree', 'tree', 'dog', 'frog', 'cat', 'dog', 'cat', 'tree', 'cat', 'dog']
d1 = datetime(2014,8,1)
d2 = datetime(2014,8,2)
d3 = datetime(2014,8,3)
dates = [d1, d1, d1, d1, d1, d1, d1, d2, d2, d1, d1, d1]
dic = {'sessions':sessions, 'events':events, 'dates':dates}
df_tot = pd.DataFrame(dic)


#get only groups that have at least first event
gb_tot = df_tot.groupby('sessions')
df_filt = gb_tot.filter(lambda x: 'dog' in x['events'].values) #changes to dataframe

#get funnel position for each session
#returns a 1 if first event is reached, returns a 2 if second event is reached, etc
gb_filt = df_filt.groupby('sessions')
gb_funn = gb_filt.aggregate(lambda x: find_funnels_ex(
                                x['events'].values, 
                                ['dog','cat']
                                )
                   ) 

#join this to funnel to get date events funnel was started
gb_filt = gb_filt.aggregate({'dates':np.min}) 
gb_filt['funnel'] = gb_funn['events']
df_funn = gb_filt.reset_index() #change back to dataframe

#pivot to get columns of funnel position indicators
df_piv = pd.pivot_table(df_funn,'funnel', cols='funnel', rows=['sessions','dates'], aggfunc=np.sum) #pivot
df_piv = df_piv.reset_index() #reset

#group by date and sum
df_piv = df_piv.set_index('dates') #set index
gb_piv = df_piv.groupby(lambda x: x) #groupby date
gb_final = gb_piv.aggregate({1:np.sum,2:np.sum})

#get totals
gb_tot = df_tot.groupby('sessions')
gb_tot = gb_tot.aggregate({'dates':np.min})
gb_tot = gb_tot.set_index('dates') #set index
gb_tot = gb_tot.groupby(lambda x: x).size() #groupby date
gb_final['total'] = gb_tot


gb_final[2] = gb_final.apply(lambda x: x[2]/2.0,axis=1)

【问题讨论】:

  • 您能否在您的示例中添加一些细节,说明为什么reachedFirstEvent0 对于2014-08-02?如果首先达到的标准是会话中的dog,那么会话c 不合格吗?
  • 对,这来自我的 find_funnels_ex() 函数。当且仅当到达漏斗的第二部分时,它才返回 2。否则,如果仅到达第一部分,则返回 1。所以,你是对的,firstEventReached 的实际计数应该是列 1 + 2
  • 听起来不错,正在写一些可能有帮助的东西。为了再次更好地理解,您的目标是做两件事:1)识别到达第一个和/或第二个事件的会话,以及 2)对于每个日期,将符合这些布尔值的会话数相加?此外,您拥有的日期数组不会产生您列出的 df 。它需要阅读[d1,d1,d1,d1,d1,d1,d1,d2,d2,d1,d1,d1]
  • 非常感谢!我在下面提出了第二个解决方案,但它仍然相当滞后。是的,正如你上面所说,这正是我想要的
  • dog 是否必须是会话中的第一个事件才能成为reachedFirst,或者如果狗在会话中的任何位置,它具有reachedFirst

标签: python pandas dataframe


【解决方案1】:

这是我想出的另一个版本。虽然有很多数据,但同样慢:(

此函数确定会话是否包含当前漏斗:

def find_funnels(dlist,event_list):

    m = -1
    for i in range(0,len(event_list)):

        j = np.where(dlist == event_list[i])[0]
        j = j[j>=m]
        if j.size == 0:
            return False
        else:
            m = np.min(j)

    return True

此函数将当前漏斗应用于df:

def funnelz(df, eventList, groups, dates, events):

    dfz = pd.DataFrame()
    count = 1
    eventList2 = [eventList[0]]

    while eventList:

        if not dfz.empty:
            gb = df.groupby(groups)
            df = gb.filter(lambda x: find_funnels(x[events].values, eventList2))

        gb = df.groupby(groups)
        gb = gb.aggregate({dates:np.min})
        gb = gb.set_index(dates)
        gb = gb.groupby(lambda x: x).size()

        if not dfz.empty:
            dfz['event'+str(count)+'Reached'] = gb
            count += 1
            eventList = eventList[1:]
            if eventList:
                eventList2.append(eventList[0])

        else:
            dfz['total'] = gb

    return dfz

似乎可以工作,但速度很慢:

funnelz(df_funn, eventList=['dog', 'cat'], groups = 'sessions', dates = 'dates', events = 'events')

【讨论】:

    猜你喜欢
    • 2014-06-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-09-25
    • 1970-01-01
    • 1970-01-01
    • 2013-06-11
    • 2012-05-20
    相关资源
    最近更新 更多