您可能已经注意到我们现在在社区Wiki帖子上显示编辑摘要:
社区维基 220个修订版,48个用户
我还想向“最拥有”页面上显示的最终内容的用户显示剩余文本的百分比:
社区维基 220个修订,48个用户
kronoz 87%
是的,可能有顶级(n)“所有者”,但现在我想要前1名。
假设你有这个数据结构,一个按时间顺序排列的用户/文本对列表:
User Id Post-Text ------- --------- 12 The quick brown fox jumps over the lazy dog. 27 The quick brown fox jumps, sometimes. 30 I always see the speedy brown fox jumping over the lazy dog.
哪些用户最“拥有”最终文字?
我正在寻找一个合理的算法 - 它可以是一个近似值,它不一定是完美的 - 来确定所有者。理想情况下表示为百分比。
请注意,我们需要考虑编辑,删除和插入,因此最终结果合理且正确。您可以使用任何具有良好修订历史的stackoverflow帖子(不仅仅是重新标记,而是频繁更新帖子)作为测试语料库。这是一个很好的,有14个不同作者的15个修订版。谁是“所有者”?
https://stackoverflow.com/revisions/327973/list
点击“查看来源”以获取每个修订版的原始文本。
我应该警告你,一个纯粹的算法解决方案最终可能会成为Longest Common Substring Problem的一种形式。但正如我所提到的,如果它们运作良好,近似值和估计值也很好。
欢迎使用任何语言的解决方案,但我更喜欢
的解决方案SO上的帖子超过25次修订是非常罕见的。但它应该“感觉”准确,所以如果你对编辑进行观察,你就会同意最终的决定。我鼓励你在带有修订历史的堆栈溢出帖子上测试你的算法,看看你是否同意最终输出。
我现在已经部署了以下近似值,您可以在社区Wiki帖子中为每个新保存的修订版看到这些近似值
(对于常见的简单条件,例如1个修订版,只有1个作者等,也有一些保护条款。基于行的差异使得所有修订版的重新计算速度相当快;在典型的情况下,例如10个修订版,它是~50ms 。)
这在我的测试中运作得相当好。当你有几个人编辑的1或2个小帖子时,它会分解一点,但我认为这是不可避免的。接受Joel Neely的答案与我的精神最接近,并且赞同其他一切似乎可行的事情。
答案 0 :(得分:25)
我认为这个想法存在根本缺陷。
如果有人用糟糕的拼写和不清楚的例子写出精彩的分析,并且我复制了大量编辑,我创作了60%的作品吗?显然不是;结果是衍生品,其中大部分价值来自初始海报。基于字符或单词计数不可能有用的措施,但需要强大的AI级语义分析。
除此之外,根据文章的“所有权”寻求信用可能完全没有帮助和反维基。例如,在维基百科上,表现得好像拥有文章的人是最具破坏性的影响之一。
答案 1 :(得分:20)
早点看到你的推文。从327973链接的显示中可以看出,您已经有了单步差异。基于此,我将专注于多编辑组合:
A,原始海报拥有该职位的100%。
当B,第二张海报进行编辑时,例如90%的文本没有变化,所有权为A:90%,B:10%。
现在C,第三方,改变了50%的文字。 (答:45%,B:5%,C:50%)
换句话说,当海报进行编辑以使x%改变且y =(100-x)%不变时,该海报现在拥有文本的x%,并且所有先前的所有权都乘以y%。
为了让它变得有趣,现在假设......
A进行20%的编辑。然后A拥有“新”20%,剩余所有权现在乘以80%,留下(A:36%,B:4%,C:40%)。因此,“净”所有权(A:56%,B:4%,C:40%)。
将此应用于您的样本(327973),所有内容均四舍五入到最接近的百分比:
版本0:原帖。
版本1:您当前的差异工具显示纯文本添加,因此所有这些字符都属于第二张海报。
版本2:差异显示单词的替换。新单词属于第三张海报,其余文字属于之前的海报。
版本3:仅标记编辑。由于你的问题是关于文本的,我忽略了这些标签。
第4版:添加文字。
我希望这足以让人理解这个提议。它确实有一些限制,但我在你的声明中将这些限制在可接受的近似值中。 ; - )
它强行在所有先前所有者之间分配变更的影响。如果A帖子,B做了纯粹的添加,而C编辑了B添加的一半,这种简单的方法只是在整个帖子中应用C的所有权,而不试图解析哪个以前的所有权发生了最大的改变。
它考虑了添加或更改,但没有为删除提供任何所有权信用,因为删除器会将剩余文本添加0%。您可以将此视为错误或功能。我选择了2号门。
更新:更多关于上述问题#1。我认为,完全跟踪编辑的帖子部分的所有权将需要两件事之一(网页的边距不足以进行正式证明;):
更改文本的存储方式以反映文本各个部分的所有权(例如A拥有单词1-47,B拥有单词48-59,A拥有单词60-94,......),我的提案中对每个部分的“剩余多少”方法,以及更新部分所有权数据。
考虑从头到尾的所有版本(实际上,即时重新计算部分所有权数据)。
所以这是一个很好的例子,可以在快速和肮脏的近似(以精度为代价),整个数据库的更改(以空间为代价)之间进行权衡,或者每次计算都要看在整个历史中(以时间为代价)。
答案 2 :(得分:5)
答案 3 :(得分:4)
如果我正确地理解了您的问题,看起来您正在尝试做IBM在Wikipedia研究项目中所做的工作。即,查看哪些文本对其他用户最常接受的文本的修订以及整体文本如何随时间变化。该项目的名称为history flow,history flow - how it works对其算法的工作原理进行了很好的概述。
答案 4 :(得分:4)
如何简单地计算每个人对先前版本的编辑的Levenshtein distance。然后将每个用户的距离分数相加,并计算用户所有用户距离分数之和的百分比。
答案 5 :(得分:3)
离开我的头顶我会做这样的事情:
答案 6 :(得分:3)
如果你想在Python difflib
中实现/利用差异算法,这将有效 - 在任何情况下你都可能需要做某种差异。此代码段调用最多文本的用户称为赢家。
请原谅我的硬编码。
#!/usr/bin/env python
import collections
import difflib
import logging
import pprint
import urllib2
import re
class OwnageDeterminer(object):
add_coefficient = 1
remove_coefficient = .5
def __init__(self, edits):
self.edits = edits
self.counts_by_username = {}
def __call__(self):
edits, counts_by_username = self.edits, self.counts_by_username
for i, edit in enumerate(edits):
username = edit['username']
unique_counts = {'added': 0, 'removed': 0}
existing_text = edits[i-1]['text'] if i > 0 else ''
new_text = edits[i]['text']
for char_diff in difflib.ndiff(existing_text, new_text):
if char_diff.startswith('+'):
unique_counts['added'] += 1
elif char_diff.startswith('-'):
unique_counts['removed'] += 1
user_counts = counts_by_username.get(username, collections.defaultdict(int))
user_counts['removed'] += self.remove_coefficient * unique_counts['removed']
user_counts['added'] += self.add_coefficient * unique_counts['added']
counts_by_username[username] = user_counts
winner = None
winning_score = 0
score_by_username = {}
for username, counts in counts_by_username.iteritems():
score = counts['removed'] + counts['added']
if score > winning_score:
winner = username
winning_score = score
score_by_username[username] = score
logging.debug('Scores: %s', pprint.pformat(score_by_username))
return winner
if __name__ == '__main__':
logging.basicConfig(level=logging.DEBUG)
site = urllib2.urlopen('http://stackoverflow.com/revisions/327973/list')
contents = site.read()
regex = re.compile(r'(/revisions/viewmarkup/\d+).*?/users/\d+/([\w-]+)',
re.MULTILINE|re.DOTALL)
revisions = regex.findall(contents)
print revisions
edits = []
for reluri, username in sorted(revisions, key=lambda t: t[0]):
text = urllib2.urlopen('http://stackoverflow.com{0}'.format(reluri)).read()
edit = {'username': username, 'text': text}
edits.append(edit)
od = OwnageDeterminer(edits)
print od()
输出:
DEBUG:root:Scores: {'blorgbeard': 0.5,
'dave-markle': 0.5,
'dbr': 1172.0,
'gatekiller': 69.5,
'joseph-ferris': 0.0,
'lkessler': 0.0,
'mark-harrison': 592.0,
'mdb': 3.0,
'onebyone-livejournal-com': 0.0,
'paul-oyster': 482.0,
'rob-wells': 0.0,
'simucal': 1070.5,
'skiphoppy': 0.0,
'thesoftwarejedi': 701.0}
dbr
关于复杂性的
时间:基本的Ratcliff-Obershelp 算法是最差的立方时间 案例和二次时间 预期案例。 SequenceMatcher是 最坏情况下的二次时间和 具有预期的案例行为依赖性 在一个复杂的方式上有多少 序列共有的元素; 最佳案例时间是线性的。
另一个好处是,此获胜者计算是线性的,因此您可以缓存原始结果并对新编辑执行增量更新,尽管初始化负载很大。
答案 7 :(得分:3)
没有人拥有它。授予所有权违反了“社区维基”的精神,并可能导致适得其反的编辑战争。
答案 8 :(得分:2)
一个问题是删除字符是否与添加字符一样有效。使用Diff可能效果很好,但并不总是如此,添加最多的人是最有效的编辑器(有些人可以用10个字符写出其他人用来编写页面的内容)。
所以我认为你有两个因素:
因此,我很想写一些简单地将添加/删除的单词映射到积分的东西。除此之外还有某种品质因素(这必须是一个外部参数),然后可以在排序中使用组合值。
你可以根据项目编辑之前的距离来产生某种原始的“品质因子”。因此,如果我写的内容在第12次编辑之前没有改变,那么它就不会太错误(相对于质量较低的东西,只要它被添加就会改变)。
答案 9 :(得分:2)
这是一个维基 - 为什么不让每个编辑选择他或她改变的意义?提供类似......的下拉列表。
请对您的编辑进行限定:
然后使用合并后的回复来估算所有权。
答案 10 :(得分:2)
这个想法怎么样?
关键在于经过一定程度的改变后谁拥有它并不重要。我同意用户的说法,试图将“所有者”分配给维基内容会产生反作用。
答案 11 :(得分:1)
字符数是棘手的问题。
怎么样:
Break latest revision into a set of sentences.
//Sentence is any text fragment surrounded by punctuation
For each Sentence
Find which user created that sentence.
Add 1 to the user who created the sentence
Add 1 to the number of sentences
For Each user
% ownership = Count for that user / Number of sentences.
查找哪个用户创建了该句子。
如果你想要完全匹配,将句子与修订相匹配很容易,但我对部分匹配更满意。
要做这个部分匹配...
从句子片段中删除常用单词,并在每个修订的剥离版本中搜索该剥离的片段。最早的打击是所有者写的句子。
选项:(而不是常用字词剥离)
剥离常用词
您已经为搜索执行此操作,因此库等已经存在。即使你使用别人的公式,你也许应该在开始之前使用CommonWordStrip每个版本。
答案 12 :(得分:1)
解决此问题的关键是获取有关编辑内容的额外信息。此媒介中提供的额外信息是对问题的投票和回复率。因此,如果有人进行编辑,导致问题得到很多赞成,评论和回复,那么他们的编辑非常有价值。特殊情况可能存在一个全新的未答复问题,该问题在很长一段时间内都会被编辑。
您应该使用Levenshtein距离算法查看帖子的更改量,然后根据问题在编辑后收到的投票,评论和答案的数量来加权编辑。
Let n = total revisions
Let m = the revision number of a poster
Let post[it] = array with text of post at revision 'it'
Let votes[it] = votes that revision 'it' received (also add bonus for comments/answers)
value = 0
for (it = m; it < n; ++it) {
value += (Levenshtein(post[it-1], post[m]) / average_length_post) * (votes[it])
}
如果您计算每个帖子的值,则帖子的所有权是该用户所有修改的总值除以该帖子的所有编辑值的总和。
答案 13 :(得分:0)
不确定是否可行,但您可以计算添加的字符数。
示例:
如果您还原,则还应恢复为之前的用户/字符数。
但是...... 也许只是简单而公平地命名原始海报......
第二个想法,我编辑了很多,但我从不认为自己是tekst的“所有者”因为我只是改变了演示文稿(格式和语法)而不是内容。
答案 14 :(得分:0)
最初的概念必须给予重视。 拼写纠正必须给予重量。 语法/结构必须给予重量。 措辞必须给予重量。 简洁必须给予重视。 等...
权衡是唯一公平的方式,但也无法确定。