2017-04-26 9 views
2

Array[Option[Long]]を直線補間しようとしています。与えられた例:スカラで配列を補間する

val example1 = Array(Some(20l), None, Some(60l)) 
val example2 = Array(Some(20l), None, None, Some(80l)) 
val example3 = Array(Some(20l), None, None, Some(80l), Some(90l), Some(100l)) 
val example4 = Array(Some(20l), None, None, Some(80l), None, Some(82l)) 

を私は期待してい:

val example1Interpolated = Array(20l, 40l, 60l) 
val example2Interpolated = Array(20l, 40l, 60l, 80l) 
val example3Interpolated = Array(20l, 40l, 60l, 80l, 90l, 100l) 
val example4Interpolated = Array(20l, 40l, 60l, 80l, 81l, 82l) 

コレクション(例えばexample4)内の要素の間には関係がありません。しかし値は単調に増加しています。

def interpolate(input_): 
    nans = np.isnan(input_) 
    get_index = lambda z: z.nonzero()[0] 
    input_[nans] = np.interp(get_index(nans), get_index(~nans), input_[~nans]) 
    return input_ 

のために:

interpolate(np.array([20, np.nan, 60])) 
interpolate(np.array([20, np.nan, np.nan, 80])) 
interpolate(np.array([20, np.nan, np.nan, 80, np.nan, 82])) 

利回り:

array([ 20., 40., 60.]) 
array([ 20., 40., 60., 80.]) 
array([ 20., 40., 60., 80., 81., 82.]) 
+2

これまでに何を試しましたか?あなたはどこでブロックされていますか?あなたの具体的な問題は何ですか? – sjrd

+0

@sjrdは、任意の値を持つコレクションがあれば、これを行うための機能的な方法を理想的に探しています。誰かが知っている実装や、私が紛失していることがあるパッケージがあるかどうかを知りましょう。 –

+3

@AmirZiai質問に必要な正確な要件を追加する必要があります。 –

答えて

3

この機能は限りSome(_)で、リスト内の少なくとも1つの要素があるとして、そこに先頭またはNone後続している場合でも動作します。それはまたIntegralタイプの間でも一般的です。 (あなたが望んでいた場合は、Fractionalタイプで、それは一般的な作ることができる。)

def interpolate[T](list: Iterable[Option[T]])(implicit num: Integral[T]) = { 
    import num._ 
    val prevs = list.zipWithIndex.scanLeft(Option.empty[(T, Int)]) { 
    case (prev, (cur, i)) => cur.map((_, i)).orElse(prev) 
    } 
    val nexts = list.zipWithIndex.scanRight(Option.empty[(T, Int)]) { 
    case ((cur, i), next) => cur.map((_, i)).orElse(next) 
    } 
    prevs.tail.zip(nexts).zipWithIndex.map { 
    case ((Some((prev, i)), Some((next, j))), k) => 
     if (i == j) prev else prev + (next - prev) * fromInt(k - i)/fromInt(j - i) 
    case ((Some((prev, _)), _), _) => prev 
    case ((_, Some((next, _))), _) => next 
    } 
} 

これはと同じである、左に最新のSome(_)のトラックとそのインデックスを保持している、prevsを構築し、nexts右。次に、prevsnextsの両方を並列に反復すると、左、右、およびインデックスに基づいて補間値が生成されます。左または右がない場合は、反対側から入力してください。

2

私はないです、私は次のScalaの同等を探していますのPythonに精通している人のために

numpyに精通していますが、これはあなたのデモンストレーションのすべてを処理すると思います。リストの最初と最後の要素が定義されていると仮定します(そうでない場合は、fillNones関数を再実行する必要があります)。

def interpolate(list: List[Option[Long]]) = { 

    // Creates a new list that will be used to replace a sequence of Nones 
    def fillNones(noneCount: Int, min: Long, max: Long): List[Long] = { 
    val stepSize = (max - min)/(noneCount + 1) 
    (1 to noneCount).toList.map(i => i * stepSize + min) 
    } 

    // We will recursively traverse the list 
    def recursive(done: List[Long], todo: List[Option[Long]]): List[Long] = { 
    todo match { 

     // If todo is empty, we are done 
     case Nil => done 

     // If the head of todo is Some(Long), then add it to the list of things that are done and move on 
     case Some(l) :: tail => recursive(done :+ l, tail) 

     // If the head wasn't Some(Long), then we have to figure out how many Nones are in a row, and replace them 
     case todo => 

     // Find out how many Nones are in a row 
     val noneCount = todo.takeWhile(_.isEmpty).length 

     // Split the todo so we can get what is remaining 
     val remaining = todo.splitAt(noneCount)._2 

     // Create a new list to replace the sequence of Nones 
     val filled = fillNones(noneCount, done.last, remaining.head.get) 

     // Add our new filled list to done, and continue on 
     recursive(done ++ filled, remaining) 
    } 
    } 

    recursive(List.empty, list) 
} 

テスト:

val example1 = List(Some(20l), None, Some(60l)) 
println(interpolate(example1)) 
// Prints: List(20, 40, 60)  

val example2 = List(Some(20l), None, None, Some(80l)) 
println(interpolate(example2)) 
// Prints: List(20, 40, 60, 80) 

val example3 = List(Some(20l), None, None, Some(80l), Some(90l), Some(100l)) 
println(interpolate(example3)) 
// Prints: List(20, 40, 60, 80, 90, 100) 

val example4 = List(Some(20l), None, None, Some(80l), None, Some(82l)) 
println(interpolate(example4)) 
// Prints: List(20, 40, 60, 80, 81, 82) 
関連する問題