【问题标题】:Relationship based on time基于时间的关系
【发布时间】:2021-10-21 12:06:58
【问题描述】:

我正在尝试在两个相关的数据框之间创建关系,但没有创建关系的键。这是我的问题的布局: 我使用的第一个数据框是关于人们何时进入游乐园的信息。在这个游乐园里,人们可以在公园里逗留多日。所以这个数据框的结构是

id name date
0 John Smith 07-01-2020 10:13:24
1 John Smith 07-22-2020 09:47:04
4 Jane Doe 07-22-2020 09:47:04
2 Jane Doe 06-13-2020 13:27:53
3 Thomas Wallace 07-08-2020 11:15:28

因此人们可能会访问公园一次或多次(假设名称是人们的唯一标识符)。对于另一个数据框,数据是他们在公园期间进行的游乐设施。所以这个数据框的结构是

name ride date
John Smith Insanity 07-01-2020 13:53:07
John Smith Bumper Cars 07-01-2020 16:37:29
John Smith Tilt-A-Whirl 07-02-2020 08:21:18
John Smith Insanity 07-22-2020 11:44:32
Jane Doe Bumper Cars 06-13-2020 14:14:41
Jane Doe Teacups 06-13-2020 17:31:56
Thomas Wallace Insanity 07-08-2020 13:20:23

通过这两个数据框,我想获取与他们在访问期间进行的游乐设施相关联的访问 ID。所以这个例子中想要的输出是

id name ride date
0 John Smith Insanity 07-01-2020 13:53:07
0 John Smith Bumper Cars 07-01-2020 16:37:29
0 John Smith Tilt-A-Whirl 07-02-2020 08:21:18
1 John Smith Insanity 07-22-2020 11:44:32
2 Jane Doe Bumper Cars 06-13-2020 14:14:41
2 Jane Doe Teacups 06-13-2020 17:31:56
3 Thomas Wallace Insanity 07-08-2020 13:20:23

我考虑解决此问题的方法是遍历访问,然后如果名称匹配,则将 id 添加到乘车,乘车发生在访问期间/之后,并且时间增量是最小的差异(使用较大的初始时间增量,然后更新与该差异的最小差异)。如果不满足这些条件,则保持相同的值。考虑到这个过程,这是我在代码中的思考过程:

rides['min_diff'] = pd.to_timedelta(365, unit='day')
rides['id'] = -1
for index, row in visits.iterrows():
    rides['id'], rides['min_diff'] = np.where((rides['name'] == row['name']) & (
                                               rides['date'] >= visits['date']) & (
                                               (rides['date'] - row['date']) < rides['min_diff']),
                                               (row['id'], rides['date'] - row['date']),
                                               (rides['id'], rides['min_diff'))

不幸的是,由于形状不匹配(以及尝试跨多个列分配值,我不知道该怎么做),这没有执行,但这是一般的想法。我不确定这到底是如何实现的,所以如果有人有解决方案,我将不胜感激。

【问题讨论】:

    标签: python pandas datetime


    【解决方案1】:

    试试apply()asof()

    df1 = df1.set_index("date").sort_index() #asof requires a sorted index
    df2["id"] = df2.apply(lambda x: df1[df1["Name"]==x["Name"]]["id"].asof(x["date"]), axis=1)
    
    >>> df2
                 Name          ride                date  id
    0      John Smith      Insanity 2020-07-01 13:53:07   0
    1      John Smith   Bumper Cars 2020-07-01 16:37:29   0
    2      John Smith  Tilt-A-Whirl 2020-07-02 08:21:18   0
    3      John Smith      Insanity 2020-07-22 11:44:32   1
    4        Jane Doe   Bumper Cars 2020-06-13 14:14:41   2
    5        Jane Doe       Teacups 2020-06-13 17:31:56   2
    6  Thomas Wallace      Insanity 2020-07-08 13:20:23   3
    

    【讨论】:

    • 这在日期没有重叠的情况下有效。不幸的是,我正在使用的数据很容易具有相同的日期和时间,所以我不确定这是否可行
    • 那么请提供一个更具代表性的样本,这不起作用。
    • 我添加了一行,因此这将成为解决方案的冲突。我想指出的是,我的实际数据比这个大得多,所以效率很重要。由于机密性,我无法包含真实数据。我必须想出一个适用于我的问题的方案,并且我必须编造假数据,这需要时间,所以希望大家能更加理解为什么会这样。
    【解决方案2】:

    认为这可以满足您的需求。 id 不是您指定的顺序,但它们确实代表了具有您请求的逻辑的访问 id。

    merged = pd.merge(df1, df2, how="right", left_on=['date', 'name'], right_on=['name', 'ride'])[['name_y', 'ride', 'date_y']]
    merged['ymd'] = pd.to_datetime(merged.date_y).apply(lambda x: x.strftime('%Y-%m-%d'))
    merged['id'] = merged.groupby(['name_y', 'ymd']).ngroup()
    merged.drop('ymd', axis=1, inplace=True)
    merged.columns = ['name', 'ride', 'date', 'id']
    merged.sort_values(by='id', inplace=True)
    print(merged)
    

    输出:

                 name           ride                 date  id
    4        Jane Doe   Bumper Cars   06-13-2020 14:14:41   0
    5        Jane Doe       Teacups   06-13-2020 17:31:56   0
    0      John Smith      Insanity   07-01-2020 13:53:07   1
    1      John Smith   Bumper Cars   07-01-2020 16:37:29   1
    2      John Smith  Tilt-A-Whirl   07-02-2020 08:21:18   2
    3      John Smith      Insanity   07-22-2020 11:44:32   3
    6  Thomas Wallace       Insanity  07-08-2020 13:20:23   4
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-03-24
      • 1970-01-01
      • 1970-01-01
      • 2013-08-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-05-13
      相关资源
      最近更新 更多