Deedle


データフレームを F# で扱う

このセクションではF#データフレームライブラリの様々な機能を紹介します (SeriesFrame 型およびモジュールを使用します)。 任意のセクションに読み飛ばしてもらって構いませんが、 一部のセクションでは「作成および読み取り」で組み立てた値を参照している点に 注意してください。

また、このページをGitHubから F# スクリプトファイル としてダウンロードすれば、インタラクティブにサンプルを実行することもできます。

フレームの作成とデータの読み取り

CSVファイルのロードとセーブ

データをデータフレームとして取得する一番簡単な方法は CVSファイルを使用することです。 この機能は Frame.ReadCsv 関数として用意されています:

 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
11: 
// 'root' ディレクトリにファイルが置かれているものとします
let titanic = Frame.ReadCsv(root + "Titanic.csv")

// データを読み取ってインデックス列を設定し、行を並び替えます
let msft = 
  Frame.ReadCsv(root + "stocks/msft.csv") 
  |> Frame.indexRowsDate "Date"
  |> Frame.sortRowsByKey

// 列区切り文字を指定します
let air = Frame.ReadCsv(root + "AirQuality.csv", separators=";")

ReadCsv メソッドにはロード時の動作を制御するためのオプションが多数あります。 このメソッドはCSVファイルやTSVファイル、その他の形式のファイルをサポートします。 ファイル名がtsvで終わる場合には自動的にタブ文字が処理されますが、 separator 引数を明示的に指定して区切り文字を設定することもできます。 以下の引数が有効です:

  • path - リソースのファイル名またはWeb上の位置を指定します。
  • inferTypes - メソッドが列の型を推測すべきかどうかを指定します。 (スキーマを指定する場合にはfalseを指定します)
  • inferRows - interTypes=true の場合、この引数には 型の推論に使用する行数を指定します。 デフォルトは0で、すべての行が使用されます。
  • schema - CSVスキーマを指定する文字列です。 スキーマの形式については別途ドキュメントを参照してください。
  • separators - CSVファイルの行を区切る1つ以上の(単一)文字を文字列として 指定します。 たとえば ";" とするとセミコロン区切りのファイルとしてパースされます。
  • culture - CVSファイルの値をパースする際に使用される カルチャ(たとえば "en-US" )を指定します。 デフォルトはインバリアントカルチャです。

これらの引数は F# DataのCSV型プロバイダー (日本語) で使用されるものと同じものなので、そちらのドキュメントも参照してください。

データフレームを取得した後は、 SaveCsv メソッドを使用して CSVファイルとして保存できます。 たとえば以下のようにします:

1: 
2: 
3: 
4: 
// セミコロン区切りでCSVを保存します
air.SaveCsv(Path.GetTempFileName(), separator=';')
// 行キーを"Date"列として含むようなCSVファイルとして保存します
msft.SaveCsv(Path.GetTempFileName(), keyNames=["Date"], separator='\t')

デフォルトでは SaveCsv メソッドはデータフレームのキーを含めません。 この動作は SaveCsv メソッドのオプション引数に includeRowKeys=true を指定するか、 (上の例のように) keyNames 引数に(複数の)キー列となるヘッダを設定します。 通常、行キーは1つだけですが、 階層的インデックシング が使用されている場合には複数になることもあります。

F#レコードまたは.NETオブジェクトのロード

データをF#のレコード、C#の匿名型、あるいはその他の.NETオブジェクトとして返すような .NETあるいはF#のコンポーネントを使用している場合には、 Frame.ofRecords を使用すればこれらをデータフレームに変換できます。 たとえば以下のデータがあるとします:

1: 
2: 
3: 
4: 
5: 
6: 
7: 
8: 
type Person = 
  { Name:string; Age:int; Countries:string list; }

let peopleRecds = 
  [ { Name = "Joe"; Age = 51; Countries = [ "UK"; "US"; "UK"] }
    { Name = "Tomas"; Age = 28; Countries = [ "CZ"; "UK"; "US"; "CZ" ] }
    { Name = "Eve"; Age = 2; Countries = [ "FR" ] }
    { Name = "Suzanne"; Age = 15; Countries = [ "US" ] } ]

そうすると Person のプロパティと同じ型のデータを持った 3つの列(Name Age Countries)を含んだデータフレームを 簡単に作成できます:

1: 
2: 
3: 
4: 
// レコードのリストをデータフレームに変換します
let peopleList = Frame.ofRecords peopleRecds
// 'Name' 列を(文字列型の)キーとして使用します
let people = peopleList |> Frame.indexRowsString "Name"

なおここでは列データに対する変換は何も行われないことに注意してください。 数値的なシリーズは ? 演算子を使用してアクセスできます。 その他の型の場合には適切な型引数を指定して GetColumn を明示的に呼び出す必要があります:

1: 
2: 
people?Age
people.GetColumn<string list>("Countries")

F#データプロバイダ

一般的にはデータをタプルのシリーズとして公開するような 任意のデータソースを使用できます。 つまり、F# Dataライブラリ のWorld Bank型プロバイダーのような機能を使用すれば、 簡単にデータをロードできるというわけです。

 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
11: 
12: 
// World Bankに接続します
let wb = WorldBankData.GetDataContext()

/// 特定の地域に対して、GDPを現在のUSドルでロードし、
/// 2レベルの列キー(地域と国名)を持ったフレームとしてデータを返します
let loadRegion (region:WorldBankData.ServiceTypes.Region) =
  [ for country in region.Countries -> 
      // タプルを使用して、2レベルの列キーを作成します
      (region.Name, country.Name) => 
        // WorldBankから返された複数のタプルからシリーズを作成します
        Series.ofObservations country.Indicators.``GDP (current US$)`` ]
  |> frame

データ処理をもっと簡単にするために、 地域毎の国情報を読み取って階層的インデックスを持ったデータフレームを作成しています (詳細については高度なインデックシングのセクションを参照)。 これでOECDとユーロエリアのデータを簡単に読み取ることができるようになりました:

1: 
2: 
3: 
4: 
5: 
6: 
// ユーロとOECD地域をロード
let eu = loadRegion wb.Regions.``Euro area``
let oecd = loadRegion wb.Regions.``OECD members``

// これらをジョインして、10億USドル単位に変換します
let world = eu.Join(oecd) / 1e9

(Euro area, Austria)

(Euro area, Belgium)

(Euro area, Cyprus)

...

(OECD members, Sweden)

(OECD members, Turkey)

(OECD members, United States)

1960

6.59

11.66

N/A

...

14.84

14

520.53

1961

7.31

12.4

N/A

...

16.15

8.02

539.05

1962

7.76

13.26

N/A

...

17.51

8.92

579.75

1963

8.37

14.26

N/A

...

18.95

10.35

611.67

1964

9.17

15.96

N/A

...

21.14

11.17

656.91

1965

9.99

17.37

N/A

...

23.26

11.95

712.08

1966

10.89

18.65

N/A

...

25.3

14.12

780.76

1967

11.58

19.99

N/A

...

27.46

15.66

825.06

...

...

...

...

...

...

...

...

2009

383.73

473.25

23.54

...

405.78

614.55

14417.9

2010

377.68

471.15

23.13

...

462.9

731.14

14958.3

2011

415.98

513.32

24.85

...

536.29

774.78

15533.8

2012

394.45

482.95

22.77

...

523.94

789.26

16244.6

読み取ったデータはおよそ上のようになります。 見ての通り、列は地域によってグループ化され、一部のデータが値無しになっています。

オブジェクトを列に展開する

シリーズ内のメンバーとして他の.NETオブジェクトを含むようなデータフレームを 作成することもできます。 これはたとえば複数のデータソースから生成されたオブジェクトを取得して、 これらを処理する前にアラインまたは連結したいような場合に便利なことがあります。 しかし複雑な.NETオブジェクトを含むフレームの場合には、 逆に利便性が損なわれる場合もあります。

そのため、データフレームは展開(expansion)機能をサポートしています。 列に何かしらのオブジェクトを含んだデータフレームに対して Frame.expandColsを使用すると、オブジェクトのプロパティそれぞれを新しい列として 含むような新しいフレームを作成できます。 たとえば以下のようにします:

1: 
2: 
3: 
4: 
5: 
6: 
// 'People'という1列だけを持ったフレームを作成します
let peopleNested = 
  [ "People" => Series.ofValues peopleRecds ] |> frame

// 'People'列を展開します
peopleNested |> Frame.expandCols ["People"]

People.Name

People.Age

People.Countries

0

Joe

51

[UK; US; UK]

1

Tomas

28

[CZ; UK; US; ... ]

2

Eve

2

[FR]

3

Suzanne

15

[US]

見ての通り、この操作では元の列の型に含まれるプロパティを元にして 複数の列が生成されて、それぞれの列の名前は 元の列の名前に各プロパティの名前を続けたものになります。

.NETオブジェクトだけでなく、IDictionary<K, V>型の値や stringをキーとするネストされたシリーズ(つまりSeries<string, T>) について展開することができます。 さらに複雑な構造をしている場合には、 Frame.expandAllCols を使用して特定のレベルまで再帰的に列を展開することもできます:

1: 
2: 
3: 
4: 
5: 
6: 
7: 
8: 
9: 
// タプルを含むディクショナリを含んだシリーズ
let tuples = 
  [ dict ["A", box 1; "C", box (2, 3)]
    dict ["B", box 1; "C", box (3, 4)] ] 
  |> Series.ofValues

