1

これは一種の厄介な質問です...

これの前に、ここで月次データの正規化について質問がありました: 引き伸ばされたグラフのX値を生成する方法は?

私は良い答えを得ました、そしてそれはうまくいきます、唯一の問題は今私が28で月のX値に対して31日で1ヶ月のX値をチェックする必要があるということです。

したがって、私の質問は次のようになります。次のような2つのパラメータセットがある場合:

x    |    y           x2    |     y2

1    |    10        1.0    |     10
2    |    9         1.81    |     9.2
3    |    8         2.63    |     8.6
4    |    7         3.45    |     7.8
5    |    6         4.27    |     7
6    |    5         5.09    |     6.2
7    |    4         5.91    |     5.4
8    |    3         6.73    |     4.2
9    |    2         7.55    |     3.4
10   |    1         8.36    |     2.6
                    9.18    |     1.8
                    10.0    |     1.0

ご覧のとおり、一般的な傾向はこれら2つのデータセットで同じです。ただし、これらの値を相互相関関数(一般的な目標)で実行すると、データセットのサイズが2つ異なるため、これを反映していないものが返されます。

これの実際の例は、たとえば、1日に何マイル走るかを追跡している場合です。

2月(28日)の最初の週は、毎日1マイル走ります。2週目は、毎日2マイル走ります。

3月(31日)も同じことをしますが、1マイルで8日間、2マイルで8日間、3マイルで8日間、4マイルで7日間走ります。

次の関数による相関係数は、ほぼ正確に1である必要があります。

class CrossCorrelator {

    def variance = { x->
        def v = 0
        x.each{ v += it**2}
        v/(x.size()) - (mean(x)**2)
    }

    def covariance = {x, y->
        def z = 0
        [x, y].transpose().each{ z += it[0] * it[1] }
        (z / (x.size())) - (mean(x) * mean(y))
    }
    def coefficient = {x, y->
        covariance(x,y) / (Math.sqrt(variance(x) * variance(y)))
    }
}
def i = new CrossCorrelator()
i.coefficient(y values, y2 values)

データセットを見るだけで、1、2、3、4、5、6、7、8、9、および10の値を取得した場合、グラフはまったく同じになるように見えます。関数は次のようになります。より正確な結果を生成します。

ただし、長さが同じではないため、ゆがんでいます。

12値データセットの整数の値を特定する方法はありますか?私はそれを行う簡単な方法を見つけていませんが、これは信じられないほど役に立ちます。

前もって感謝します、

5

編集:リクエストに応じて、グラフのX値を生成するコードは次のとおりです。

def x  = (1..12) 
def y = 10

change = {l, size ->
    v = [1]
    l.each{
        v << ((((size-1)/(x.size() - 1)) * it) + 1)
    }
    v -= v.last()
    return v
}


change(x, y)

編集:別のリクエストに従ってコードが機能していません:

def normalize( xylist, days ) {
  xylist.collect { x, y -> [ x * ( days / xylist.size() ), y ] }
}

def change = {l, size ->
    def v = [1]
    l.each{
        v << ((((size-1)/(l.size() - 1)) * it) + 1)
    }
    v -= v.last()
    return v
}

def resample( list, min, max ) {
   // We want a graph with integer points from min to max on the x axis
  (min..max).collect { i ->
    // find the values above and below this point
    bounds = list.inject( [ a:null, b:null ] ) { r, p ->
      // if the value is less than i, set it in r.a
      if( p[ 0 ] < i )
        r.a = p
      // if it's bigger (and we don't already have a bigger point)
      // then set it into r.b
      if( !r.b && p[ 0 ] >= i )
        r.b = p
      r
    }
    // so now, bounds.a is the point below our required point, and bounds.b
    // Deal with the first case (where a is null, because we are at the start)
    if( !bounds.a )
      [ i, list[ 0 ][ 1 ] ]
    else {
      // so work out the distance from bounds.a to bounds.b
      dist = ( bounds.b[0] - bounds.a[0] )
      // And how far the point i is along this line
      r = ( i - bounds.a[0] ) / dist
      // and recalculate the y figure for this point
      y = ( ( bounds.b[1] - bounds.a[1] ) * r ) + bounds.a[1]
      [ i, y ]
    }
  }
}

def feb = [9, 3, 7, 23, 15, 16, 17, 18, 19, 13, 14, 8, 13, 12, 15, 6, 7, 13, 19, 12, 7, 3, 4, 15, 6, 17, 8, 19]
def march = [8, 12, 4, 17, 11, 15, 12, 8, 9, 13, 12, 7, 3, 4, 8, 2, 17, 19, 21, 12, 12, 13, 14, 15, 16, 7, 8, 19, 21, 14, 16]

//X and Y Values for February
z = [(1..28), change(feb, 28)].transpose()

//X and Y Values for March stretched to 28 entries
o = [(1..31), change(march, 28)].transpose()

o1 = normalize(o, 28)

resample(o1, 1, 28)

o変数宣言の「march」を(1..31)に切り替えると、スクリプトは正常に実行されます。「march」を使用しようとすると、「java.lang.NullPointerException:nullオブジェクトでメソッドgetAt()を呼び出せません」が表示されます。

