5

7 ビット値を持つ 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ます。

誰かが以前に似たようなことをしたことがありますか?

データセットを 2 つの形式でアップロードしました。

通常、index 順

マップされた値でグループ化

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))

テストデータとして。最初の列にインデックスがある場合は、ここでループ内のvalandの順序を切り替える必要があります。indexfor

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)

編集:おっと、行がありませんでした。修理済み。また、乗数は実際には 35 ではなく 36 でした。頭の中で (14, 86) を (15, 85) に丸めたに違いありません。

編集 2: テーブルの 4 分の 1 のみを保存する方法を示します。

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[...]代わりに最初の 2 つを作成します。

また、一番下の比較はあいまいです。これは 72 個の off-by-one エラーが発生するためです。これは、値が整数に丸められているためです。これらはすべて 2 つの値の中間にあるため、精度の低下はほとんどありません。

于 2011-08-06T04:06:15.337 に答える
2

閉じた後、私は遅ればせながらこの解決策を見つけました。「リスト内の連続する重複を識別するための最もPythonの方法は何ですか?」


注意:正弦のような周期的なfnを使用すると、テーブルの4分の1(つまり、256の値)または半分を格納するだけでうまくいき、ルックアップ時にインデックスに対して少し(固定小数点)の演算を実行できます。私がコメントしたように、さらに+50のオフセットを格納しない場合は、ルックアップ時間後に1つの整数を追加するという犠牲を払って、1ビット少なくする必要があります。したがって、79%の圧縮を簡単に実現できます。RLEはあなたにもっと与えるでしょう。fnにノイズがある場合でも、この一般的なアプローチで適切な圧縮を得ることができます。

agfが指摘したように、あなたのf(n) = 50 + 36*sin(72*pi*n/1024)=50 + g(n)は言います。

g(n) = 36*sin(72*pi*n/1024)したがって、n = 0..255の範囲についてのみ、の256個の値を表にします。

次に、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がアプローチを変更する前に、テーブルコンプレッサーアプローチを開始しました... itertoolsまたはリスト内包表記ソリューションを取得しようとしていました)

于 2011-08-06T05:54:58.703 に答える