2017-05-05 13 views
1

pandas.DataFrame.Mergeと同様の方法で、各フレームの特定の列に基づいて2つのDeedle(F#)フレームをマージしようとしています。これの完璧な例は、データの列を含むプライマリフレームです(city、state)列と、次の列を含む情報フレームとを含む。(city、state);緯度;長いです。私は、長い長さの列をプライマリフレームに追加したい場合は、(都市、州)列に2つのフレームをマージします。ここでpeedas.mergeに相当するディードル

は一例です。このように見て「mergedFrame」につながる

let primaryFrame = 
      [(0, "Job Name", box "Job 1") 
      (0, "City, State", box "Reno, NV") 
      (1, "Job Name", box "Job 2") 
      (1, "City, State", box "Portland, OR") 
      (2, "Job Name", box "Job 3") 
      (2, "City, State", box "Portland, OR") 
      (3, "Job Name", box "Job 4") 
      (3, "City, State", box "Sacramento, CA")] |> Frame.ofValues 

    let infoFrame = 
      [(0, "City, State", box "Reno, NV") 
      (0, "Lat", box "Reno_NV_Lat") 
      (0, "Long", box "Reno_NV_Long") 
      (1, "City, State", box "Portland, OR") 
      (1, "Lat", box "Portland_OR_Lat") 
      (1, "Long", box "Portland_OR_Long")] |> Frame.ofValues 

    // see code for merge_on below. 
    let mergedFrame = primaryFrame 
         |> merge_On infoFrame "City, State" null 

> mergedFrame.Format();; 
val it : string = 
    "  Job Name City, State Lat    Long    
0 -> Job 1 Reno, NV  Reno_NV_Lat  Reno_NV_Long  
1 -> Job 2 Portland, OR Portland_OR_Lat Portland_OR_Long 
2 -> Job 3 Portland, OR Portland_OR_Lat Portland_OR_Long 
3 -> Job 4 Sacramento, CA <missing>  <missing> 

私はこれを行う方法(「merge_on」関数が出ています上記の例では使用していましたが、F#を初めて使用しているセールスエンジニアであるため、もっと慣用的で効率的な方法があると思います。以下は 'removeDuplicateRows'と一緒にこれを行うための私の関数です。これは 'merge_on'関数に必要とされ、必要とされたことを行います。これを行うより良い方法についてコメントしたいのであれば、してください。

let removeDuplicateRows column (frame : Frame<'a, 'b>) = 
      let nonDupKeys = frame.GroupRowsBy(column).RowKeys 
           |> Seq.distinctBy (fun (a, b) -> a) 
           |> Seq.map (fun (a, b) -> b) 
      frame.Rows.[nonDupKeys] 


    let merge_On (infoFrame : Frame<'c, 'b>) mergeOnCol missingReplacement 
        (primaryFrame : Frame<'a,'b>) = 
      let frame = primaryFrame.Clone() 
      let infoFrame = infoFrame       
          |> removeDuplicateRows mergeOnCol 
          |> Frame.indexRows mergeOnCol 
      let initialSeries = frame.GetColumn(mergeOnCol) 
      let infoFrameRows = infoFrame.RowKeys 
      for colKey in infoFrame.ColumnKeys do 
       let newSeries = 
        [for v in initialSeries.ValuesAll do 
         if Seq.contains v infoFrameRows then 
          let key = infoFrame.GetRow(v) 
          yield key.[colKey] 
         else 
          yield box missingReplacement ] 
       frame.AddColumn(colKey, newSeries) 
      frame 

ありがとうございました!

UPDATE:

は 'mergOnCol' 内の型が文字列でないケースを処理するためにFrame.indexRowsにFrame.indexRowsStringを交換しました。トーマス

答えて

0

方法により示唆されるように

はinfoFrame.Clone()を処分したDeedle(のみ行/列のキーに)フレームの接合悲しげにそれを行うために、組み込み関数の素敵を持っていないことを意味しません非キー列にフレームを結合する。

私が見る限り、あなたのアプローチは私にとても良く見えます。 infoFrameにはCloneが必要ではありません(フレームを変更していないため)infoFrame.GetRowinfoFrame.TryGetRowに置き換えることができます(そして、事前にキーを取得する必要はありません)。元気?

私は次のように見えた、代替及びこれを行うためのビット短い方法を思いついた:

// Index the info frame by city/state, so that we can do lookup 
let infoByCity = infoFrame |> Frame.indexRowsString "City, State" 

// Create a new frame with the same row indices as 'primaryFrame' 
// containing the additional information from infoFrame. 
let infoMatched = 
    primaryFrame.Rows 
    |> Series.map (fun k row -> 
     // For every row, we get the "City, State" value of the row and then 
     // find the corresponding row with additional information in infoFrame. Using 
     // 'ValueOrDefault' will automatically give missing when the key does not exist 
     infoByCity.Rows.TryGet(row.GetAs<string>("City, State")).ValueOrDefault) 
    // Now turn the series of rows into a frame 
    |> Frame.ofRows 

// Now we have two frames with matching keys, so we can join! 
primaryFrame.Join(infoMatched) 

これはちょっと短いと一目瞭然多分もっとあるが、私はすべてのテストを行っていませんどちらが速いかを確認する。パフォーマンスが第一の関心事でない限り、私はもっと読みやすいバージョンを使うのが良いデフォルト選択だと思います!

+0

ありがとうございました。私は実際のプロジェクトでこれを実行し、いくつかのコメントがありました。これは、情報フレームに同じ "City、State"が2回表示されている場合(この例に固執する)には、 "removeDuplicateRows"を追加する必要がある以外は機能しました。また、私はinfoFramesの1つをこの関数とマージすることができませんでしたが、それは上記のものと同じでしょう。また、 –

+0

最後に私はいくつかのテストを実行しました。 (行、列)、一次フレーム=(29635,7)、第1の情報フレーム=(2572,4)、および第2の情報フレーム=(18601,2)。 3つのすべてのマージの5回の実行は、平均5.97秒でした。私の方法と27.05秒で。あなたと一緒に。にもかかわらずこれを見て、すぐに答えるために感謝! –

+0

テストを実行するための素晴らしい仕事と感謝:-)あなたの方法のような音が行く方法です! –