また、悪い習慣であるという理由だけでコードを直接コピーしないようにしています。そのため、変更した関数の1つは基本的に同じことを実行します。これは、私のバージョンです。最終的には残りのリファクタリングにも取り掛かります。しかし、それがわずかに異なる理由です。

4

1 に答える 1

2

わかりました...ここに行きます...これはこれまでで最もクリーンなコードではないかもしれません...

まず、1から10(y軸)の2つの分布を生成しましょう。

def generate( range, max ) {
  range.collect { i ->
    [ i, max * ( i / ( range.to - range.from + 1 ) ) ]
  }
}

// A distribution 10 elements long from 1 to 10
def e1 = generate( 1..10, 10 )
// A distribution 14 elements long from 1 to 10
def e2 = generate( 1..14, 10 )

したがって、e1とe2は次のようになります。

[1.00,1.00], [2.00,2.00], [3.00,3.00], [4.00,4.00], [5.00,5.00], [6.00,6.00], [7.00,7.00], [8.00,8.00], [9.00,9.00], [10.00,10.00]
[1.00,0.71], [2.00,1.43], [3.00,2.14], [4.00,2.86], [5.00,3.57], [6.00,4.29], [7.00,5.00], [8.00,5.71], [9.00,6.43], [10.00,7.14], [11.00,7.86], [12.00,8.57], [13.00,9.29], [14.00,10.00]

それぞれ(2dpまで)。ここで、前の質問のコードを使用して、これらを同じx範囲に正規化できます。

def normalize( xylist, days ) {
  xylist.collect { x, y -> [ x * ( days / xylist.size() ), y ] }
}

n1 = normalize( e1, 10 )
n2 = normalize( e2, 10 )

これは、n1とn2が次のことを意味します。

[1.00,1.00], [2.00,2.00], [3.00,3.00], [4.00,4.00], [5.00,5.00], [6.00,6.00], [7.00,7.00], [8.00,8.00], [9.00,9.00], [10.00,10.00]
[0.71,0.71], [1.43,1.43], [2.14,2.14], [2.86,2.86], [3.57,3.57], [4.29,4.29], [5.00,5.00], [5.71,5.71], [6.43,6.43], [7.14,7.14], [7.86,7.86], [8.57,8.57], [9.29,9.29], [10.00,10.00]

ただし、サンプルポイントの数が異なると正しく述べているため、簡単に比較することはできません。

ただし、グラフ内の必要な各ポイントをステップスルーし、最も近い2つのポイントを見つけて、次のようにこれら2つのポイントの値からay値を補間するメソッドを作成できます。

def resample( list, min, max ) {
   // We want a graph with integer points from min to max on the x axis
  (min..max).collect { i ->
    // find the values above and below this point
    bounds = list.inject( [ a:null, b:null ] ) { r, p ->
      // if the value is less than i, set it in r.a
      if( p[ 0 ] < i )
        r.a = p
      // if it's bigger (and we don't already have a bigger point)
      // then set it into r.b
      if( !r.b && p[ 0 ] >= i )
        r.b = p
      r
    }
    // so now, bounds.a is the point below our required point, and bounds.b
    if( !bounds.a )             // no lower bound...take the first element
      [ i, list[ 0 ][ 1 ] ]
    else if( !bounds.b )        // no upper bound... take the last element
      [ i, list[ -1 ][ 1 ] ]
    else {
      // so work out the distance from bounds.a to bounds.b
      dist = ( bounds.b[0] - bounds.a[0] )
      // And how far the point i is along this line
      r = ( i - bounds.a[0] ) / dist
      // and recalculate the y figure for this point
      y = ( ( bounds.b[1] - bounds.a[1] ) * r ) + bounds.a[1]
      [ i, y ]
    }
  }
}    
final1 = resample( n1, 1, 10 )
final2 = resample( n2, 1, 10 )

現在、値final1final2は次のとおりです。

[1.00,1.00], [2.00,2.00], [3.00,3.00], [4.00,4.00], [5.00,5.00], [6.00,6.00], [7.00,7.00], [8.00,8.00], [9.00,9.00], [10.00,10.00]
[1.00,1.00], [2.00,2.00], [3.00,3.00], [4.00,4.00], [5.00,5.00], [6.00,6.00], [7.00,7.00], [8.00,8.00], [9.00,9.00], [10.00,10.00]

(明らかに、ここにはいくつかの丸めがあるので、2d.p。はそれらが完全に同じではないという事実を隠しています

ふぅ...その後はホームタイムに違いない;-)

編集

質問の編集で指摘したようにresample、特定の条件で失敗する原因となる私のメソッドのバグがありました...

これは上記のコードで修正されたと思います。与えられた例から:

def march = [8, 12, 4, 17, 11, 15, 12, 8, 9, 13, 12, 7, 3, 4, 8, 2, 17, 19, 21, 12, 12, 13, 14, 15, 16, 7, 8, 19, 21, 14, 16]
o = [ (1..31), march ].transpose()

// X values squeezed to be between 1 and 28 (instead of 1 to 31)
o1 = normalize(o, 28)

// Then, resample this graph so there are only 28 points
v = resample(o1, 1, 28)

o元の31ポイント(in )と28ポイントの新しいグラフ(in)をプロットすると、次のvようになります。

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

それほど悪くはありません。

メソッドが何をするのかchangeわからないので、このコードから省略しました

于 2011-09-30T16:11:50.777 に答える