6

9999 に設定されたデータ値がない 1 次元データ セットがあります。

this_array = [   4,    4,    1, 9999, 9999, 9999,   -5,   -4, ... ]

データなしの値を両側の最も近い値の平均に置き換えたいのですが、一部のデータなしの値にはデータなしの値と同様に最も近い値があるため、それらを置き換えるのは少し困難です。つまり、3 つのデータなしの値を -2 に置き換えたいと考えています。配列内の各スカラーを通過し、データがないかどうかをテストするループを作成しました。

for k in this_array:
    if k == 9999:
        temp = np.where(k == 9999, (abs(this_array[k-1]-this_array[k+1])/2), this_array[k])
    else:
        pass
this_array[k] = temp

ただし、if 関数を追加するか、k-1 の前または k+1 の後に値を取得する方法を追加する必要があります (それも 9999 に等しい場合)。

if np.logical_or(k+1 == 9999, k-1 == 9999):
    temp = np.where(k == 9999, (abs(this_array[k-2]-this_array[k+2])/2), this_array[k])

お分かりのように、このコードは乱雑になり、間違った値を取得したり、ネストされた if 関数が大量に作成されたりする可能性があります。データセット全体でかなり可変であるため、これを実装するよりクリーンな方法を知っている人はいますか?

要求に応じて: 最初および/または最後のポイントがデータではない場合、それらはできれば最も近いデータ ポイントに置き換えられます。

4

4 に答える 4

3

numpy 関数でこれを行うためのより効率的な方法があるかもしれませんが、itertools モジュールを使用した解決策は次のとおりです。

from itertools import groupby

for k, g in groupby(range(len(this_array)), lambda i: this_array[i] == 9999):
    if k:
        indices = list(g)
        new_v = (this_array[indices[0]-1] + this_array[indices[-1]+1]) / 2
        this_array[indices[0]:indices[-1]+1].fill(new_v)

最後の要素または最初の要素が である可能性が9999ある場合は、次を使用します。

from itertools import groupby

for k, g in groupby(range(len(this_array)), lambda i: this_array[i] == 9999):
    if k:
        indices = list(g)
        prev_i, next_i = indices[0]-1, indices[-1]+1
        before = this_array[prev_i] if prev_i != -1 else this_array[next_i]
        after = this_array[next_i] if next_i != len(this_array) else before
        this_array[indices[0]:next_i].fill((before + after) / 2)

2 番目のバージョンを使用した例:

>>> from itertools import groupby
>>> this_array = np.array([9999, 4, 1, 9999, 9999, 9999, -5, -4, 9999])
>>> for k, g in groupby(range(len(this_array)), lambda i: this_array[i] == 9999):
...     if k:
...         indices = list(g)
...         prev_i, next_i = indices[0]-1, indices[-1]+1
...         before = this_array[prev_i] if prev_i != -1 else this_array[next_i]
...         after = this_array[next_i] if next_i != len(this_array) else before
...         this_array[indices[0]:next_i].fill((before + after) / 2)
...
>>> this_array
array([ 4,  4,  1, -2, -2, -2, -5, -4, -4])
于 2012-12-18T22:02:40.383 に答える
1

私は次の行に沿って何かをします:

import numpy as np

def fill(arr, fwd_fill):
  out = arr.copy()
  if fwd_fill:
    start, end, step = 0, len(out), 1
  else:
    start, end, step = len(out)-1, -1, -1
  cur = out[start]
  for i in range(start, end, step):
    if np.isnan(out[i]):
      out[i] = cur
    else:
      cur = out[i]
  return out

def avg(arr):
  fwd = fill(arr, True)
  back = fill(arr, False)
  return (fwd[:-2] + back[2:]) / 2.

arr = np.array([   4,    4,    1, np.nan, np.nan, np.nan,   -5,   -4])
print arr
print avg(arr)

最初の関数は、すべての NaN を最も近い非 NaN に置き換えて、順方向または逆方向の塗りつぶしを実行できます。

それができたら、平均の計算は簡単で、2 番目の関数によって実行されます。

最初の要素と最後の要素をどのように処理したいかは言わないので、コードはそれらを切り取るだけです。

最後に、入力配列の最初または最後の要素が欠落している場合、関数は NaN を返す可能性があることに注意してください (この場合、平均の一部を計算するためのデータがありません)。

于 2012-12-18T22:15:56.570 に答える
0

わかりました、私はそれを自分で書かなければならないのではないかと心配していますnp.interp..scipy.interpolate

わかりました、読み直します... 線形補間はしたくないですか?もちろん、これはうまくいきません...ベクトル化された方法がいくつかあると確信していますが。

imort numpy as np
# data is the given array.
data = data.astype(float) # I cast to float, if you don't want that badly...
valid = data != 9999
x = np.nonzero(valid)[0]
replace = np.nonzero(~valid)[0]
valid_data = data[x]

# using np.interp, but I think you will find better things in scipy.interpolate
# if you don't mind using scipy.
data[replace] = np.interp(replace, x, valid_data,
                                   left=valid_data[0], right=valid_data[-1])
于 2012-12-18T22:58:59.957 に答える
0

これは、最初と最後が 9999 ではない再帰的な解決策です。再帰が少し深くなる可能性があるため、おそらくジェネレーターでクリーンアップできます。合理的なスタートです

def a(list, first, depth):    
  if ([] == list):
    return []
  car = list[0]
  cdr = list[1:]
  if (9999 ==  car):        
      return a(cdr, first, depth+1)
  if (depth != 0):
      avg = [((first + car) /2)] * depth
      return  avg + [car] + a(cdr, car, 0)
  else:
      return [car] + a(cdr, car, 0)



print a([1,2,9999, 4, 9999,9999, 12],0,0)
# => [1, 2, 3, 4, 8, 8, 12]
于 2012-12-18T22:45:34.040 に答える