// ディクショナリのキー(レベル1)とタプルのアイテム(レベル2)を展開
frame ["Tuples" => tuples]
|> Frame.expandAllCols 2

この場合、結果のデータフレームには Tuples.ATuples.B、 さらにディレクトリ内にネストされたタプルの2つの項目を表す Tuples.C.Item1Tuples.C.Item2 の列が含まれることになります。

データフレームの操作

シリーズ型 Series<K, V> はシリーズのキーの型が K で 値の型が V であることを表しています。 つまりシリーズを処理する場合には、値の型があらかじめわかっているということです。 一方、データフレームの場合にはそうはいきません。 Frame<R, C>RC はそれぞれ行と列のインデックスの型を表します (一般的に Rint または DateTime で、C は異なる行または列名を表す string になります)。

フレームには多様なデータが含まれます。 ある列には整数、別の列には浮動小数点数、さらに別の列には文字列や日付、 あるいは文字列のリストのような別のオブジェクトが含まれることがあります。 これらの情報は静的にキャプチャされません。 したがってシリーズの読み取りなど、フレームを操作する場合には、 明示的に型を指定しなければいけないことがあります。

フレームからデータを取得する

ここでは string 型の Name と、int 型の Agestring list 型の Countries という3つの列を持った people データフレームを使用します (これは 先のセクションで F#のレコードから作成したものです):

1: 
2: 
3: 
4: 
5: 
           Name    Age Countries
Joe     -> Joe     51  [UK; US; UK]
Tomas   -> Tomas   28  [CZ; UK; US; ... ]
Eve     -> Eve     2   [FR]
Suzanne -> Suzanne 15  [US]

フレーム df から列(シリーズ)を取得するには データフレームで直接公開されている操作を使用するか、 df.Columns を使用してフレームのすべての列を シリーズのシリーズとして取得することもできます。

1: 
2: 
3: 
4: 
5: 
6: 
7: 
// 'Age' 列を 'float' 値のシリーズとして取得します
// ('?' 演算子が値を自動的に変換します)
people?Age
// 'Name' 列を 'string' 値のシリーズとして取得します
people.GetColumn<string>("Name")
// フレームのすべての列をシリーズのシリーズとして取得します
people.Columns

Series<string, V> 型 は疑問符演算子をサポートしているため、 この型の s に対して s?Foo とすると、 キー Foo に関連づけられた型 V の値を取得できます。 それ以外の型を取得する場合には Get メソッドを使用します。 なおフレームの場合と異なり、明示的な変換は行われないことに注意してください:

1: 
2: 
3: 
4: 
5: 
6: 
7: 
8: 
9: 
// Series<string, float> を取得します
let numAges = people?Age

// 疑問符演算子を使用して値を取得します
numAges?Tomas
// 'Get' メソッドを使用して値を取得します
numAges.Get("Tomas")
// キーが見つからない場合には値無しを返します
numAges.TryGet("Fridrich")

疑問符演算子と Get メソッドはデータフレームの Columns プロパティに対しても使用できます。 df?Columns の返り値の型は `ColumnSeriesで、 これは単にSeries>の薄いラッパーです。 つまり各列を表すObjectSeriesを値に持つような列の名前で インデックスされたシリーズを取得しなおすことができるというわけです。 `ObjectSeries<R>` 型はSeries` の薄いラッパーで、 これは値を特定の型として取得できるような機能がいくつか追加されたものです。

今回の場合、返される値は ObjectSeries<string> として表されるそれぞれの列になります:

 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
11: 
12: 
13: 
14: 
15: 
16: 
17: 
18: 
19: 
20: 
// ObjectSeriesとして列を取得します
people.Columns?Age
people.Columns?Countries
val it : ObjectSeries<string> =
  Joe     -> [UK; US; UK]       
  Tomas   -> [CZ; UK; US; ... ] 
  Eve     -> [FR]               
  Suzanne -> [US]               

// メンバーを使用して列の取得を試みます
people.Columns.Get("Name")
people.Columns.TryGet("CreditCard")
// 特定のオフセットにある列を取得します
people.Columns.GetAt(0)

// 列をObjectSeriesとして取得し、
// それを型付きの Series<string, string> に変換します
people.Columns?Name.As<string>()
// 列をSeries<string, int>として変換するよう試みます
people.Columns?Name.TryAs<int>()

ObjectSeries<string> 型には元の Series<K, V> 型に 若干のメソッドが追加されています。 18行目と20行目では As<T>TryAs<T> を使用して、ObjectSeriesを 静的に既知の型を持った値のシリーズに変換しています。 18行目の式は people.GetColumn<string>("Name") という式と同じものですが、 As<T> の対象はフレームの行だけではありません。 データセットの行がいずれも同じ型の場合には、フレームの行に対して (people.Rowsを使用して)同じ操作ができます。

ObjectSeries<T> を扱わなければならないケースはもう1つ、 行をマッピングする場合です:

1: 
2: 
3: 
// 行を走査して、国リストの長さを取得します
people.Rows |> Series.mapValues (fun row ->
  row.GetAs<string list>("Countries").Length)

people.Rows から返された行は混種である(つまり異なる型の値が含まれている)ため、 シリーズのすべての値を row.As<T>() で何かしらの型に変換することはできません。 その代わり、 Get(...) と同じような GetAs<T>(...) を使用すると、 値を特定の型に変換して取得することができます。 row?Countries とすれば結果が string list にキャストされた状態で取得できますが、 GetAs メソッドにはもう1つ便利な文法があります。

行および列の追加

シリーズ型は 不変 なので、シリーズに新しい値を追加したり、 既存のシリーズに含まれる値を変更したりすることはできません。 しかし Merge のような機能を使用して、新しいシリーズを含むような結果を 返す操作を行うことはできます。

1: 
2: 
3: 
4: 
// さらに値を含んだシリーズを作成します
let more = series [ "John" => 48.0 ]
// シリーズが連結された新しいシリーズを作成します
people?Age.Merge(more)

データフレームは非常に限定的に変更をサポートしています。 既存のデータフレームには(列として)新しいシリーズを追加したり、 削除あるいは置き換えたりすることもできます。 しかしシリーズそれぞれはやはり不変です。

 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
11: 
12: 
// すべての人物の年齢を1つ増やします
let add1 = people?Age |> Series.mapValues ((+) 1.0)

// 新しいシリーズとしてフレームに追加します
people?AgePlusOne <- add1

// 値のリストを使用して新しいシリーズを追加します
people?Siblings <- [0; 2; 1; 3]

// 既存のシリーズを新しい値に置き換えます
// (people?Siblings <- ... と同じです)
people.ReplaceColumn("Siblings", [3; 2; 1; 0])

最後に、既存のデータフレームに1つのデータフレーム、 あるいは1つの行を追加することも可能です。 この操作も不変なので、行が追加された新しいデータフレームが返されることになります。 データフレーム用の新しい行を作成するには、 キー値ペアからシリーズを作成する標準的な方法か、 あるいは SeriesBuilder 型を使用することもできます:

 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
11: 
12: 
13: 
14: 
15: 
16: 
// 必須の列に対応する値を持った新しいシリーズオブジェクトを作成します
let newRow = 
  [ "Name" => box "Jim"; "Age" => box 51;
    "Countries" => box ["US"]; "Siblings" => box 5 ]
  |> series
// 新しいシリーズを含んだ新しいデータフレームを作成します
people.Merge("Jim", newRow)

// 可変なSeriesBuilderオブジェクトを使用することもできます
let otherRow = SeriesBuilder<string>()
otherRow?Name <- "Jim"
otherRow?Age <- 51
otherRow?Countries <- ["US"]
otherRow?Siblings <- 5
// 組み立てたシリーズはSeriesプロパティで取得できます
people.Merge("Jim", otherRow.Series)

高度なスライシングおよびルックアップ

特定のシリーズからは多数の方法で1つ以上の値を取得したり、 (複数キーや関連する複数の値などの)観測データを取得したりできます。 まず(順序づけられていないシリーズも含む)任意のデータを 対象にできる差分ルックアップ操作について説明します。

1: 
2: 
3: 
4: 
5: 
6: 
7: 
8: 
9: 
// 異なるキーと値を持ったサンプル用のシリーズ
let nums = series [ 1 => 10.0; 2 => 20.0 ]
let strs = series [ "en" => "Hi"; "cz" => "Ahoj" ]

// キーを使用して値を検索します
nums.[1]
strs.["en"]
// キーが文字列の場合には以下のようにアクセスできます
strs?en

さらなる例として、前の例で作成したデータセットAge 列を使用します:

1: 
2: 
3: 
4: 
5: 
6: 
7: 
// 順序づけられていないサンプルのシリーズを取得します
let ages = people?Age

// 特定のキーに対応する値を取得します
ages.["Tomas"]
// データソースから2つのキーを指定してシリーズを取得します
ages.[ ["Tomas"; "Joe"] ]

Series モジュールには便利な関数が他にも用意されています (たとえば ages.TryGet のように、多くはメンバーメソッドとしても 呼び出すことが出来ます):

1: 
2: 
3: 
4: 
5: 
6: 
7: 
// キーが存在しない場合には失敗します
try ages |> Series.get "John" with _ -> nan
// キーが存在志ない場合には'None'が返ります
ages |> Series.tryGet "John"
// 'John' の値を除いたシリーズが返ります
// ('ages.[ ["Tomas"; "John"] ]' と同じです)
ages |> Series.getAll [ "Tomas"; "John" ]

シリーズからすべてのデータを取得することもできます。 データフレームライブラリではすべてのキー値ペアのことを observations(観測値) と呼んでいます。

1: 
2: 
3: 
4: 
5: 
6: 
// すべてのobservationsを'KeyValuePair'のシーケンスとして取得します
ages.Observations
// すべてのobservationsをタプルのシーケンスとして取得します
ages |> Series.observations
// 値無しに対しては'None'となるようにしてすべてのobservationsを取得します
ages |> Series.observationsAll

これまでの例ではいずれもキーを厳密に指定して検索を行っていました。 順序付きシリーズの場合には、最も近くで利用可能なキーを使用して検索をしたり、 スライシングしたりすることができます。 先の例で作成した MSFTの株価データで試してみましょう:

1: 
2: 
3: 
4: 
5: 
6: 
7: 
8: 
9: 
// 始値をシリーズとして取得します
let opens = msft?Open

// キーがシリーズ内に無いため失敗します
try opens.[DateTime(2013, 1, 1)] with e -> nan
// 最も近い大きな値をキーにして値を探すため正しく動作します
opens.Get(DateTime(2013, 1, 1), Lookup.ExactOrSmaller)
// 最も近い小さな値をキーにして値を探すため正しく動作します
opens.Get(DateTime(2013, 1, 1), Lookup.ExactOrSmaller)

インスタンスのメンバーを使用する場合、 Lookup を引数にとる Get メソッドのオーバーロードが使用できます。 同じ機能が Series.lookup として定義されています。 キーのシーケンスに対応する値を取得することもできます:

1: 
2: 
3: 
4: 
5: 
6: 
// 最も近い大きなキーに対する値を取得します
opens |> Series.lookup (DateTime(2013, 1, 1)) Lookup.ExactOrGreater

// 2012年の各月における1つめの価格を取得します
let dates = [ for m in 1 .. 12 -> DateTime(2012, m, 1) ]
opens |> Series.lookupAll dates Lookup.ExactOrGreater

順序付きシリーズに対しては、スライシングによって シリーズの部分区間を取得することもできます:

1: 
2: 
opens.[DateTime(2013, 1, 1) .. DateTime(2013, 1, 31)]
|> Series.mapKeys (fun k -> k.ToShortDateString())

Keys

2013/01/02

2013/01/03

2013/01/04

2013/01/07

2013/01/08

...

2013/01/29

2013/01/30

2013/01/31

Values

27.25

27.63

27.27

26.77

26.75

...

27.82

28.01

27.79

スライシングはシリーズのキーが利用できない場合であっても機能します。 ルックアップ時には上限(最も近い上方の値のうち、最も小さい値) および下限(最も近い下方の値のうち、最も大きい値)が自動的に使用されます (今回の場合、1月1日に対応する値はありません)。

後のセクション で説明しますが、 階層的(あるいはマルチレベル)インデックスを使用している場合には まだいくつかの方法があります。 しかしまずはグループ化について説明する必要があるでしょう。

データのグループ化

データのグループ化は順序付きのシリーズやフレーム、順序無しのシリーズやフレームの いずれに対しても行うことができます。 順序付きシリーズを対象とする場合には (フローティングウィンドウや連続要素のグループ化など) 固有の機能を利用できます。 詳細については 時系列データのチュートリアル を参照してください。 基本的には2つの機能があります:

  • 任意の値のシリーズをグループ化して、(それぞれのグループを) シリーズのシリーズとして取得できます Frame.ofColumns あるいは Frame.ofRows を使用することにより、 結果を簡単にデータフレームへと変換できますが、この処理は自動的には行われません。

  • 特定の列に含まれる値、あるいは関数を使用してフレーム行をグループ化できます。 この場合にはマルチレベル(階層的)インデックスを持ったフレームが返されます。 階層的インデックスについては 後ほど説明します

データフレームに対して df.Rows あるいは df.Columns とすれば 簡単に行シリーズ、あるいは列シリーズが取得できるわけなので、 データフレームに対する1番目の機能は特に有用だということを覚えておいてください。

シリーズのグループ化

以下のサンプルでは、 先のセクション でF#のレコードから ロードしたデータフレーム people を使用しています。 まずデータを取得します:

1: 
2: 
3: 
4: 
5: 
6: 
let travels = people.GetColumn<string list>("Countries")
val travels : Series<string,string list> =
  Joe     -> [UK; US; UK]       
  Tomas   -> [CZ; UK; US; ... ] 
  Eve     -> [FR]               
  Suzanne -> [US]               

そうすると、キー(例:名前の長さ) と値(行ったことがある国の数)の 両方を使用して要素を取得することができます:

1: 
2: 
3: 
4: 
5: 
6: 
7: 
8: 
9: 
// 名前の長さでグループ化 (行ったことがある国は無視)
travels |> Series.groupBy (fun k v -> k.Length)
// 行ったことがある国の数 (USに行ったことがある/無い人)
travels |> Series.groupBy (fun k v -> List.exists ((=) "US") v)

// 名前の長さでグループ化して各グループの値の個数を取得します
travels |> Series.groupInto 
  (fun k v -> k.Length) 
  (fun len people -> Series.countKeys people)

groupBy 関数はシリーズのシリーズを返します(新しいキーを持ち、 特定の新しいキーに対するすべての値を含んだシリーズを値とします)。 そして Series.mapValues を使用すると値を変形させることができます。 しかし間でシリーズを全く確保したくないという場合には、 Series.groupInto を使用できます。 この関数の2番目の引数には射影関数を指定します。 上の例の場合には各グループのキーの数をカウントしています。

最後の例として、(行として)それぞれの人物と、 (列として)誰かしらが行ったことのある国を含むデータフレームを組み立ててみましょう。 フレームにはそれぞれの人物が行ったことのある国の数が含まれるようにします:

1: 
2: 
3: 
4: 
travels
|> Series.mapValues (Seq.countBy id >> series)
|> Frame.ofRows
|> Frame.fillMissingWith 0

UK

US

CZ

FR

Joe

2

1

0

0

Tomas

1

1

2

0

Eve

0

0

0

1

Suzanne

0

1

0

0

この問題は Series.mapValues とF#の標準的な Seq 関数を 組み合わせるだけで解決できます。 まずすべての行(人物および行ったことのある国リスト)を走査します。 そしてそれぞれの国リストに対して、各国と訪問数を含むようなシリーズを生成します (Seq.countByseries を組み合わせることで観測データのシリーズを組み立てます)。 それからこの結果をデータフレームへと変換して、 値無しのデータを定数値0で置き換えています (値無しへの対処を参照してください)。

データフレームのグループ化

これまではシリーズやシリーズのシリーズを対象にしてきました (シリーズのシリーズは Frame.ofRowsFrame.ofColumns で データフレームに変換できます)。 次に、データフレームを対象とする方法を説明しましょう。

ここでは プロジェクトのホームページ でも使用している、 タイタニック号のデータセット が読み取り済みであるとします。 まず基本的なグループ化を紹介します(ホームページのデモでも使用しているものです):

 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
11: 
12: 
13: 
// 'string'型の列'Sex'でグループ化
titanic |> Frame.groupRowsByString "Sex"

// 'decimal'に変換された列でグループ化
let byDecimal : Frame<decimal * _, _> = 
  titanic |> Frame.groupRowsBy "Fare"

// これはメンバーメソッドを使用すれば簡単に記述できます
titanic.GroupRowsBy<decimal>("Fare")

// 計算値(名前の長さ)でグループ化
titanic |> Frame.groupRowsUsing (fun k row -> 
  row.GetAs<string>("Name").Length)

フレームを対象にする場合、行と列の両方のデータを使用してグループ化できます。 多くの関数にとって groupRowsgroupCols は同じものです。 一番簡単に使用できる関数は Frame.groupRowsByXyz で、 Xyz にはグループ化に使用する列の型を指定します。 たとえば Frame.groupRowsByString("Sex") とすれば、 文字列型の列 "Sex" を使用して行を簡単にグループ化できます。

あまり一般的では無い型を使用する場合、列の型を指定する必要があります。 これは5行目と9行目でdecimalをキーとして使用しているコードを参照してください。 最後に、キーセレクタを関数で指定することもできます。 この関数は元のキーと、ObjectSeries<K> 型の値である行を引数にとります。 ObjectSeries<K> には特定の型の列を取得する GetAs など、 それぞれの値(列)を取得するための様々なメンバーが定義されています。

単一キーでのグループ化

グループ化されたデータフレームではマルチレベルインデックスが使用されています。 これはつまり、インデックスが複数レベルを表すキーのタプルになっているということです。 たとえば以下の通りです:

1: 
2: 
3: 
4: 
5: 
6: 
7: 
8: 
9: 
titanic |> Frame.groupRowsByString "Sex"
val it : Frame<(string * int),string> =
                Survive   Name                    
  female 2   -> True      Heikkinen, Miss. Laina  
         11  -> True      Bonnell, Miss. Elizabeth
         19  -> True      Masselmani, Mrs. Fatima 
                ...       ...                     
  male   870 -> False     Balkic, Mr. Cerin       
         878 -> False     Laleff, Mr. Kristo      

見ての通り、簡易プリンターはマルチレベルインデックスを理解して、 第1レベル(性別)に続けて第2レベル(乗船者ID)を出力します。 Frame.unnestFrame.nest を使用すると、 2レベルインデックスをデータフレームのシリーズ1つに変換する(あるいは逆の変換をする) ことができます:

1: 
2: 
3: 
4: 
5: 
let bySex = titanic |> Frame.groupRowsByString "Sex" 
// 値として2つのフレームを持つようなシリーズを返します
let bySex1 = bySex |> Frame.nest
// スタックされていないデータを単一のフレームに戻します
let bySex2 = bySex |> Frame.nest |> Frame.unnest

複数キーでのグループ化

最後に、複数のキーを使用してデータを繰り返しグループ化できるということを説明します。 たとえば乗船者を階級(Pclass)および乗船した場所(Embarked)でグループ化できます:

1: 
2: 
3: 
4: 
5: 
6: 
7: 
8: 
9: 
// 階級および乗船場所で乗船者をグループ化します
let byClassAndPort = 
  titanic
  |> Frame.groupRowsByInt "Pclass"
  |> Frame.groupRowsByString "Embarked"
  |> Frame.mapRowKeys Pair.flatten3

// 同じ行インデックスを持ったAgeシリーズだけを取得します
let ageByClassAndPort = byClassAndPort?Age

byClassAndPort の型を確認してみると、 Frame<(string * int * int),string> になっていることがわかります。 行キーは乗船場の識別子(string)、乗船者の階級(1から3までのint)、 乗船者IDの3つ組です。 フレームから単一のフレームを取得すると、 マルチレベルインデックスは保持されます。

最後の例として、グループに対する様々な集計方法を紹介します:

 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
11: 
12: 
13: 
14: 
15: 
// 各グループの平均年齢を求めます
byClassAndPort?Age
|> Stats.levelMean Pair.get1And2Of3

// 数字的なすべての行に対して平均を求めます
byClassAndPort
|> Frame.getNumericCols
|> Series.dropMissing
|> Series.mapValues (Stats.levelMean Pair.get1And2Of3)
|> Frame.ofColumns

// 各グループの生存者数をカウントします
byClassAndPort.GetColumn<bool>("Survived")
|> Series.applyLevel Pair.get1And2Of3 (Series.values >> Seq.countBy id >> series)
|> Frame.ofRows

2番目のスニペットでは便利な関数を複数組み合わせています。 まず、 Frame.getNumericCols を使用して、 データフレームから数字的な列だけを取得します。 そして Series.dropMissing を使用して、値無しの列を排除します。 それから Series.mapValues を使用して、すべての列に対して平均を計算しています。

最後のスニペットにも注目してください。 (ブール値が含まれた)"Survived"列を取得した後、 特定の関数を使用して各グループを集計しています。 この関数は3つのコンポーネントで構成されています。 まずグループ内の値を取得し、その値(つまり truefalse の数)をカウントし、 この結果を使用してシリーズを作成しています。 実行結果は以下のようなテーブルになります(一部の値を省略してあります):

1: 
2: 
3: 
4: 
5: 
6: 
7: 
         True  False     
C 1  ->  59    26        
  2  ->  9     8         
  3  ->  25    41        
S 1  ->  74    53        
  2  ->  76    88        
  3  ->  67    286       

ピボットテーブルを使用してデータを集計する

先のセクションでは非常に一般的なデータ処理操作であるグループ化を紹介しました。 しかしたとえば特定のキーでデータをグループ化しつつ、 集計結果を出力するというように、2つの操作を同時に行いたいこともよくあります。 この組み合わせは ピボットテーブル という概念としてまとめられています。

ピボットテーブルはデータフレームの行で利用可能な2つのキーを 元にしたフレーム内のデータを集計したい場合に便利なツールです。

たとえば 以前に読み込み、先のセクションでも扱った タイタニック号のデータセットに対して、男性と女性の生存比率を比較したいとしましょう。 これはピボットテーブルを作成する呼び出しを1回行うだけで実現できます:

1: 
2: 
3: 
4: 
5: 
6: 
7: 
8: 
titanic
|> Frame.pivotTable
    // 新しい行キーを返します
    (fun k r -> r.GetAs<string>("Sex"))
    // 新しい列キーを返します
    (fun k r -> r.GetAs<bool>("Survived"))
    // サブフレームに対する集計処理を指定します
    Frame.countRows

pivotTable 関数(および対応する PivotTable メソッド)は 3つの引数をとります。 最初の2つには元のフレームの行を受け取って新しい行キーを返す関数、 および列を受け取って新しい列キーを返す関数をそれぞれ指定します。 上の例では Sex の値が新しい行キーで、 乗船者が生存したかどうかが新しい列キーになります。 その結果、以下のような2x2のテーブルになります:

False

True

male

468

109

female

81

233

ピボットテーブル操作では元となるフレームを受け取り、 データ(行)を新しい行キーと列キーで分割し、 そして指定された集計処理により各フレームを集計します。 上の例では単に各サブグループの合計人数を返せばよいため、 Frame.countRows を指定しています。 ですが、たとえば平均年齢のように別の統計情報を計算することも簡単にできます:

1: 
2: 
3: 
4: 
5: 
6: 
titanic 
|> Frame.pivotTable 
    (fun k r -> r.GetAs<string>("Sex")) 
    (fun k r -> r.GetAs<bool>("Survived")) 
    (fun frame -> frame?Age |> Stats.mean)
|> round

この結果から、年配の男性は若者に比べて生存率が低い一方、 年配の女性は若者に比べて生存率が高いことがわかります:

False

True

male

32

27

female

25

29

階層的インデックシング

一部のデータセットではインデックスが単純なキーのシーケンスではなく、 さらに複雑な階層構造をなしている場合があります。 これは階層的インデックスを使用することで処理することができます。 また多次元データを簡単に処理する方法もあります。 マルチレベルインデックスは最も一般的にはグループ化によって生成されます (先のセクションにいくつか例があります)。

世界銀行データセットのルックアップ

このセクションでは 先ほど使用したものと同じ、世界銀行のデータセット を見ていくことにします。 これは2レベルの列階層を持ったデータフレームで、 1レベル目が地域名、2レベル名が国名になっています。

基礎的なルックアップ操作としてはスライシング処理があります。 以下のコードはF# 3.1においてのみ有効です:

1: 
2: 
3: 
4: 
5: 
6: 
// ユーロエリアの全国を取得します
world.Columns.["Euro area", *]
// ユーロエリアグループからベルギー(Belgium)のデータを取得します
world.Columns.[("Euro area", "Belgium")]
// ベルギーはユーロとOECD両方に属するため2つデータが返されます
world.Columns.[*, "Belgium"]

F# 3.0の場合には以下のように LookupXOfY 系のヘルパ関数を使用します:

1: 
2: 
3: 
4: 
// ユーロエリアの全国を取得します
world.Columns.[Lookup1Of2 "Euro area"]
// ベルギーはユーロとOECD両方に属するため2つデータが返されます
world.Columns.[Lookup2Of2 "Belgium"]

ルックアップ操作では常に元のフレームと同じ型のデータフレームが返されます。 これはつまり1つのサブグループを選択したとしても、 マルチレベル階層キーを持った同じフレームを取得し直すことができるということです。 この動作はキーに対する射影を行うことで簡単に変更できます:

1: 
2: 
3: 
4: 
// 1レベル目のキーを除去します(そして国名だけを取得します)
let euro = 
  world.Columns.["Euro area", *]
  |> Frame.mapColKeys snd

世界銀行のデータに対するグループ化および集計

階層的キーはグループ化の結果として生成されることがよくあります。 たとえばユーロ地区のデータセットに対して10年単位で行をグループ化することができます (グループ化の詳細についてはこのドキュメント内にある グループ化のセクション を参照してください)。

 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
11: 
let decades = euro |> Frame.groupRowsUsing (fun k _ -> 
  sprintf "%d0s" (k / 10))
 
val decades : Frame<(string * int),string> =
                Austria  Estonia   ...      
  1960s 1960 -> 6.592    <missing> 
        1961 -> 7.311    <missing> 
        ...  
  2010s 2010 -> 376.8    18.84 
        2011 -> 417.6    22.15 
        2012 -> 399.6    21.85 

これで階層的インデックスを持ったデータフレームが用意出来たので、 たとえば1990年代のような1つのグループから データを選択することが出来るようになりました。 その結果は同じ型を持ったデータフレームです。 値それぞれを積算すれば、USドル基準の(10億単位ではない)元々のGDPを計算できます:

1: 
decades.Rows.["1990s", *] * 1e9

Frame および Series モジュールには集計やグループ化を行うための関数が 多数定義されています。 たとえば特定の国データを取得してその国のGDPを集計したり、 データセット全体に対して集計を行ったりすることもできます:

 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
11: 
12: 
// スロヴァキアの10年単位の平均値を計算します
decades?``Slovak Republic`` |> Stats.levelMean fst

// 全国の10年単位の平均値を計算します
decades
|> Frame.getNumericColumns 
|> Series.mapValues (Stats.levelMean fst)
|> Frame.ofColumns

// 10年単位の標準偏差をUSドル基準で計算します
decades?Belgium * 1.0e9 
|> Stats.levelStdDev fst

これまでは階層的インデックスを1つしか持たないようなデータフレームを 対象にしてきました。 しかし行と列の両方に階層的インデックスがある場合でも完璧に処理できます。 以下のスニペットではGDP平均を基準にして国をグループ化しています (さらに行を10年単位にグループ化しています):

1: 
2: 
3: 
4: 
// GDPを500ビリオン(5,000億)ドルと比較して国をグループ化します
let byGDP = 
  decades |> Frame.transpose |> Frame.groupRowsUsing (fun k v -> 
    v.As<float>() |> Stats.mean > 500.0)

(byGDP 上にマウスを移動させると) 2つの階層が型に含まれていることが確認できます。 列キーは bool * string (豊かどうかと国名)で、 行キーは string * int (10年単位および年)です。 このコードでは2つの列グループが作成されます。 1つはフランス(France)、ドイツ(Germany)、イタリア(Italy)を含む列で、 もう1つの列にはそれ以外の国が含まれます。

集計機能は(直接的には)行に対してのみサポートされますが、 Frame.transpose を使用すれば行と列を入れ替えることができます。

値無しへの対処

値無しに対するサポートは組み込みで用意されています。 つまりシリーズやフレームはいずれも値無しを含むことができます。 データからシリーズまたはフレームを構成する際に、 特定の値が自動的に「値無し」として処理されます。 具体的には Double.NaN や、参照型およびnull許容型における null が該当します:

1: 
Series.ofValues [ Double.NaN; 1.0; 3.14 ]

Keys

0

1

2

Values

N/A

1

3.14

1: 
2: 
[ Nullable(1); Nullable(); Nullable(3) ]
|> Series.ofValues

Keys

0

1

2

Values

1

N/A

3

Series.mean のような統計計算を行う場合、値無しは自動的にスキップされます。 また Series.mapValues のように、射影やフィルタリングを行う際にも無視されます。 値無しを処理したい場合には Series.mapAll を使用します。 この場合には値が option<T> として取得できます (ここでは 先のセクション で使用したサンプルデータセットを使用します):

1: 
2: 
3: 
4: 
5: 
6: 
// 値無しを含む列を取得します
let ozone = air?Ozone 

// 値無しを0に置き換えます
ozone |> Series.mapAll (fun k v -> 
  match v with None -> Some 0.0 | v -> v)

実際、 Series モジュールには値無しを より手軽に埋めるための関数が定義されているため、 Series.mapAll を使用する必要はほとんどないでしょう:

 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
11: 
12: 
13: 
14: 
// 値無しを定数値で置き換えます
ozone |> Series.fillMissingWith 0.0

// 値無しではない値が前方にコピーされて
// 値無しが埋められます
ozone |> Series.fillMissing Direction.Backward

// 値無しではない値が後方にコピーされます
// (1番目が値無しの場合にはそのまま値無しです!)
ozone |> Series.fillMissing Direction.Forward

// 値無しを埋めて、埋められなかったものを除外します
ozone |> Series.fillMissing Direction.Forward
      |> Series.dropMissing

上記以外による値無しへの対処方法についてはライブラリでは直接サポートしていませんが、 Series.fillMissingUsing を使用すれば簡単に機能を追加できます。 この関数はすべての値無しに対して呼ばれることになる関数を引数にとります。 たとえば補完関数が既にあるとして、この関数を fillMissingUsing に指定すれば 必要になる補完処理を実行することができます。

たとえば以下のスニペットでは(値無しではない)前後の値の平均か、 どちらかの値(あるいは前後が値無しの場合には0)を返すようにしています:

 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
11: 
12: 
// 補完関数を使用して値無しを置き換えます
ozone |> Series.fillMissingUsing (fun k -> 
  // 前後の値を取得します
  let prev = ozone.TryGet(k, Lookup.ExactOrSmaller)
  let next = ozone.TryGet(k, Lookup.ExactOrGreater)
  // 利用可能な値に応じたパターンマッチ
  match prev, next with 
  | OptionalValue.Present(p), OptionalValue.Present(n) -> 
      (p + n) / 2.0
  | OptionalValue.Present(v), _ 
  | _, OptionalValue.Present(v) -> v
  | _ -> 0.0)
val titanic : Frame<int,string>

Full name: Frame.titanic
Multiple items
module Frame

from Deedle

--------------------
type Frame =
  static member CreateEmpty : unit -> Frame<'R,'C> (requires equality and equality)
  static member FromArray2D : array:'T [,] -> Frame<int,int>
  static member FromColumns : cols:Series<'TColKey,Series<'TRowKey,'V>> -> Frame<'TRowKey,'TColKey> (requires equality and equality)
  static member FromColumns : cols:Series<'TColKey,ObjectSeries<'TRowKey>> -> Frame<'TRowKey,'TColKey> (requires equality and equality)
  static member FromColumns : columns:seq<KeyValuePair<'ColKey,ObjectSeries<'RowKey>>> -> Frame<'RowKey,'ColKey> (requires equality and equality)
  static member FromColumns : columns:seq<KeyValuePair<'ColKey,Series<'RowKey,'V>>> -> Frame<'RowKey,'ColKey> (requires equality and equality)
  static member FromColumns : rows:seq<Series<'ColKey,'V>> -> Frame<'ColKey,int> (requires equality)
  static member FromRecords : values:seq<'T> -> Frame<int,string>
  static member FromRecords : series:Series<'K,'R> -> Frame<'K,string> (requires equality)
  static member FromRowKeys : keys:seq<'K> -> Frame<'K,string> (requires equality)
  ...

Full name: Deedle.Frame

--------------------
type Frame<'TRowKey,'TColumnKey (requires equality and equality)> =
  interface IDynamicMetaObjectProvider
  interface INotifyCollectionChanged
  interface IFsiFormattable
  interface IFrame
  new : names:seq<'TColumnKey> * columns:seq<ISeries<'TRowKey>> -> Frame<'TRowKey,'TColumnKey>
  private new : rowIndex:IIndex<'TRowKey> * columnIndex:IIndex<'TColumnKey> * data:IVector<IVector> -> Frame<'TRowKey,'TColumnKey>
  member AddColumn : column:'TColumnKey * series:ISeries<'TRowKey> -> unit
  member AddColumn : column:'TColumnKey * series:seq<'V> -> unit
  member AddColumn : column:'TColumnKey * series:ISeries<'TRowKey> * lookup:Lookup -> unit
  member AddColumn : column:'TColumnKey * series:seq<'V> * lookup:Lookup -> unit
  ...

Full name: Deedle.Frame<_,_>

--------------------
new : names:seq<'TColumnKey> * columns:seq<ISeries<'TRowKey>> -> Frame<'TRowKey,'TColumnKey>
static member Frame.ReadCsv : path:string * ?hasHeaders:bool * ?inferTypes:bool * ?inferRows:int * ?schema:string * ?separators:string * ?culture:string * ?maxRows:int -> Frame<int,string>
static member Frame.ReadCsv : stream:Stream * ?hasHeaders:bool * ?inferTypes:bool * ?inferRows:int * ?schema:string * ?separators:string * ?culture:string * ?maxRows:int -> Frame<int,string>
val root : string

Full name: Frame.root
val msft : Frame<DateTime,string>

Full name: Frame.msft
val indexRowsDate : column:'C -> frame:Frame<'R1,'C> -> Frame<DateTime,'C> (requires equality and equality)

Full name: Deedle.Frame.indexRowsDate
val sortRowsByKey : frame:Frame<'R,'C> -> Frame<'R,'C> (requires equality and equality)

Full name: Deedle.Frame.sortRowsByKey
val air : Frame<int,string>

Full name: Frame.air
member Frame.SaveCsv : path:string * keyNames:seq<string> -> unit
static member FrameExtensions.SaveCsv : frame:Frame<'R,'C> * path:string * keyNames:seq<string> * separator:char * culture:Globalization.CultureInfo -> unit (requires equality and equality)
static member FrameExtensions.SaveCsv : frame:Frame<'R,'C> * stream:Stream * includeRowKeys:bool * keyNames:seq<string> * separator:char * culture:Globalization.CultureInfo -> unit (requires equality and equality)
static member FrameExtensions.SaveCsv : frame:Frame<'R,'C> * path:string * includeRowKeys:bool * keyNames:seq<string> * separator:char * culture:Globalization.CultureInfo -> unit (requires equality and equality)
member Frame.SaveCsv : stream:Stream * ?includeRowKeys:bool * ?keyNames:seq<string> * ?separator:char * ?culture:Globalization.CultureInfo -> unit
member Frame.SaveCsv : path:string * ?includeRowKeys:bool * ?keyNames:seq<string> * ?separator:char * ?culture:Globalization.CultureInfo -> unit
type Path =
  static val DirectorySeparatorChar : char
  static val AltDirectorySeparatorChar : char
  static val VolumeSeparatorChar : char
  static val InvalidPathChars : char[]
  static val PathSeparator : char
  static member ChangeExtension : path:string * extension:string -> string
  static member Combine : params paths:string[] -> string + 3 overloads
  static member GetDirectoryName : path:string -> string
  static member GetExtension : path:string -> string
  static member GetFileName : path:string -> string
  ...

Full name: System.IO.Path
Path.GetTempFileName() : string
type Person =
  {Name: string;
   Age: int;
   Countries: string list;}

Full name: Frame.Person
Person.Name: string
Multiple items
val string : value:'T -> string

Full name: Microsoft.FSharp.Core.Operators.string

--------------------
type string = String

Full name: Microsoft.FSharp.Core.string
Person.Age: int
Multiple items
val int : value:'T -> int (requires member op_Explicit)

Full name: Microsoft.FSharp.Core.Operators.int

--------------------
type int = int32

Full name: Microsoft.FSharp.Core.int

--------------------
type int<'Measure> = int

Full name: Microsoft.FSharp.Core.int<_>
Person.Countries: string list
type 'T list = List<'T>

Full name: Microsoft.FSharp.Collections.list<_>
val peopleRecds : Person list

Full name: Frame.peopleRecds
val peopleList : Frame<int,string>

Full name: Frame.peopleList
static member Frame.ofRecords : series:Series<'K,'R> -> Frame<'K,string> (requires equality)
static member Frame.ofRecords : values:seq<'T> -> Frame<int,string>
val people : Frame<string,string>

Full name: Frame.people
val indexRowsString : column:'C -> frame:Frame<'R1,'C> -> Frame<string,'C> (requires equality and equality)

Full name: Deedle.Frame.indexRowsString
member Frame.GetColumn : column:'TColumnKey -> Series<'TRowKey,'R>
member Frame.GetColumn : column:'TColumnKey * lookup:Lookup -> Series<'TRowKey,'R>
val wb : WorldBankData.ServiceTypes.WorldBankDataService

Full name: Frame.wb
type WorldBankData =
  static member GetDataContext : unit -> WorldBankDataService
  nested type ServiceTypes

Full name: FSharp.Data.WorldBankData


<summary>Typed representation of WorldBank data. See http://www.worldbank.org for terms and conditions.</summary>
WorldBankData.GetDataContext() : WorldBankData.ServiceTypes.WorldBankDataService
val loadRegion : region:WorldBankData.ServiceTypes.Region -> Frame<int,(string * string)>

Full name: Frame.loadRegion


 特定の地域に対して、GDPを現在のUSドルでロードし、
 2レベルの列キー(地域と国名)を持ったフレームとしてデータを返します
val region : WorldBankData.ServiceTypes.Region
type ServiceTypes =
  nested type Countries
  nested type Country
  nested type Indicators
  nested type IndicatorsDescriptions
  nested type Region
  nested type Regions
  nested type Topic
  nested type Topics
  nested type WorldBankDataService

Full name: FSharp.Data.WorldBankData.ServiceTypes


<summary>Contains the types that describe the data service</summary>
type Region =
  inherit Region
  member Countries : Countries
  member Indicators : Indicators
  member Name : string
  member RegionCode : string

Full name: FSharp.Data.WorldBankData.ServiceTypes.Region
val country : WorldBankData.ServiceTypes.Country
property WorldBankData.ServiceTypes.Region.Countries: WorldBankData.ServiceTypes.Countries


<summary>The indicators for the region</summary>
property Runtime.WorldBank.Region.Name: string
property Runtime.WorldBank.Country.Name: string
Multiple items
module Series

from Deedle

--------------------
type Series =
  static member ofNullables : values:seq<Nullable<'a0>> -> Series<int,'a0> (requires default constructor and value type and 'a0 :> ValueType)
  static member ofObservations : observations:seq<'a0 * 'a1> -> Series<'a0,'a1> (requires equality)
  static member ofOptionalObservations : observations:seq<'K * 'a1 option> -> Series<'K,'a1> (requires equality)
  static member ofValues : values:seq<'a0> -> Series<int,'a0>

Full name: Deedle.FSharpSeriesExtensions.Series

--------------------
type Series<'K,'V (requires equality)> =
  interface IFsiFormattable
  interface ISeries<'K>
  new : pairs:seq<KeyValuePair<'K,'V>> -> Series<'K,'V>
  new : keys:seq<'K> * values:seq<'V> -> Series<'K,'V>
  new : index:IIndex<'K> * vector:IVector<'V> * vectorBuilder:IVectorBuilder * indexBuilder:IIndexBuilder -> Series<'K,'V>
  member After : lowerExclusive:'K -> Series<'K,'V>
  member Aggregate : aggregation:Aggregation<'K> * observationSelector:Func<DataSegment<Series<'K,'V>>,KeyValuePair<'TNewKey,OptionalValue<'R>>> -> Series<'TNewKey,'R> (requires equality)
  member Aggregate : aggregation:Aggregation<'K> * keySelector:Func<DataSegment<Series<'K,'V>>,'TNewKey> * valueSelector:Func<DataSegment<Series<'K,'V>>,OptionalValue<'R>> -> Series<'TNewKey,'R> (requires equality)
  member AsyncMaterialize : unit -> Async<Series<'K,'V>>
  member Before : upperExclusive:'K -> Series<'K,'V>
  ...

Full name: Deedle.Series<_,_>

--------------------
new : pairs:seq<Collections.Generic.KeyValuePair<'K,'V>> -> Series<'K,'V>
new : keys:seq<'K> * values:seq<'V> -> Series<'K,'V>
new : index:Indices.IIndex<'K> * vector:IVector<'V> * vectorBuilder:Vectors.IVectorBuilder * indexBuilder:Indices.IIndexBuilder -> Series<'K,'V>
static member Series.ofObservations : observations:seq<'a0 * 'a1> -> Series<'a0,'a1> (requires equality)
property WorldBankData.ServiceTypes.Country.Indicators: WorldBankData.ServiceTypes.Indicators


<summary>The indicators for the country</summary>
val frame : columns:seq<'a * #ISeries<'c>> -> Frame<'c,'a> (requires equality and equality)

Full name: Deedle.FSharpFrameExtensions.frame
val eu : Frame<int,(string * string)>

Full name: Frame.eu
property WorldBankData.ServiceTypes.WorldBankDataService.Regions: WorldBankData.ServiceTypes.Regions
val oecd : Frame<int,(string * string)>

Full name: Frame.oecd
val world : Frame<int,(string * string)>

Full name: Frame.world
member Frame.Join : otherFrame:Frame<'TRowKey,'TColumnKey> -> Frame<'TRowKey,'TColumnKey>
member Frame.Join : colKey:'TColumnKey * series:Series<'TRowKey,'V> -> Frame<'TRowKey,'TColumnKey>
member Frame.Join : otherFrame:Frame<'TRowKey,'TColumnKey> * kind:JoinKind -> Frame<'TRowKey,'TColumnKey>
member Frame.Join : colKey:'TColumnKey * series:Series<'TRowKey,'V> * kind:JoinKind -> Frame<'TRowKey,'TColumnKey>
member Frame.Join : otherFrame:Frame<'TRowKey,'TColumnKey> * kind:JoinKind * lookup:Lookup -> Frame<'TRowKey,'TColumnKey>
member Frame.Join : colKey:'TColumnKey * series:Series<'TRowKey,'V> * kind:JoinKind * lookup:Lookup -> Frame<'TRowKey,'TColumnKey>
val peopleNested : Frame<int,string>

Full name: Frame.peopleNested
static member Series.ofValues : values:seq<'a0> -> Series<int,'a0>
val expandCols : names:seq<string> -> frame:Frame<'R,string> -> Frame<'R,string> (requires equality)

Full name: Deedle.Frame.expandCols
val tuples : Series<int,Collections.Generic.IDictionary<string,obj>>

Full name: Frame.tuples
val dict : keyValuePairs:seq<'Key * 'Value> -> Collections.Generic.IDictionary<'Key,'Value> (requires equality)

Full name: Microsoft.FSharp.Core.ExtraTopLevelOperators.dict
val box : value:'T -> obj

Full name: Microsoft.FSharp.Core.Operators.box
val expandAllCols : nesting:int -> frame:Frame<'R,string> -> Frame<'R,string> (requires equality)

Full name: Deedle.Frame.expandAllCols
property Frame.Columns: ColumnSeries<string,string>
val numAges : Series<string,float>

Full name: Frame.numAges
member Series.Get : key:'K -> 'V
member Series.Get : key:'K * lookup:Lookup -> 'V
member Series.TryGet : key:'K -> OptionalValue<'V>
member Series.TryGet : key:'K * lookup:Lookup -> OptionalValue<'V>
member Series.GetAt : index:int -> 'V
member ObjectSeries.As : unit -> Series<'K,'R>
property Frame.Rows: RowSeries<string,string>
val mapValues : f:('T -> 'R) -> series:Series<'K,'T> -> Series<'K,'R> (requires equality)

Full name: Deedle.Series.mapValues
val row : ObjectSeries<string>
member ObjectSeries.GetAs : column:'K -> 'R
member ObjectSeries.GetAs : column:'K * fallback:'R -> 'R
val more : Series<string,float>

Full name: Frame.more
val series : observations:seq<'a * 'b> -> Series<'a,'b> (requires equality)

Full name: Deedle.FSharpSeriesExtensions.series
val add1 : Series<string,float>

Full name: Frame.add1
member Frame.ReplaceColumn : column:'TColumnKey * data:seq<'V> -> unit
member Frame.ReplaceColumn : column:'TColumnKey * series:ISeries<'TRowKey> -> unit
member Frame.ReplaceColumn : column:'TColumnKey * data:seq<'V> * lookup:Lookup -> unit
member Frame.ReplaceColumn : column:'TColumnKey * series:ISeries<'TRowKey> * lookup:Lookup -> unit
val newRow : Series<string,obj>

Full name: Frame.newRow
member Frame.Merge : params otherFrames:Frame<'TRowKey,'TColumnKey> [] -> Frame<'TRowKey,'TColumnKey>
member Frame.Merge : otherFrames:seq<Frame<'TRowKey,'TColumnKey>> -> Frame<'TRowKey,'TColumnKey>
member Frame.Merge : otherFrame:Frame<'TRowKey,'TColumnKey> -> Frame<'TRowKey,'TColumnKey>
static member FrameExtensions.Merge : frame:Frame<'TRowKey,'TColumnKey> * rowKey:'TRowKey * row:ISeries<'TColumnKey> -> Frame<'TRowKey,'TColumnKey> (requires equality and equality)
val otherRow : SeriesBuilder<string>

Full name: Frame.otherRow
Multiple items
type SeriesBuilder<'K (requires equality)> =
  inherit SeriesBuilder<'K,obj>
  new : unit -> SeriesBuilder<'K>

Full name: Deedle.SeriesBuilder<_>

--------------------
type SeriesBuilder<'K,'V (requires equality and equality)> =
  interface IDynamicMetaObjectProvider
  interface IDictionary<'K,'V>
  interface seq<KeyValuePair<'K,'V>>
  interface IEnumerable
  new : unit -> SeriesBuilder<'K,'V>
  member Add : key:'K * value:'V -> unit
  member Series : Series<'K,'V>
  static member ( ?<- ) : builder:SeriesBuilder<string,'V> * name:string * value:'V -> unit

Full name: Deedle.SeriesBuilder<_,_>

--------------------
new : unit -> SeriesBuilder<'K>

--------------------
new : unit -> SeriesBuilder<'K,'V>
property SeriesBuilder.Series: Series<string,obj>
val nums : Series<int,float>

Full name: Frame.nums
val strs : Series<string,string>

Full name: Frame.strs
val ages : Series<string,float>

Full name: Frame.ages
val get : key:'K -> series:Series<'K,'T> -> 'T (requires equality)

Full name: Deedle.Series.get
val nan : float

Full name: Microsoft.FSharp.Core.Operators.nan
val tryGet : key:'K -> series:Series<'K,'T> -> 'T option (requires equality)

Full name: Deedle.Series.tryGet
val getAll : keys:seq<'K> -> series:Series<'K,'T> -> Series<'K,'T> (requires equality)

Full name: Deedle.Series.getAll
property Series.Observations: seq<Collections.Generic.KeyValuePair<string,float>>
val observations : series:Series<'K,'T> -> seq<'K * 'T> (requires equality)

Full name: Deedle.Series.observations
val observationsAll : series:Series<'K,'T> -> seq<'K * 'T option> (requires equality)

Full name: Deedle.Series.observationsAll
val opens : Series<DateTime,float>

Full name: Frame.opens
Multiple items
type DateTime =
  struct
    new : ticks:int64 -> DateTime + 10 overloads
    member Add : value:TimeSpan -> DateTime
    member AddDays : value:float -> DateTime
    member AddHours : value:float -> DateTime
    member AddMilliseconds : value:float -> DateTime
    member AddMinutes : value:float -> DateTime
    member AddMonths : months:int -> DateTime
    member AddSeconds : value:float -> DateTime
    member AddTicks : value:int64 -> DateTime
    member AddYears : value:int -> DateTime
    ...
  end

Full name: System.DateTime

--------------------
DateTime()
   (+0 other overloads)
DateTime(ticks: int64) : unit
   (+0 other overloads)
DateTime(ticks: int64, kind: DateTimeKind) : unit
   (+0 other overloads)
DateTime(year: int, month: int, day: int) : unit
   (+0 other overloads)
DateTime(year: int, month: int, day: int, calendar: Globalization.Calendar) : unit
   (+0 other overloads)
DateTime(year: int, month: int, day: int, hour: int, minute: int, second: int) : unit
   (+0 other overloads)
DateTime(year: int, month: int, day: int, hour: int, minute: int, second: int, kind: DateTimeKind) : unit
   (+0 other overloads)
DateTime(year: int, month: int, day: int, hour: int, minute: int, second: int, calendar: Globalization.Calendar) : unit
   (+0 other overloads)
DateTime(year: int, month: int, day: int, hour: int, minute: int, second: int, millisecond: int) : unit
   (+0 other overloads)
DateTime(year: int, month: int, day: int, hour: int, minute: int, second: int, millisecond: int, kind: DateTimeKind) : unit
   (+0 other overloads)
val e : exn
type Lookup =
  | Exact = 1
  | ExactOrGreater = 3
  | ExactOrSmaller = 5
  | Greater = 2
  | Smaller = 4

Full name: Deedle.Lookup
Lookup.ExactOrSmaller: Lookup = 5
val lookup : key:'K -> lookup:Lookup -> series:Series<'K,'T> -> 'T (requires equality)

Full name: Deedle.Series.lookup
Lookup.ExactOrGreater: Lookup = 3
val dates : DateTime list

Full name: Frame.dates
val m : int
val lookupAll : keys:seq<'K> -> lookup:Lookup -> series:Series<'K,'T> -> Series<'K,'T> (requires equality)

Full name: Deedle.Series.lookupAll
val mapKeys : f:('K -> 'R) -> series:Series<'K,'T> -> Series<'R,'T> (requires equality and equality)

Full name: Deedle.Series.mapKeys
val k : DateTime
DateTime.ToShortDateString() : string
val travels : Series<string,string list>

Full name: Frame.travels
val groupBy : keySelector:('K -> 'T -> 'TNewKey) -> series:Series<'K,'T> -> Series<'TNewKey,Series<'K,'T>> (requires equality and equality)

Full name: Deedle.Series.groupBy
val k : string
val v : string list
property String.Length: int
Multiple items
module List

from Microsoft.FSharp.Collections

--------------------
type List<'T> =
  | ( [] )
  | ( :: ) of Head: 'T * Tail: 'T list
  interface IEnumerable
  interface IEnumerable<'T>
  member Head : 'T
  member IsEmpty : bool
  member Item : index:int -> 'T with get
  member Length : int
  member Tail : 'T list
  static member Cons : head:'T * tail:'T list -> 'T list
  static member Empty : 'T list

Full name: Microsoft.FSharp.Collections.List<_>
val exists : predicate:('T -> bool) -> list:'T list -> bool

Full name: Microsoft.FSharp.Collections.List.exists
val groupInto : keySelector:('K -> 'T -> 'TNewKey) -> f:('TNewKey -> Series<'K,'T> -> 'TNewValue) -> series:Series<'K,'T> -> Series<'TNewKey,'TNewValue> (requires equality and equality)

Full name: Deedle.Series.groupInto
val len : int
val people : Series<string,string list>
val countKeys : series:Series<'K,'T> -> int (requires equality)

Full name: Deedle.Series.countKeys
module Seq

from Microsoft.FSharp.Collections
val countBy : projection:('T -> 'Key) -> source:seq<'T> -> seq<'Key * int> (requires equality)

Full name: Microsoft.FSharp.Collections.Seq.countBy
val id : x:'T -> 'T

Full name: Microsoft.FSharp.Core.Operators.id
static member Frame.ofRows : rows:seq<'a0 * #ISeries<'a2>> -> Frame<'a0,'a2> (requires equality and equality)
static member Frame.ofRows : rows:Series<'a0,#ISeries<'a2>> -> Frame<'a0,'a2> (requires equality and equality)
val fillMissingWith : value:'T -> frame:Frame<'R,'C> -> Frame<'R,'C> (requires equality and equality)

Full name: Deedle.Frame.fillMissingWith
val groupRowsByString : column:'C -> frame:Frame<'R,'C> -> Frame<(string * 'R),'C> (requires equality and equality)

Full name: Deedle.Frame.groupRowsByString
val byDecimal : Frame<(decimal * int),string>

Full name: Frame.byDecimal
Multiple items
val decimal : value:'T -> decimal (requires member op_Explicit)

Full name: Microsoft.FSharp.Core.Operators.decimal

--------------------
type decimal = Decimal

Full name: Microsoft.FSharp.Core.decimal

--------------------
type decimal<'Measure> = decimal

Full name: Microsoft.FSharp.Core.decimal<_>
val groupRowsBy : column:'C -> frame:Frame<'R,'C> -> Frame<('K * 'R),'C> (requires equality and equality and equality)

Full name: Deedle.Frame.groupRowsBy
member Frame.GroupRowsBy : colKey:'TColumnKey -> Frame<('TGroup * 'TRowKey),'TColumnKey> (requires equality)
val groupRowsUsing : selector:('R -> ObjectSeries<'C> -> 'K) -> frame:Frame<'R,'C> -> Frame<('K * 'R),'C> (requires equality and equality and equality)

Full name: Deedle.Frame.groupRowsUsing
val k : int
val bySex : Frame<(string * int),string>

Full name: Frame.bySex
val bySex1 : Series<string,Frame<int,string>>

Full name: Frame.bySex1
val nest : frame:Frame<('R1 * 'R2),'C> -> Series<'R1,Frame<'R2,'C>> (requires equality and equality and equality)

Full name: Deedle.Frame.nest
val bySex2 : Frame<(string * int),string>

Full name: Frame.bySex2
val unnest : series:Series<'R1,Frame<'R2,'C>> -> Frame<('R1 * 'R2),'C> (requires equality and equality and equality)

Full name: Deedle.Frame.unnest
val byClassAndPort : Frame<(string * int * int),string>

Full name: Frame.byClassAndPort
val groupRowsByInt : column:'C -> frame:Frame<'R,'C> -> Frame<(int * 'R),'C> (requires equality and equality)

Full name: Deedle.Frame.groupRowsByInt
val mapRowKeys : f:('R1 -> 'R2) -> frame:Frame<'R1,'C> -> Frame<'R2,'C> (requires equality and equality and equality)

Full name: Deedle.Frame.mapRowKeys
module Pair

from Deedle
val flatten3 : v1:'a * ('b * 'c) -> 'a * 'b * 'c

Full name: Deedle.Pair.flatten3
val ageByClassAndPort : Series<(string * int * int),float>

Full name: Frame.ageByClassAndPort
type Stats =
  static member count : frame:Frame<'R,'C> -> Series<'C,int> (requires equality and equality)
  static member count : series:Series<'K,'V> -> int (requires equality)
  static member expandingCount : series:Series<'K,float> -> Series<'K,float> (requires equality)
  static member expandingKurt : series:Series<'K,float> -> Series<'K,float> (requires equality)
  static member expandingMax : series:Series<'K,float> -> Series<'K,float> (requires equality)
  static member expandingMean : series:Series<'K,float> -> Series<'K,float> (requires equality)
  static member expandingMin : series:Series<'K,float> -> Series<'K,float> (requires equality)
  static member expandingSkew : series:Series<'K,float> -> Series<'K,float> (requires equality)
  static member expandingStdDev : series:Series<'K,float> -> Series<'K,float> (requires equality)
  static member expandingSum : series:Series<'K,float> -> Series<'K,float> (requires equality)
  ...

Full name: Deedle.Stats
static member Stats.levelMean : level:('K -> 'L) -> series:Series<'K,float> -> Series<'L,float> (requires equality and equality)
val get1And2Of3 : v1:'a * v2:'b * 'c -> 'a * 'b

Full name: Deedle.Pair.get1And2Of3
val getNumericCols : frame:Frame<'R,'C> -> Series<'C,Series<'R,float>> (requires equality and equality)

Full name: Deedle.Frame.getNumericCols
val dropMissing : series:Series<'K,'T> -> Series<'K,'T> (requires equality)

Full name: Deedle.Series.dropMissing
static member Frame.ofColumns : cols:Series<'a0,#ISeries<'a2>> -> Frame<'a2,'a0> (requires equality and equality)
static member Frame.ofColumns : cols:seq<'a0 * #ISeries<'K>> -> Frame<'K,'a0> (requires equality and equality)
type bool = Boolean

Full name: Microsoft.FSharp.Core.bool
val applyLevel : level:('K1 -> 'K2) -> op:(Series<'K1,'V> -> 'R) -> series:Series<'K1,'V> -> Series<'K2,'R> (requires equality and equality)

Full name: Deedle.Series.applyLevel
val values : series:Series<'K,'T> -> seq<'T> (requires equality)

Full name: Deedle.Series.values
val pivotTable : rowGrp:('R -> ObjectSeries<'C> -> 'RNew) -> colGrp:('R -> ObjectSeries<'C> -> 'CNew) -> op:(Frame<'R,'C> -> 'T) -> frame:Frame<'R,'C> -> Frame<'RNew,'CNew> (requires equality and equality and equality and equality)

Full name: Deedle.Frame.pivotTable
val r : ObjectSeries<string>
val countRows : frame:Frame<'R,'C> -> int (requires equality and equality)

Full name: Deedle.Frame.countRows
val frame : Frame<int,string>
static member Stats.mean : frame:Frame<'R,'C> -> Series<'C,float> (requires equality and equality)
static member Stats.mean : series:Series<'K,float> -> float (requires equality)
val round : value:'T -> 'T (requires member Round)

Full name: Microsoft.FSharp.Core.Operators.round
property Frame.Columns: ColumnSeries<int,(string * string)>
val Lookup1Of2 : k:'a -> ICustomLookup<'b>

Full name: Deedle.MultiKeyExtensions.Lookup1Of2
val Lookup2Of2 : k:'a -> ICustomLookup<'b>

Full name: Deedle.MultiKeyExtensions.Lookup2Of2
val euro : Frame<int,string>

Full name: Frame.euro
val mapColKeys : f:('C -> 'a) -> frame:Frame<'R,'C> -> Frame<'R,'a> (requires equality and equality and equality)

Full name: Deedle.Frame.mapColKeys
val snd : tuple:('T1 * 'T2) -> 'T2

Full name: Microsoft.FSharp.Core.Operators.snd
val decades : Frame<(string * int),string>

Full name: Frame.decades
val sprintf : format:Printf.StringFormat<'T> -> 'T

Full name: Microsoft.FSharp.Core.ExtraTopLevelOperators.sprintf
property Frame.Rows: RowSeries<(string * int),string>
val fst : tuple:('T1 * 'T2) -> 'T1

Full name: Microsoft.FSharp.Core.Operators.fst
static member Stats.levelStdDev : level:('K -> 'L) -> series:Series<'K,float> -> Series<'L,float> (requires equality and equality)
val byGDP : Frame<(bool * string),(string * int)>

Full name: Frame.byGDP
val transpose : frame:Frame<'R,'TColumnKey> -> Frame<'TColumnKey,'R> (requires equality and equality)

Full name: Deedle.Frame.transpose
val v : ObjectSeries<string * int>
Multiple items
val float : value:'T -> float (requires member op_Explicit)

Full name: Microsoft.FSharp.Core.Operators.float

--------------------
type float = Double

Full name: Microsoft.FSharp.Core.float

--------------------
type float<'Measure> = float

Full name: Microsoft.FSharp.Core.float<_>
type Double =
  struct
    member CompareTo : value:obj -> int + 1 overload
    member Equals : obj:obj -> bool + 1 overload
    member GetHashCode : unit -> int
    member GetTypeCode : unit -> TypeCode
    member ToString : unit -> string + 3 overloads
    static val MinValue : float
    static val MaxValue : float
    static val Epsilon : float
    static val NegativeInfinity : float
    static val PositiveInfinity : float
    ...
  end

Full name: System.Double
field float.NaN = NaN
Multiple items
type Nullable =
  static member Compare<'T> : n1:Nullable<'T> * n2:Nullable<'T> -> int
  static member Equals<'T> : n1:Nullable<'T> * n2:Nullable<'T> -> bool
  static member GetUnderlyingType : nullableType:Type -> Type

Full name: System.Nullable

--------------------
type Nullable<'T (requires default constructor and value type and 'T :> ValueType)> =
  struct
    new : value:'T -> Nullable<'T>
    member Equals : other:obj -> bool
    member GetHashCode : unit -> int
    member GetValueOrDefault : unit -> 'T + 1 overload
    member HasValue : bool
    member ToString : unit -> string
    member Value : 'T
  end

Full name: System.Nullable<_>

--------------------
Nullable()
Nullable(value: 'T) : unit
val ozone : Series<int,float>

Full name: Frame.ozone
val mapAll : f:('K -> 'T option -> 'R option) -> series:Series<'K,'T> -> Series<'K,'R> (requires equality)

Full name: Deedle.Series.mapAll
val v : float option
union case Option.None: Option<'T>
union case Option.Some: Value: 'T -> Option<'T>
val fillMissingWith : value:'a -> series:Series<'K,'T> -> Series<'K,'T> (requires equality)

Full name: Deedle.Series.fillMissingWith
val fillMissing : direction:Direction -> series:Series<'K,'T> -> Series<'K,'T> (requires equality)

Full name: Deedle.Series.fillMissing
type Direction =
  | Backward = 0
  | Forward = 1

Full name: Deedle.Direction
Direction.Backward: Direction = 0
Direction.Forward: Direction = 1
val fillMissingUsing : f:('K -> 'T) -> series:Series<'K,'T> -> Series<'K,'T> (requires equality)

Full name: Deedle.Series.fillMissingUsing
val prev : OptionalValue<float>
val next : OptionalValue<float>
Multiple items
module OptionalValue

from Deedle

--------------------
type OptionalValue =
  static member Create : v:'a0 -> OptionalValue<'a0>
  static member Empty : unit -> OptionalValue<'T>
  static member OfNullable : v:Nullable<'T> -> OptionalValue<'T> (requires default constructor and value type and 'T :> ValueType)

Full name: Deedle.OptionalValue

--------------------
type OptionalValue<'T> =
  struct
    new : value:'T -> OptionalValue<'T>
    private new : hasValue:bool * value:'T -> OptionalValue<'T>
    override Equals : y:obj -> bool
    override GetHashCode : unit -> int
    override ToString : unit -> string
    member HasValue : bool
    member Value : 'T
    member ValueOrDefault : 'T
    static member Missing : OptionalValue<'T>
  end

Full name: Deedle.OptionalValue<_>

--------------------
OptionalValue()
new : value:'T -> OptionalValue<'T>
active recognizer Present: 'T opt -> Choice<unit,'T>

Full name: Deedle.OptionalValue.( |Missing|Present| )
val p : float
val n : float
val v : float
Fork me on GitHub