20

対数的に間隔を空けた100点のみのスライスを取得したい10,000ポイントのベクトルがあるとします。インデックスの整数値を取得する関数が必要です。これは、単純に+ログスペースを使用し、重複を取り除く単純なソリューションです。

def genLogSpace( array_size, num ):
    lspace = around(logspace(0,log10(array_size),num)).astype(uint64)
    return array(sorted(set(lspace.tolist())))-1

ls=genLogspace(1e4,100)

print ls.size
>>84
print ls
array([   0,    1,    2,    3,    4,    5,    6,    7,    8,    9,   10,
         11,   13,   14,   15,   17,   19,   21,   23,   25,   27,   30,
         33,   37,   40,   44,   49,   54,   59,   65,   71,   78,   86,
         94,  104,  114,  125,  137,  151,  166,  182,  200,  220,  241,
        265,  291,  319,  350,  384,  422,  463,  508,  558,  613,  672,
        738,  810,  889,  976, 1071, 1176, 1291, 1416, 1555, 1706, 1873,
       2056, 2256, 2476, 2718, 2983, 3274, 3593, 3943, 4328, 4750, 5213,
       5721, 6279, 6892, 7564, 8301, 9111, 9999], dtype=uint64)

16の重複があったので、今は84ポイントしかないことに注意してください。

出力サンプルの数がnumであることを効率的に保証するソリューションを誰かが持っていますか?この特定の例では、121と122のnumの入力値は、100の出力ポイントを提供します。

4

4 に答える 4

19

これは少し注意が必要です。常に対数間隔の数値を取得できるとは限りません。あなたの例のように、最初の部分はかなり線形です。あなたがそれで大丈夫なら、私は解決策を持っています。しかし、解決策として、重複がある理由を理解する必要があります。

対数目盛は次の条件を満たす。

s[n+1]/s[n] = constant

rこの定数を。と呼びましょうration範囲間のこれらの数値については、次のよう1...sizeになります。

1, r, r**2, r**3, ..., r**(n-1)=size

だからこれはあなたに与えます:

r = size ** (1/(n-1))

あなたの場合、、は、n=100size=10000なりrます~1.0974987654930561。つまり、で始まる場合1、次の数値はになり、1.0974987654930561次に再び丸められ1ます。したがって、あなたの複製。この問題は少数の場合に発生します。十分に大きい数の後で、比率を掛けると、異なる丸められた整数になります。

これを念頭に置いて、最善の策は、特定のポイントまで連続する整数を追加して、この比率との乗算が問題にならないようにすることです。次に、対数スケーリングを続行できます。次の関数はそれを行います:

import numpy as np

def gen_log_space(limit, n):
    result = [1]
    if n>1:  # just a check to avoid ZeroDivisionError
        ratio = (float(limit)/result[-1]) ** (1.0/(n-len(result)))
    while len(result)<n:
        next_value = result[-1]*ratio
        if next_value - result[-1] >= 1:
            # safe zone. next_value will be a different integer
            result.append(next_value)
        else:
            # problem! same integer. we need to find next_value by artificially incrementing previous value
            result.append(result[-1]+1)
            # recalculate the ratio so that the remaining values will scale correctly
            ratio = (float(limit)/result[-1]) ** (1.0/(n-len(result)))
    # round, re-adjust to 0 indexing (i.e. minus 1) and return np.uint64 array
    return np.array(list(map(lambda x: round(x)-1, result)), dtype=np.uint64)

Python 3の更新:最後の行はPython2にあり return np.array(map(lambda x: round(x)-1, result), dtype=np.uint64) ました

これを使用したいくつかの例を次に示します。

In [157]: x = gen_log_space(10000, 100)

In [158]: x.size
Out[158]: 100

In [159]: len(set(x))
Out[159]: 100

In [160]: y = gen_log_space(2000, 50)

In [161]: y.size
Out[161]: 50

In [162]: len(set(y))
Out[162]: 50

In [163]: y
Out[163]:
array([   0,    1,    2,    3,    4,    5,    6,    7,    8,    9,   11,
         13,   14,   17,   19,   22,   25,   29,   33,   38,   43,   49,
         56,   65,   74,   84,   96,  110,  125,  143,  164,  187,  213,
        243,  277,  316,  361,  412,  470,  536,  612,  698,  796,  908,
       1035, 1181, 1347, 1537, 1753, 1999], dtype=uint64)

結果がどの程度対数であるかを示すために、次の出力の片対数プロットを示しますx = gen_log_scale(10000, 100)(ご覧のとおり、左側は実際には対数ではありません)。

ここに画像の説明を入力してください

于 2012-09-14T09:35:25.093 に答える
4

ログ間隔のポイントを直接生成するというAvarisの回答のアプローチは、間違いなく進むべき道です。logspaceしかし、私はあなたが望むものを得るために渡すために適切な値を選ぶ方法を見るのは面白いだろうと思いました。

