我有一个包含1024个条目的大型数组,这些条目在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
编写表达式时遇到了困难。
之前有人做过类似的事吗?
我已经以两种形式上传了数据集:
通常,ordered by index。
答案 0 :(得分: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))
作为测试数据。如果您在第一列中有索引,则需要在val
循环中切换index
和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个一个一个错误。这只是因为你的值四舍五入为整数;它们都是你在两个值之间的中间位置,因此准确度几乎没有降低。
答案 1 :(得分:2)
关闭后,我迟到了"What's the most Pythonic way to identify consecutive duplicates in a list?"。
注意:使用像 sine 这样的周期性fn,只需存储四分之一(即256个值)或表的一半,然后执行一个小的(定点)算术就可以了查找时的索引。正如我评论的那样,如果你进一步不存储+50的偏移量,你需要少一点,这需要在查找时间之后增加一个整数。因此,可以轻松实现79%的压缩。 RLE会给你更多。即使fn有噪音,你仍然可以通过这种通用方法获得适当的压缩。
正如agf指出的那样,你的f(n) = 50 + 36*sin(72*pi*n/1024)
= 50 + g(n)
,比方说。
所以将g(n) = 36*sin(72*pi*n/1024)
的256个值制成表格,仅适用于范围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)三元组。
我使用list comprehensions和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改变他的方法之前开始使用表压缩器方法......试图获得一个itertools或list-comprehension解决方案)