【问题标题】:Matching overlapping Intervals (Dictionary) in Python在 Python 中匹配重叠区间(字典)
【发布时间】:2020-04-10 00:12:05
【问题描述】:

所以,我试图通过 python 解决一些随机问题,但被困在了逻辑上。这是问题所在: 我有多个视频以及它们的运行时间或运行长度。现在,我想维护 2 个列表。如果“已同步”,则列出 1 个列表,而另一个列表“未同步”。如果流的运行时间差异小于或等于 2 秒,我们决定“同步”。否则,它们不会同步。 如果我们有多个匹配的流,那么我们会采用匹配计数/数量最高的流。

我能够想出一个非常简单/缓慢的方法来分割和配对这些文件。但是,当我得到不同的数据集时,我的逻辑失败了。

这是我写的:

from datetime import datetime


# same_streams_old = {
  "Stream_1": "0:24:08.925167",
  "Stream_2": "0:24:08.990644",
  "Stream_3": "0:24:08.990644",
  "Stream_4": "0:24:12.118778",
  "Stream_5": "0:24:12.118778",
  "stream_6": "0:24:10.075066"
}
same_streams = {
  "Stream_1": "0:24:08.925167",
  "Stream_2": "0:24:12.118778",
  "Stream_3": "0:23:11.057711",
  "Stream_4": "0:24:12.118778",
  "Stream_5": "0:24:10.075066",
  "Stream_6": "0:24:08.990644"
}

keys = []
values = []
final_synced_video_files = []
final_non_synced_video_files = []

def get_time_diff(episode_run_time, episode_time):
    prev_episode_time = datetime.strptime(episode_run_time, '%H:%M:%S.%f')
    current_episode_time = datetime.strptime(episode_time, '%H:%M:%S.%f')

    time_diff = prev_episode_time - current_episode_time
    if current_episode_time > prev_episode_time:
        time_diff = current_episode_time - prev_episode_time

    return float(time_diff.seconds)

for key, value in same_streams.items():
    keys.append(key)
    values.append(value)
for key in keys:
    for _key in keys:
        if key != _key:
            diff = get_time_diff(same_streams[key], same_streams[_key])
            if diff <= 1.5:
                final_synced_video_files.append(key)
            else:
                pass

final_synced_video_files = list(set(final_synced_video_files))
final_non_synced_video_files = list(set(keys) - set(final_synced_video_files))

print("Synced Files : {0}".format(final_synced_video_files))
print("Non Synced Files : {0}".format(final_non_synced_video_files))

REPL Link

如您所见,匹配最多的流是stream_1stream_2stream_3stream_6

我写的还没有比较最大计数。然而,当我在做这件事时,我觉得这并不是真正有效的,也是解决这个问题的好方法。有人输入吗?

我尝试了一些关于重叠间隔的方法,然后得到了这个:REPL LINK

但是,如果您同时查看same_streams 字典,您会看到结果不是我想要实现的。对此的任何帮助都会很棒。

编辑: 我需要获取彼此相差 2 秒的流。例如 : 在 same_streams_old 中,期望的结果是流 1、2、3 和 6。但是,在字典 same_streams 中,期望的结果是流 2、4 和 5。

基本上,我需要查看哪些流可以“复用”在一起,哪些不能复用。

【问题讨论】:

  • 你能解释一下同步是什么意思吗?如果视频在同步列表中,它必须在列表中所有个其他视频的 2 秒内,还是至少一个?还是您的意思是在当前(实际)时间的 2 秒内?请同时解释一下匹配计数是什么。
  • 我只需要检查哪些流落入彼此的 2 秒标记。我会在问题中解释更多。

标签: python python-2.7 dictionary intervals overlapping-matches


【解决方案1】:

好的,所以下面的打印例程可能有点乱,但请耐心等待,它们仅用于调试,完成后您可能不需要它们。我知道这是一个很长的答案,但请仔细阅读..

简短回答:

您的问题可能来自这样一个事实,即当您从字符串转换为 datetime 时丢失了小数精度,它将秒数视为整数。但是,timedelta 对象有一个名为total_seconds() 的方法,它确实提供亚秒级分辨率。有关详细信息,请参阅this 或一般文档。只需将get_time_diff()return 语句更改为,

 return float(time_diff.total_seconds())

长答案的动机:

我不确定您想通过(非和)同步列表实现什么:您可能遇到流 a 与流 同步的情况b,虽然流cd同步,但cd ab 同步。它们都应该在您的synced_list 中吗?根据您要对列表执行的操作,我会考虑使用下面描述的同步矩阵,而不是您的列表,因为它们会丢失很多信息。

