Python 聚类区间

Python 聚类区间,python,pandas,group-by,Python,Pandas,Group By,我的数据帧的每一行都是一个间隔,由date1和date2以及一个用户id表示。对于每个用户id,我需要将间隔分组在一起,间隔之间有一个低于某个阈值的间隙 到目前为止,对于每个用户id,我按开始日期和结束日期对行进行排序。然后,我计算间距并根据这些值对行进行分组。然后,我将修改后的行添加到新的数据帧中(这是我发现的取消数据帧分组的方法) 然而,这是相当缓慢的。你有没有发现改进我分组方式的方法 def gap(group): return group[['date1', 'date2']].

我的数据帧的每一行都是一个间隔,由date1和date2以及一个用户id表示。对于每个用户id,我需要将间隔分组在一起,间隔之间有一个低于某个阈值的间隙

到目前为止,对于每个用户id,我按开始日期和结束日期对行进行排序。然后,我计算间距并根据这些值对行进行分组。然后,我将修改后的行添加到新的数据帧中(这是我发现的取消数据帧分组的方法)

然而,这是相当缓慢的。你有没有发现改进我分组方式的方法

def gap(group):
    return group[['date1', 'date2']].min(axis = 1) - \
        group.shift()[['date1', 'date2']].max(axis = 1)

def cluster(df, threshold):
    df['clusters'] = 0
    grouped = df.groupby('user_id')
    newdf = pd.DataFrame()
    for name, group in grouped:
        group = group.sort_values(['date1', 'date2'], ascending = True)
        group['gap'] = gap(group)
        cuts = group['gap'] > timedelta(threshold)
        df2 = group.copy()
        for g, d, r in zip(group.loc[cuts, 'gap'], group.loc[cuts, 'date1'], group.loc[cuts, 'date2']):
            df2.loc[((df2['date1'] >= d) & (df2['date2'] >= r)), 'clusters'] +=1
        df2 = df2.drop('gap', axis = 1)
        newdf = pd.concat([newdf, df2])
    return newdf
以下是它使用的数据的最小示例:

 df = pd.DataFrame(dict([('user_id', np.array(['a', 'a', 'a', 'a', 'a', 'a', 'a'])), 
    ('date1', np.array([datetime.strptime(x, "%y%m%d") for x in ['160101', '160103', '160110', '160120', '160130', '160308', '160325']])),
    ('date2', np.array([datetime.strptime(x, "%y%m%d") for x in ['160107', '160109', '160115', '160126', '160206', '160314', '160402']]))]))

一个简单的改进是在布尔向量
割集
上使用
cumsum

def cluster2(df, threshold):
    df['clusters'] = 0
    grouped = df.groupby('user_id')
    df_list = []
    for name, group in grouped:
        group = group.sort_values(['date1', 'date2'], ascending = True)
        group['gap'] = gap(group)
        print(group)
        cuts = group['gap'] > timedelta(threshold)
        df2 = group.copy()
        df2['clusters'] = cuts.cumsum()
        df_list.append(df2)
    return pd.concat(df_list)
编辑:在OP的评论之后,我将串联从循环中移出以提高性能

进一步的改进可能是在
groupby
操作中不对组进行排序(如果有许多用户):

甚至可以通过按
user\u id
df
进行排序,然后将一个条件添加到
cuts
直接在原始数据帧上手动分组:

df = df.sort_values(['user_id', 'date1', 'date2'], ascending = True)
df['gap'] = gap(df)
cuts = (df['user_id'] != df['user_id'].shift()) | (df['gap'] > timedelta(threshold))
df['clusters'] = cuts.cumsum()

一个简单的改进是在布尔向量
割集
上使用
cumsum

def cluster2(df, threshold):
    df['clusters'] = 0
    grouped = df.groupby('user_id')
    df_list = []
    for name, group in grouped:
        group = group.sort_values(['date1', 'date2'], ascending = True)
        group['gap'] = gap(group)
        print(group)
        cuts = group['gap'] > timedelta(threshold)
        df2 = group.copy()
        df2['clusters'] = cuts.cumsum()
        df_list.append(df2)
    return pd.concat(df_list)
编辑:在OP的评论之后,我将串联从循环中移出以提高性能

进一步的改进可能是在
groupby
操作中不对组进行排序(如果有许多用户):

甚至可以通过按
user\u id
df
进行排序,然后将一个条件添加到
cuts
直接在原始数据帧上手动分组:

df = df.sort_values(['user_id', 'date1', 'date2'], ascending = True)
df['gap'] = gap(df)
cuts = (df['user_id'] != df['user_id'].shift()) | (df['gap'] > timedelta(threshold))
df['clusters'] = cuts.cumsum()

您能否发布此代码开头的最小数据样本?以您的示例来说,合理的阈值是多少?7,14天。类似这样的东西为了使代码正常工作,我必须在
gap
函数中切换
max
shift
group[['date1','date2']].min(axis=1)-group['date1','date2'].max(axis=1).shift()。不知道为什么…你能发布这段代码开头的最小数据样本吗?以你的例子来说,合理的阈值是多少?7,14天。类似这样的东西为了使代码正常工作,我必须在
gap
函数中切换
max
shift
group[['date1','date2']].min(axis=1)-group['date1','date2'].max(axis=1).shift()。不知道为什么…我还将所有的
df2
数据帧存储在一个列表中,并且只进行了一次连接。这很有帮助,非常感谢你的想法!关于连接的一点很好,我应该明白:)我还将所有的
df2
数据帧存储在一个列表中,并且只进行了一次连接。这很有帮助,非常感谢你的想法!关于连接的观点很好,我应该抓住这一点:)