【问题标题】:Best approach for matching a pattern of data in a dataframe column of a group?匹配组的数据框列中的数据模式的最佳方法?
【发布时间】:2021-07-04 23:00:18
【问题描述】:

标题有点啰嗦。我将尝试解释我想要解决的问题——在这一点上我很迷茫,所以我真的在寻找解决这个问题的最佳方法。我有一个数据框,其中的数据看起来像这样:

id_not_unique datetime binary_var
111111111 2020-08-26 15:44:58 1
111111111 2020-08-28 15:33:45 1
222222222 2020-07-12 11:21:09 1
222222222 2019-04-21 14:22:42 0

我想创建另一个列,我们称之为“标识符”,它本质上按 id_not_unique 分组,提供基于 binary_var 的唯一标识符。因此,对于每个唯一的 id_not_unique,我希望按升序排列日期时间——我可以这样做。但是,对于 binary_var 的某些模式,例如 1 或 [0, 1],“标识符”值将是唯一的。生成的数据集应如下所示:

id_not_unique datetime binary_var identifier
111111111 2020-08-26 15:44:58 1 x_1
111111111 2020-08-28 15:33:45 1 x_2
222222222 2019-04-21 14:22:42 0 x_3
222222222 2020-07-12 11:21:09 1 x_3

binary_var 序列可以是 [1]、[0, 1]、[0, 0, 1] 中的任何一个,基本上是任意数量的 0,后跟 1。目前,我按 id_not_unique 对数据帧进行分组,然后在订购日期时间,我正在遍历 binary_var 并检查它是什么值以及它在 index-1 处的值,以确定标识符应该是新的还是与 index-1 处的标识符相同。但这很慢,我的行数约为 300 万。那么还有其他更好的方法来解决这个问题吗?

【问题讨论】:

    标签: python pandas


    【解决方案1】:

    这是一个可以满足您要求的 sn-p。

    import pandas as pd
    import numpy as np
    import random
    
    
    # Taken from https://stackoverflow.com/a/50668285/1347611
    def pp(start, end, n):
        start_u = start.value//10**9
        end_u = end.value//10**9
        return pd.DatetimeIndex((
                10**9*np.random.randint(start_u, end_u, n,
                                        dtype=np.int64)).view('M8[ns]'))
    
    
    def get_unique_ids(n_rows):
        # Generating random data
        start = pd.to_datetime('2015-01-01')
        end = pd.to_datetime('2017-01-01')
        date_list = pp(start, end, n_rows)
        id_list = ['1111111', '2222222', '3333333']
        df = pd.DataFrame()
        df['datetime'] = date_list
        # Taken from https://note.nkmk.me/en/python-random-choice-sample-choices/
        df['id_not_unique'] = random.choices(id_list, k=n_rows)
        df['binary_var'] = random.choices([0, 1], k=n_rows)
        # Sorting the data
        df = df.sort_values(by=['id_not_unique', 'datetime', 'binary_var'])
        # Taken from https://stackoverflow.com/a/45846173/1347611
        # Ensuring the last value in a sequence is 1, as you mentioned
        df.loc[df.groupby('id_not_unique')['binary_var'].tail(1).index,
               'binary_var'] = 1
        # Taken from https://stackoverflow.com/a/53116526/1347611
        # Creating a unique value and a identifier per sequence
        df['binary_var_cumsum'] = df['binary_var'][::-1].cumsum()
        df['identifier'] = 'x_' +\
            (np.sign(np.abs(df['binary_var_cumsum'].diff().fillna(0))).cumsum() +
             1).astype(int).astype(str)
        df.index.name = 'index'
        return df
    
    
    if __name__ == '__main__':
        # Printing to check
        df = get_unique_ids(20)
        df.loc[:, ['id_not_unique', 'datetime', 'binary_var',
                   'identifier']]
    

    我生成了随机数据,因此每次运行的输出可能不同。但是,它将根据您要求的规格。其中一次运行的输出是:

          id_not_unique            datetime  binary_var identifier
    index                                                         
    9           1111111 2015-01-23 10:48:37           0        x_1
    3           1111111 2015-02-06 04:19:00           0        x_1
    10          1111111 2015-05-01 14:08:16           0        x_1
    8           1111111 2015-08-23 06:05:32           1        x_1
    6           1111111 2015-08-23 20:36:21           0        x_2
    2           1111111 2016-02-01 22:36:31           1        x_2
    19          1111111 2016-04-10 01:49:13           0        x_3
    7           1111111 2016-06-26 00:23:26           1        x_3
    17          1111111 2016-06-26 01:07:38           0        x_4
    18          1111111 2016-06-26 15:26:54           1        x_4
    1           2222222 2015-05-21 07:41:51           0        x_5
    15          2222222 2015-06-24 05:43:35           1        x_5
    14          2222222 2015-09-30 14:01:19           1        x_6
    4           2222222 2015-11-14 07:31:39           1        x_7
    12          2222222 2016-09-15 09:07:24           0        x_8
    11          2222222 2016-12-17 22:11:31           1        x_8
    16          3333333 2015-05-03 12:01:33           1        x_9
    5           3333333 2015-05-24 10:29:01           1       x_10
    13          3333333 2015-09-29 01:34:38           0       x_11
    0           3333333 2015-11-21 22:09:08           1       x_11
    

    300 万行耗时 11.1 秒。不知道你在寻找什么样的速度。

    %time dflarge = get_unique_ids(3000000)
    Wall time: 11.1 s
    

    【讨论】:

    • 实际上,我不确定这是否正确。运行后,binary_var 全部变为 1,标识符只是 x_(索引),所以它实际上并没有索引它。
    • 如果它不是机密的,你能给我一个相当大的数据样本,以便我检查吗?不知道我是否理解你的问题。
    • 对不起,数据来自一家公司。但我想你确实明白了,至少从输出来看,它是正确的。但是查看代码,这行 'df.loc[df.groupby('id_not_unique')['binary_var'].tail(1).index, 'binary_var'] = 1' 是否将最后一个值设置为 1 ?它将所有内容都设置为 1,因此标识符都是唯一的
    猜你喜欢
    • 1970-01-01
    • 2014-04-16
    • 2019-09-24
    • 1970-01-01
    • 2016-09-12
    • 2019-03-21
    • 2021-12-24
    • 2010-09-13
    • 2020-08-12
    相关资源
    最近更新 更多