OSSにissueを立てた話


## はじめに
アドベントカレンダー7日目の記事です

https://qiita.com/advent-calendar/2022/hrbrain

HRBrainでバックエンドエンジニアをやっている入中です。
OSSにissueを立てようと思った経緯、実際にissueを立てるまでに行ったことを書きます。

## 誰に向けた記事

- OSSを使ったプロダクト開発を行っているエンジニア

OSSを使用していて、あれこの機能まだ実装されていないんだ...や
期待挙動が返ってこないな...という経験があった場合にissueをあげてみたいんだけど...
と思って躊躇している方の参考になればと思います。

## 経緯

HRBrainでは現在`goban`というOSS開発を行っています。
(詳しくは[HRBrainアドベントカレンダー1の1日目](https://qiita.com/yuonoda/items/22a6dd04eb18b4dca240)の@yuonodaさんの記事を御覧ください！)
そのOSS開発のContributorとなることを決意しました。

そこであてられた`good first issue` が`集計関数Median(中央値)`を返すメソッド追加するtaskでした。
`goban`では、[Gonumライブラリ](https://github.com/gonum/gonum)を一部使用しています。
今回のMedianメソッドも、Gonumを用いて実装しようと考えました。
ですが、引数として渡す値の数が偶数の場合に、期待している中央値の値が返ってきませんでした。

実装したmedianメソッド

```median.go

func median() {
	xs := []float64{2, 3, 5, 9}
	median := stat.Quantile(0.5, stat.LinInterp, xs, nil)

	fmt.Println(median)
    // 3
}
```

この例では、データが偶数個なので中央の2つの数字の平均値`(3 + 5) / 2 = 4`が中央値として返ってくる想定でした。

## issueを立てるまでに行ったこと

### ライブラリの中身・ドキュメントを読む

最初medianを実装をしようとしたときに参照したドキュメント

- [Gonumのドキュメントでmedian実装例があった箇所](https://www.gonum.org/post/intro_to_stats_with_gonum/)を確認。

```median.go
median := stat.Quantile(0.5, stat.Empirical, xs, nil)
```

medianの実装例が記載されており、そのとおりに動かしたのですがやはり期待挙動ではないことを確認しました。

- 使用したQuantileメソッドのコードを確認
  [gonum/stat/stat.go](https://github.com/gonum/gonum/blob/master/stat/stat.go#L1080)

stat.Quantileの実装を見ると、第2引数で渡している値で挙動が変わる仕様だったので、引数を変えてみてtry。

```median.go
median := stat.Quantile(0.5, stat.LinInterp, xs, nil)
```

期待値が返ってこないことを確認しました。

※ `LinInterp`と`Empirical`の違いはこの記事の下部に記載

### Go Playgroundで挙動の確認

自分の開発環境や利用ライブラリが事象原因である可能性を排除し、再現性がある挙動を確認した上でissueに投稿するため下記の確認をしました。

- [stat.Empirical](https://go.dev/play/p/8b6vDMunna8)の挙動確認
- [stat.LinInterp](https://go.dev/play/p/lM8ZNR0rTsi)の挙動確認

Playground上でも、期待挙動とは違う動きをすることを確認しました。

### GitHubレポジトリ内に同じ内容のissueが立っていないかの確認

![スクリーンショット 2022-11-21 0.05.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/421982/137984e4-5851-c74d-2640-482ef998f7f7.png)

※キャプチャの上から1つめのissue(#1836)は私が今回あげたissue

同じ内容のissueがあがっているかもしれないので確認したところ、
2022年11月中旬時点で、Quantileメソッドで中央値の値が取得できないというissueは立っていませんでした。

### issueを立てる

いろいろと調べた結果、やはり期待挙動とは違う動きをしていたのでissueを立てることにしました。

![スクリーンショット 2022-11-20 23.25.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/421982/260ad163-90b8-8afd-28aa-78996548727b.png)

issueには`Bug Report` `Feature request` `Proposal` `Question`の4つの分類がされており、それぞれ

- `Bug Report` : バグ報告
- `Feature request` : 既存のパッケージに対して機能を追加する要望をあげる
- `Proposal`: 新しいパッケージや、機能の仕様追加等の提案
- `Question`: 質問

今回は、期待挙動ではない動きをしていたので`Bug Report`として上げました。

#### issue

[stat.Quantile returns wrong value when dataset is even size](https://github.com/gonum/gonum/issues/1836)

#### issueを立ててからわかったこと

今回、バグとしてissueをあげたのですが、Contributorの方と話をする中で以下のことがわかりました。

- 四分位数には複数の定義が存在し、定義によって導出される値が異なる
- gonumのQuantileメソッドはR上の定義でいえば9種類の四分位計算のうち、[type1(Empirical)およびtype4(LinInterp)の2種のみを現時点でサポートしている](https://pkg.go.dev/gonum.org/v1/gonum/stat#CumulantKind)
- 今回私が期待した値は中央値（50percentile）は、type5~type9で四分位計算すると求められる

つまり、今回はContributorの方がissue内で言っているように、GonumのQuantileメソッドの**バグではなく**、四分位計算可能な定義がメソッドに定義されていなかったということでした。

![スクリーンショット 2022-12-02 19.58.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/421982/4844f84a-6425-24a7-f422-08b402c3125c.png)

上記添付画像で提示された[Rのquantileメソッドの挙動](https://paiza.io/projects/Djm2KGiyHLzu-dZQS9wHJw?language=r)

## まとめ

issueを上げてから数時間後にContributorの方々から連絡がきました。
時差があるにも関わらず、返答は1日以内で、Gonumの開発が活発なことをが実感できました。
そして、すぐに挙動確認をしてくれたり、実装にtryしてくれたりととても感激しました...

自分自身もContributorとして今回のissueに対してプルリクを上げたいなと思ったのですが、`Quantile`や`Empirical`等初めて聞く言葉ばかり且つ、統計学の知識がないためライブラリの思想等を理解してContributeするのはかなり難易度が高いと思い今回は断念しました...(統計学勉強して、Contributeできるように努めよう...)
ぜひ、統計学や数学等に強い方...Gonumでmedianメソッドの実装を試していただければ嬉しいです！

## issueの会話等ででてきた言葉のまとめ

<details><summary>Median</summary><div>

データを大きい順（または小さい順）に並べたとき、真ん中の値を`中央値（メディアン）`と言います。データの数が偶数のときは「真ん中の値」が2つ登場するのでそれらを足して2で割ったものを中央値とします。

引用: [高校数学の美しい物語](https://manabitimes.jp/math/985)

</div></details>

<details><summary>Quantile</summary><div>

データの値を小さいものから並べてq等分したときのそれぞれのグループの境界となる値

参考: [統計学「分位数」Quantile](https://www.youtube.com/watch?v=0j-KK-lsd44)

</div></details>

<details><summary>Empirical</summary><div>

経験過程は関数空間に値をとる確率変数を確率過程と呼びます。

参考: [経験過程とはなんですか](http://watanabe-www.math.dis.titech.ac.jp/users/swatanab/empirical_process.pdf)

</div></details>

<details><summary>LinInterp</summary><div>

線形補間

関数$\ y=f(x)\ $が2点$\ (x_1,x_2),\ (x_2,y_2)\ $を通ることがわかっているとする。
このとき関数$\ f(x)\ $を2点を通る線分：
```math
y = y_1 + \frac{y_2-y_1}{x_2-x_1}(x-x_1)
```
で近似する手法を線形補間と言う。

引用: [高校数学の美しい物語](https://manabitimes.jp/math/1422)

</div></details>

<details><summary>R</summary><div>

オープンソースで利用可能な統計やデータ解析に特化したプログラミング言語
引用: [【初学者向け】「R」言語とは？R言語に関してわかりやすく解説！](https://aiacademy.jp/media/?p=1123)

</div></details>

## HRBrainではエンジニアを募集しています

弊社に興味を持っていただいた方はぜひ、以下サイトからご応募ください！
https://www.hrbrain.co.jp/recruit