によって生成される配列の値は、0≤i < nlogspace(0, k, n)の場合の数値10 ik  /(n -1)です。

>>> numpy.logspace(0, 2, 10)
array([   1.        ,    1.66810054,    2.7825594 ,    4.64158883,
          7.74263683,   12.91549665,   21.5443469 ,   35.93813664,
         59.94842503,  100.        ])
>>> [10 ** (i * 2 / 9.0) for i in xrange(10)]
[1.0, 1.6681005372000588, 2.7825594022071245, 4.641588833612778,
 7.742636826811269, 12.91549665014884, 21.544346900318832,
 35.938136638046274, 59.94842503189409, 100.0]

このシーケンスは、値が単位間隔よりも近い最初のセグメントで構成され(したがって、最も近い整数に丸められると重複する可能性があります)、値が単位間隔よりも広く、存在しないセグメントが続きます。重複します。

>>> ' '.join('{:.2f}'.format(10 ** (i * 2 / 19.0)) for i in xrange(20))
'1.00 1.27 1.62 2.07 2.64 3.36 4.28 5.46 6.95 8.86 11.29 14.38 18.33 23.36
 29.76 37.93 48.33 61.58 78.48 100.00'
>>> [int(0.5 + 10 ** (i * 2 / 19.0)) for i in xrange(20)]
[1, 1, 2, 2, 3, 3, 4, 5, 7, 9, 11, 14, 18, 23, 30, 38, 48, 62, 78, 100]

値の間隔はsi)= 10 iK − 10 i −1)Kです。ここで、K = k /(n − 1)です。mをsm) ≥1となる最小値とします(上記の例ではm = 7)。次に、重複を削除すると、正確に⌊½+ 10 (m -1K⌋ + n −mが残ります。数字。

代数のビットは見つけます:

m = ⌈− log(1 − 10 − <em> K / Klog10⌉</p>

それを確認しましょう。

from math import ceil, floor, log

def logspace_size(k, n):
    """
    Return the number of distinct integers we'll get if we round
    `numpy.logspace(0, k, n)` to the nearest integers and remove
    duplicates.

    >>> logspace_size(4, 100)
    84
    >>> logspace_size(4, 121)
    100
    >>> from numpy import around, logspace
    >>> all(logspace_size(k, n) == len(set(around(logspace(0, k, n))))
    ...     for k in xrange(1,10) for n in xrange(2,100))
    True
    """
    K = float(k) / (n - 1)
    m = int(ceil(- log(1 - 10 ** -K) / (K * log(10))))
    if m < n:
        return int(0.5 + 10 ** ((m - 1) * K)) + n - m
    else:
        return int(0.5 + 10 ** ((n - 1) * K))

doctestsは合格なので、これは私には良さそうです。だからあなたがする必要があるのはnそのようなものを見つけることlogspace_size(4, n) == 100です。これは、バイナリチョップまたは次のいずれかのscipy.optimize方法で実行できます。

>>> f = lambda x, k, n:(logspace_size(k, x) - n)**2
>>> int(round(scipy.optimize.fmin(f, 100, args=(4,100), xtol=0.5, ftol=0.5)[0]))
Optimization terminated successfully.
         Current function value: 0.015625
         Iterations: 8
         Function evaluations: 17
122
于 2012-09-14T10:15:12.650 に答える
1

Python(numpyの使用を省略)で対数間隔の系列(10を底とする)を取得するための簡単な方法を検索しているときに、ここに到達しました。しかし、あなたのソリューションは、私の非常に単純な要求に対して複雑になる方法です。

def logarithmic_decade(numbers_per_decade, offset=10):
    for n in xrange(numbers_per_decade):
        yield offset * 10.0 ** (n / float(numbers_per_decade))

リストを取得するにはジェネレーターなので、次のことを行う必要があります。

numbers = list(logarithmic_decade(5))
print numbers
[10.0, 15.848931924611136, 25.118864315095802, 39.81071705534972, 63.095734448019336]

for p, n in zip(numbers, numbers[1:] + [100]):
    print 'prev = {p:.2f}, next = {n:.2f}, next/prev = {rt:.4f}'.format(p=p, n=n, rt=n / p)

次の出力を提供します。

prev = 10.00, next = 15.85, next/prev = 1.5849
prev = 15.85, next = 25.12, next/prev = 1.5849
prev = 25.12, next = 39.81, next/prev = 1.5849
prev = 39.81, next = 63.10, next/prev = 1.5849
prev = 63.10, next = 100.00, next/prev = 1.5849
于 2016-04-22T22:38:34.297 に答える
0

1と1e4の間の単一ラインソリューション:

y = [(lambda x:int(x))(tmp) for tmp in np.logspace(0,4, 10)]
于 2020-08-30T14:46:36.760 に答える