5

我有一个包含 1024 个条目的大型数组,其中包含 7 位值range(14, 86)

这意味着存在多个具有相同值的索引范围。

例如,

consider the index range 741 to 795. It maps to 14
consider the index range 721 to 740. It maps to 15
consider the index range 796 to 815. It maps to 15

我想将此地图提供给一个 python 程序,该程序会输出以下内容:

if((index >= 741) and (index <= 795)) return 14;
if((index >= 721) and (index <= 740)) return 15;
if((index >= 796) and (index <= 815)) return 15;

一些groupby映射值的代码已准备好,但我很难使用pairwise.

以前有人做过类似的事情吗?

我以两种形式上传了数据集:

通常,按索引排序

按映射值分组

4

2 回答 2

3

如果您不介意由于四舍五入而略有不同的值,我可以为您很好地压缩它。

from math import pi, sin
interval=2*pi/1024
sinval=lambda i:int(round(sin(i*interval)*36))+50

这是实际执行您想要的操作的代码;它适用于

vals = sorted((sinval(i), i) for i in range(1024))

作为测试数据。如果您在第一列中有索引,则需要在此处切换循环valindex顺序。for

ranges, oldval, oldidx = [[0, 0]], 0, 0
for val, index in vals:
    if not (val == oldval and index == oldidx + 1):
        ranges[-1].append(oldidx)
        ranges.append([val, index])
    oldval, oldidx = val, index
ranges[-1].append(oldidx)
ranges.pop(0)
ifs = ('if((index >= {1}) and (index <= {2})) return {0};\n'.format(val, start, end)
            for val, start, end in ranges)
print ''.join(ifs)

编辑:哎呀,我错过了一条线。固定的。另外,您的乘数实际上是 36 而不是 35,我必须在我的脑海中将 (14, 86) 舍入到 (15, 85)。

编辑2:向您展示如何仅存储表格的四分之一。

from math import pi, sin

full = 1024
half = 512
quarter = 256
mag = 72
offset = 50

interval = 2 * pi / full

def sinval(i):
    return int(round(sin(i * interval) * (mag // 2))) + offset

vals = [sinval(i) for i in range(quarter)]

def sintable(i):
    if  i >= half + quarter:
        return 2 * offset - vals[full - i - 1]
    elif  i >= half:
        return 2 * offset - vals[i - half]
    elif i >= quarter:
        return vals[half - i - 1]
    else:
        return vals[i]

for i in range(full):
    assert -1 <= sinval(i) - sintable(i) <= 1

如果您从表中减去偏移量,只需制作前两个即可-vals[...]

此外,底部的比较是模糊的,因为我得到了 72 个错误。这仅仅是因为您的值被四舍五入为整数;它们都是您介于两个值之间的地方,因此准确性几乎没有下降。

于 2011-08-06T04:06:15.337 回答
2

关闭后,我很晚才发现这个解决方案“识别列表中连续重复项的最 Pythonic 方法是什么?” .


注意:使用像sine这样的周期性 fn ,您可以只存储四分之一(即 256 个值)或一半的表,然后在查找时对索引执行一点(定点)算术。正如我所评论的,如果您进一步不存储 +50 的偏移量,则您需要少一点,代价是在查找时间后增加一个整数。因此,79% 的压缩率很容易实现。RLE 会给你更多。即使 fn 有噪音,您仍然可以通过这种通用方法获得不错的压缩。

正如 agf 指出的那样,你的f(n) = 50 + 36*sin(72*pi*n/1024)=50 + g(n)说。

因此,将 的 256 个值制成表格g(n) = 36*sin(72*pi*n/1024),仅适用于 n=0..255 的范围

然后 f(n) 很容易通过以下方式计算:

if 0 <= n < 256, f(n) = 50 + g(n)
if 256 <= n < 512, f(n) = 50 + g(511-n)
if 512 <= n < 768, f(n) = 50 - g(n-512)
if 768 <= n < 1024, f(n) = 50 - g(1023-n)

无论如何,这是一个通用的表压缩器解决方案,它将生成(istart,iend,value)三元组。

我不知道如何使用列表推导和 itertools.takewhile() 以 Python 方式执行此操作;需要抛光。

#import itertools

table_="""
    0       50
    1       50
    ...
    1021    49
    1022    50
    1023    50""".split()

# Convert values to int. Throw away the indices - will recover them with enumerate()
table = [int(x) for x in table_[1::2]]

compressed_table = []
istart = 0
for i,v in enumerate(table):
    if v != table[i-1]:
        iend = i-1
        compressed_table.append((istart,iend,table[i-1]))
        istart = i
    else:
        continue # skip identical values
# Slightly ugly: append the last value, when the iterator was exhausted
compressed_table.append((istart,i,table[i]))

(注意,在 agf 改变他的方法之前,我开始使用 table-compressor 方法......试图获得一个 itertools 或 list-comprehension 解决方案)

于 2011-08-06T05:54:58.703 回答