Nik*_*ido 6 python random data-mining bigdata data-stream
我正在尝试在 python 中重新创建一个函数来估计数据流的二阶矩。
\n\n正如乌尔曼书《海量数据集的挖掘》中所述,第二个时刻:
\n\n\n\n\n是 m_i \xe2\x80\x99s 的平方和。它有时被称为意外数,因为它衡量流中元素分布的不均匀程度。
\n
其中 m_i 元素是流中的单义元素。
\n\n例如,有这个玩具问题\\数据流:
\n\na, b, c, b, d, a, c, d, a, b, d, c, a, a, b\n
Run Code Online (Sandbox Code Playgroud)\n\n我们这样计算第二个时刻:
\n\n5^2 + 4^2 + 3^2 + 3^2 = 59\n
Run Code Online (Sandbox Code Playgroud)\n\n(因为\'a\'在数据流中出现了5次,\'b\'出现了4次,以此类推)
\n\n由于我们无法将所有数据流存储在内存中,因此我们可以使用一种算法来估计二阶矩:
\n\nAlon -Matias-Szegedy 算法(AMS 算法),使用以下公式估计二阶矩:
\n\nE(n *(2 * X.value \xe2\x88\x92 1))\n
Run Code Online (Sandbox Code Playgroud)\n\n其中 X 是流的单义元素,是随机选择的,X.value 是一个计数器,当我们读取流时,每当我们遇到 x 元素从我们选择它时起的另一个出现时,它就会加 1 。
\n\nn表示数据流的长度,“E”是平均值。
\n\n以前面的数据流为例,假设我们在数据流的第 13 个位置选择了“a”,在第 8 个位置选择了“d”,在第 3 个位置选择了“c”。我们还没有选择“b”。
\n\na, b, c, b, d, a, c, d, a, b, d, c, a, a, b\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15\n x x x\n
Run Code Online (Sandbox Code Playgroud)\n\n像这样选择,我们有:
\n\nX.element = "a" X.value = 2\nX.element = "c" X.value = 3\nX.element = "d" X.value = 2\n
Run Code Online (Sandbox Code Playgroud)\n\nAMS算法的估计为:
\n\n(15*(2 * 2 - 1) + 15*(2 * 3 - 1) + 15*(2 * 2 - 1))/3 = 55 \n
Run Code Online (Sandbox Code Playgroud)\n\n这非常接近之前计算的二阶矩的真实值(59)。
\n\n现在专注于我的代码,我编写了这个函数来计算“真实”二阶矩,通过向量(一维数组)和 for 模拟数据流:
\n\ndef secondMoment(vector):\n mydict = dict()\n for el in vector:\n if el not in mydict:\n mydict[el] = 1\n else:\n mydict[el] += 1\n return (sum([pow(value, 2) for key, value in mydict.items()]))\n
Run Code Online (Sandbox Code Playgroud)\n\n以及计算二阶矩估计的 AMS 函数:
\n\ndef AMSestimate(vector):\n lenvect = len(vector)\n elements = dict()\n for el in vector:\n if el in elements:\n elements[el] += 1\n elif random.choice(range(0, 10)) == 0:\n elements[el] = 1\n # E(n * (2 * x.value - 1))\n lendict = len(elements)\n estimateM2 = 0\n for key, value in elements.items():\n estimateM2 += lenvect * ((2 * value) - 1)\n print(lendict)\n if lendict > 0:\n return estimateM2/lendict\n
Run Code Online (Sandbox Code Playgroud)\n\n问题是,当我尝试计算一个小玩具问题(如上面的问题)的自尊时,这些值在某种程度上是正确的,但是当我尝试将向量扩展到 10000 个元素时,这些值是真实的第二时刻和尊重,是截然不同的。
\n\n我认为问题与我生成数据流的方式以及我决定选择 X.element 的方式有关。
\n\n那是:
\n\n[random.choice(string.ascii_letters) for x in range(size)]\n
Run Code Online (Sandbox Code Playgroud)\n\n用于生成随机向量\数据流
\n\n和
\n\nelif random.choice(range(0, 10)) == 0:\n elements[el] = 1\n
Run Code Online (Sandbox Code Playgroud)\n\n对于 X.element 选择(在上面的代码中,在 AMS 函数中完成)
\n\n对于随机向量\\数据流的生成,认为问题可能是由于向量缺乏“可变性”(string.ascii_letters 只有 52 个元素)。
\n这是个有趣的问题。
假设我们从
import random
import string
size = 100000
seq = [random.choice(string.ascii_letters) for x in range(size)]
Run Code Online (Sandbox Code Playgroud)
collections.Counter
那么第一个实现与您的类似(但请注意 的使用):
from collections import Counter
def secondMoment(seq):
c = Counter(seq)
return sum(v**2 for v in c.values())
>>> secondMoment(seq)
192436972
Run Code Online (Sandbox Code Playgroud)
不过,第二个实现与您的实现有更大的不同。请注意,首先找到随机索引。然后,仅在元素在其中一个索引处第一次出现(如果有)后才对元素进行计数:
from collections import defaultdict
def AMSestimate(seq, num_samples=10):
inds = list(range(len(seq)))
random.shuffle(inds)
inds = sorted(inds[: num_samples])
d = {}
for i, c in enumerate(seq):
if i in inds and c not in d:
d[c] = 0
if c in d:
d[c] += 1
return int(len(seq) / float(len(d)) * sum((2 * v - 1) for v in d.values()))
>>> AMSestimate(seq)
171020000
Run Code Online (Sandbox Code Playgroud)
编辑问题中的原始代码
在问题的代码中,考虑您的循环
for el in vector:
if el in elements:
elements[el] += 1
elif random.choice(range(0, 10)) == 0:
elements[el] = 1
Run Code Online (Sandbox Code Playgroud)
(小)采样有问题:硬编码概率为 0.1
还要考虑:
estimateM2 += lenvect * ((2 * value) - 1)
Run Code Online (Sandbox Code Playgroud)
这缺少除以采样元素的数量。
归档时间: |
|
查看次数: |
8200 次 |
最近记录: |