长答案:

让我介绍一下同步矩阵的概念。它将完整描述您的哪些流相互同步:

同步矩阵: 一个对称矩阵; 当且仅当流“i”和“j”时,矩阵中的单元格 (i,j) 为 TRUE 是同步的。否则,单元格值为 FALSE。 因此,对角线 (.) 是完全正确的,因为 流始终与自身同步。

     1 2 3 4
    ________
 1 | . T T F
 2 |   . T F
 3 |     . F
 4 |       .

“T”为真,“F”为假:显然从上面的示例图中,流 1 与流 2 同步,但与流 4 不同步。

对于您的示例,创建这样一个同步矩阵非常简单:

def is_synced(key_1, key_2):    
    max_allowed_desync = 1.5
    return max_allowed_desync > get_time_diff(same_streams[key_1], same_streams[key_2])

keys = same_streams.keys()
keys.sort() # VERY IMPORTANT, for the synced matrix to be constructed correctly; also make 's' uppercase for "stream_6" in OP.

# The complete matrix ..
full_sync_matrix = [[is_synced(k1,k2) for k2 in keys] for k1 in keys]

# We can optimize (memory usage) to only get the half matrix, since it's symmetric anyway; also excluding the diagonal.
half_sync_matrix = [[is_synced(k1,k2) for k2 in keys[curr+1:]] for curr,k1 in enumerate(keys)]

现在,让我们实现两个函数来打印/显示同步矩阵:

# Print a HALFED sync matrix
def print_sync_half_matrix(sm):
    string = ""
    for i,row in enumerate(sm):
        string += "\n" + " "*i*2
        for col in row:
            string += " " + ("T" if col else "F")
    print(string)

# Print a COMPLETE sync_matrix
def print_sync_full_matrix(sm):
    string = ""
    for row in sm:
        string += "\n"
        for col in row:
            string += " " + ("T" if col else "F")
    print(string)

那么,对于你提供的数据集,我得到:

same_streams = {
  "Stream_1": "0:24:08.925167",
  "Stream_2": "0:24:08.990644",
  "Stream_3": "0:24:08.990644",
  "Stream_4": "0:24:12.118778",
  "Stream_5": "0:24:12.118778",
  "Stream_6": "0:24:10.075066"
} # note that "Stream_6" previously had a lower case 's'!

print_sync_half_matrix(half_sync_matrix)
#   1 2 3 4 5 6
# 1   T T F F T
# 2     T F F T
# 3       F F T
# 4         T F
# 5           F

请记住,矩阵/打印中不包含对角线!这里的结果是正确的,并且符合输入的预期。让我们打印出一些时间差来获得更多的情报,

for stream_key in same_stream:
    print("Stream_1 ~ "+stream_key+": "+str(get_time_diff(same_streams["Stream_1"], same_streams[stream_key])))

.. 这很快表明您的时间戳已经失去了小数精度:

Stream_1 ~ Stream_5: 3.0
Stream_1 ~ Stream_4: 3.0
# ...

如果我们查看datetime 的文档,我们会发现它将时间视为秒的整数。因此,当您从 get_time_diff 函数中的 datetime 对象请求 seconds 时,会丢失微秒精度。只需从 deltatime 方法 .total_seconds() 请求秒数即可解决。

【讨论】:

  • 我可以通过减少微秒来生存。我现在不在家。稍后将尝试理解这一点并在我的代码中实现以获得最终同步的流。谢谢,我会检查一下。
  • @Xonshiz 实际上,如果您使用totals_seconds() 方法,而不是seconds 成员变量,您会得到第二部分的分数。我已经更新了答案..
  • 嘿!刚刚浏览了您的代码,这或多或少是我想要实现的。因此,我将获取您的代码并获取制作“同步对”所需的数据,然后对其进行检查。很快就会接受答案,也会为我想要实现的目标添加一个完整的解决方案。万分感谢!这给了我工作的方向。
  • 感谢您的指导。我采用了您的方法和一些代码并对其进行了更改以适合我的要求并做了我想要的。你可以在这里查看:repl.it/@Xonshiz/DecentWarpedActiveserverpages。我将使用最终代码提出一个新答案,以便我可以将其标记为答案。如果您有任何建议可以使我的最终代码变得更好,请更新您的答案,我会将其标记为答案。再次感谢!
  • 很高兴我能帮上忙。我建议注册StackExchange Code Review ... 在这里您可以发布正确运行的代码,但可以在优化时间和内存消耗、提高代码的可读性等方面获得帮助。
猜你喜欢
  • 2023-03-20
  • 2018-08-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-04-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多