GitHub Sponsorsの募集を始めました、よろしくお願いします。
表題の通り、GitHub Sponsorsの審査を通過しましたので告知です。
要約
私のオープンソースソフトウェア(OSS)活動を支援するための寄付の受付を開始したので何卒一考ください。
- GitHub を利用している方は https://github.com/sponsors/uribo をご覧ください。現在、寄付金額の異なる5つの枠を用意しています。
- ☕️ buy me a coffee のアカウントもあるので、こちらからの支援も受け付けます(ニッコリ)。気軽にどうぞ https://www.buymeacoffee.com/uribo
きっかけ
GitHub Sponsorsは個人およびコミュニティのOSS活動を支援するための枠組みです。R界隈では世界の @Atsushi776 が始めたのが話題となりました(彼の告知記事。私もスポンサーになりました)。
私が得意とする言語はRです。学生時代から使っていて、まあ「ちょっとわかる」程度には使えると思っています。
Rはオープンソースで使うのにお金がかかりません。エディタとしても優秀な統合開発環境のRStudioアプリケーションも無料です。また、これまでに多くの書籍、プレゼンテーション、その他資料がインターネットで公開されてきました。
過去の人々の力に支えられている。その人たちは無償で行ってくれた。それなのに「お金儲け」をするのはどうなの?」という考えが少なからずあります。一方で仕事では前職から「ほぼR 100%」です。なので「お金稼ぎ」はしています。また書籍の執筆も少なからず行っており、それによる収入もあることも事実です。
ただ今年になって、そうした見方が変わってきました。Rは多くの研究、企業・業務でも使われる、素晴らしい言語です。そこには過去・現在・未来に豊富な人材があり、自分以上に生活の基盤としている人もいるでしょう(RStudio社はまさにそれ)。そして「技術はタダじゃない」そう思い至るようになりました。
自分の価値を低く見積もってはいけない。それはコミュニティ内の他のユーザや文化にも影響します。
なぜ支援を求めるのか
GitHub Sponsorsを始める前から、OSS活動を行う・幅を広げていく上でいくつかの課題がありました。それは次のようなものです。これらはいずれもお金で解決できる面があります。
- 英語力の向上
- 国際カンファレンス参加資金
- OSS参加のためのマシン、サーバ、サービス経費等 ... 現在の開発環境はiMac (2017) と MacBookPro (2013) がメインです。
- コミュニティ運営のモチベーション、活動経費
- R以外の言語、特にPython, Go, Juliaの学習
いくつかの項目について説明します。
OSS活動は、大別すると自分が開発者となり進めるもの、他の人・グループが中心にいる中で参画していくものがありますが、私はどちらかというと前者が中心で、グローバルなOSS活動についてはtypoの修正や簡単な機能実装等しか行えていないことが多く、まだまだ未熟さを感じています。そこには技術的な問題の他、「英語」の障壁が存在します(言語を問わず、コミュニケーション全般の課題でもありますが)。
言わずもがな、OSSでの中心言語は英語が主流です。1. 英語力の向上
はOSS活動を行う上で欠かせない能力だと捉えています。また次の2. 国際カンファレンス参加
で他の開発者と交流する際も必要となります。
Rコミュニティには2つの大きな国際カンファレンスが毎年行われています。Rユーザの集会的なuseR!は、毎回開催箇所(国)が変わる面白さがあります。もう一つのRStudio conference (rstudio::conf) はRStudio社主催で本社のあるアメリカ開催です。
カンファレンスへの参加は先端の情報や意見交換ができるだけでなく、GitHubやTwitterでお世話になっている人たちに会える絶好の機会です!一方でいずれも海外の開催&一週間ほどの滞在で個人で気軽に行くのには現実的な問題があります。(所属する企業でサポートがあると良いのですが、私の所属組織ではそうは行きません)
最後に4. コミュニティ運営のモチベーション、活動経費
です。コミュニティを維持するためには時間もお金もかかります。私はTokyo.RおよびTsukuba.Rの2つのコミュニティに関わっています。と言っても、どちらもほとんど貢献できていません。
Tokyo.Rの方は運営メンバーではありませんが、Slackコミュニティのr-wakalangの保守とRユーザと話すpodcast、R Radio for the Rest of us (R3)を継続しています。
また茨城県つくば市周辺のRユーザを対象にしたTsukuba.Rも再起動したものの、定期的に行える体制が整っていません。これは会場の確保をはじめとした各種の手続きに手間取ることが原因の一つです。コミュニティの形成は一朝一夕には行きませんが、ユーザを育てるためには欠かせないものだと信じています。私の怠惰で行えていないことは大いに反省すべきでしょう。一方でこれらの活動は完全に自らの時間と金を使って行われています。私のOSS活動の最終地点は、未来のためのユーザの育成(あるいは財産の共有)だと考えています。培った技術、情報は次世代に残していきたいです。
こんなことをしています
- Rパッケージ開発
- CRANに登録されているもの(jpmesh ⭐️26, zipangu ⭐️21, jpndistrict ⭐️11 fgdr ⭐️5)
- 時々 rstudio関係、rOpenSci、r-spatialのパッケージへissueやPRを出します
- 資料公開 (執筆、スライド、ブログ)
先日、発表させていただいた内容の公開用スライドを用意しました。
— Uryu Shinya (@u_ribo) 2019年7月15日
多様なデータの種類に対応できる、実施する統計分析、機械学習モデルに適したデータに「調理」するをテーマに、データ型に応じた「特徴量エンジニアリング」の方法を紹介しています。 (EDAや前処理もあるよ) https://t.co/G7hNtuT6PB
🗺Rで地理空間データを操作・可視化・分析するための処理を記述した教科書的なものを書くことにしました✍️特に多様な可視化の手法について注力したいと思っています💪 まだ始めたばかりでコードしかない箇所が多々ありますが、今後の動向に注目ください👀 https://t.co/A5HKY3sVQb pic.twitter.com/n8LuRQ6azO
— Uryu Shinya (@u_ribo) 2018年11月20日
- 可視化プロジェクト ... あれこれとやっています。地図を使ったものが多いです。可能な限りコードを公開しています。
ふと火山🌋の形が気になって、火山基本図が整備されている火山(西之島を除く)について #rayshader で可視化してみました。ALOS全球数値地表モデルにより斜面や火口の形がわかりやすくなったと思います! それぞれに格好良さがありますね😀🦉Rでのソースコードはこちら https://t.co/0PC5Tr4p2f pic.twitter.com/hoPbW1Emzq
— Uryu Shinya (@u_ribo) 2019年8月23日
- 情報発信 ... 毎日GitHubに張り付いているので、新しいパッケージや機能追加は比較的早い段階でキャッチアップしています。スポンサーに情報共有するというのはアリかもしれません。
サポートする意思のある人へ
ここまであれこれと宣伝でした。ではいよいよスポンサー枠のご案内です。現在5つの枠を用意していますが、
- $3/month または $6/monthは個人枠
- $20/month, $50, $1000 ($100ではない)を企業枠と捉えています(もちろん個人でやってくれても大歓迎)
の2つが大きくあります。月単位でのサポートも可能です。その場合、サポートを停止するのをお忘れなく。
また、スポンサーになっていただけるのはどなたでも歓迎ですが、次の条件に合っているかどうか、踏みとどまって欲しい項目をあげておきます。
- 私の開発するRパッケージ、資料を活用している人
- 私を通じてコミュニティ活動を支えたい人
- 私自身を応援したい人
スポンサーへの直接のお礼や特典は今のところありませんが、感謝の気持ちは述べさせてください。加えて、支援してくれる理由やお金の用途の指定があれば教えていただけますと幸いです。
それでは、瓜生真也と未来のRコミュニティのためにどうぞよろしくお願いします。
parzerパッケージで多様な緯度経度の表記を十進数に変換する
信頼と実績のrOpenSciから新しいパッケージがCRANに登録されました。parzerパッケージです。 このパッケージは多種多様な緯度経度の表記形式を処理し、十進数での表記(DEG: Degree)に変換してくれるものです。 (例えば「139°44’28.8869」を「139.7414」にする)
CRANリリース情報および基本的な関数の紹介はrOpenSciのブログ知りました。ぜひこちらもご覧ください。
また、私自身も以前に同様の処理を行う方法としてこのような記事を書いています。 ですがparzerパッケージを使うとより簡単に緯度経度座標の表記を修正できます。 日本語の表記を扱う際には課題が残っているので、その対策を後述します。
まずは基本的な使い方を見ていきましょう。
install.packages("parzer")
library(parzer)
パース関数
入力された座標の値を十進数での表記に修正するパース関数はparse_*()
で整備されています。
parse_lat()
、parse_lon()
はそれぞれlatitude(緯度)、longitude(経度)を処理します。
日本経緯度原点の座標を例にします。
x <- "E139°44’28.8869" y <- "N35°39’29.1572" parse_lon(x) ## [1] 139.7414 parse_lat(y) ## [1] 35.6581
パースした結果をマップ上で確認します。せっかくなので国土地理院の地理院タイルを背景に。
library(sf) library(leaflet) library(sfheaders)
basemap <- leaflet() %>% addTiles("http://cyberjapandata.gsi.go.jp/xyz/std/{z}/{x}/{y}.png", attribution = "<a href='http://maps.gsi.go.jp/development/ichiran.html' target='_blank'>地理院タイル</a>") sfheaders::sf_point(st_point(c(parse_lon(x), parse_lat(y)))) %>% st_set_crs(value = 6668) %>% st_transform(crs = 4326) %>% mapview::mapview(map = basemap)
しっかりと「日本経緯度原点」にポイントが落ちていますね。
parse_*()
は多様な表現方法に対応しています。
coords <- c(45.23323, "40:25:6N", "40°25’5.994N") parse_lat(coords) ## [1] 45.23323 40.41833 40.41833
parse_lon_lat()
は二つの引数に同じ長さの経度、緯度のベクトルを与えてデータフレーム形式で結果を返却します。
df <- data.frame( lon = x, lat = y, stringsAsFactors = FALSE) parse_lon_lat(df$lon, df$lat) ## lon lat ## 1 139 35
また度分秒の要素を分解する関数として
pz_*()
があります。以下の例で度分秒それぞれの要素に分解します。
pz_degree(x) ## [1] 139 pz_minute(x) ## [1] 44 pz_second(x) ## [1] 28.90863
日本語での度分秒の処理
現在のバージョン(v0.1.0)ではUnicodeを扱う際には課題があります。
https://github.com/ropensci/parzer/issues/10 github.com
具体的には次のように日本語での「東経」「北緯」、「度分秒」を扱う際に発生する問題です。
x <- "東経139度44分28秒8869" y <- "北緯35度39分29秒1572" x %>% parse_lon() ## [1] NaN y %>% parse_lat() ## [1] NaN
うまくパースされません。これに対して簡単な方法ですが、「度」「分」「秒」を変換しておきます。そうすると正常にパースできます。
@Atsushi776 さんに効率的な置換の方法を教えてもらったので書き直しています👇
str_replace_allもいいですぞ!
— atusy (@Atsushi776) 2020年3月21日
> 'ももくり3年' %>% str_replace_all(c('もも' = '桃', 'くり' = '栗'))
[1] "桃栗3年"
library(stringr) x_res <- x %>% str_replace("東経", "E") %>% str_replace_all(c("度" = "\u00b0", "分" = "\u2019", "秒" = ".")) x_res ## [1] "E139°44’28.8869" parse_lon(x_res) ## [1] 139.7414 y %>% str_replace("北緯", "N") %>% str_replace_all(c("度" = "\u00b0", "分" = "\u2019", "秒" = ".")) %>% parse_lat() ## [1] 35.6581
さらに関数化するなら以下のような感じで。
replace_dohunbyo_kanji <- function(x) { str_replace_all(x, c("東経" = "E", "西経" = "W", "北緯" = "N", "南緯" = "S"), c("E", "W", "N", "S")) %>% str_replace_all(c("度" = "\u00b0", "分" = "\u2019", "秒" = ".")) } replace_dohunbyo_kanji(x) ## [1] "E139°44’28.8869" replace_dohunbyo_kanji(y) %>% parse_lat() ## [1] 35.6581
Enjoy!
データフレーム上の緯度と経度を空間オブジェクトに変換する-🦉sfと🐍geopandasの例-
地理空間データを取り扱う際は、はじめにgeojsonやshapeファイルで受け取ることが一般的かと思います。 あるいはポイントデータの場合には、緯度と経度の値が各列に記録されるcsvなどの表形式のテキストファイルを起点とすることもあります。
前者のような地理空間データであれば、 R等のアプリケーションで読み込めば自動的に地理空間データとみなしてくれますが、 後者の場合はそうではありません。 座標の値はあくまでも数値です。なのでこうしたデータを地理空間データとして扱えるようにするには変換作業が必要となります。
今回の記事では、RおよびPythonでのデータフレームに記録された緯度経度の列を変換し、空間オブジェクトとして扱えるようにする方法を紹介します。 空間オブジェクトの形式としてRではsf、Pythonではgeopandasを対象にします。地理空間データに変換しておくと、データの空間的な配置を可視化可能になったり空間演算が可能になり、分析の幅を広げることが期待できます。
対象データ
csvファイルに緯度と経度の値が格納されているデータの例として、国土交通省 位置参照情報ダウンロードサービス 提供の平成30年整備 茨城県つくば市の大字・町丁目レベルのデータを利用します。
ファイルをダウンロードしたら、まずはデータフレームとしてcsvファイルを読み込みましょう。
library(sf) library(readr)
df_isj08220 <- read_csv("08220_2018.csv", locale = locale(encoding = "cp932"), col_types = "___c_cdd__") %>% purrr::set_names(c("city", "street_lv1", "latitude", "longitude"))
データの一部を表示します。latitude, longitudeの列がそれぞれ独立しています。
city | street_lv1 | latitude | longitude |
---|---|---|---|
つくば市 | 赤塚 | 36.04268 | 140.1232 |
つくば市 | 明石 | 36.18207 | 140.0537 |
つくば市 | 旭 | 36.11289 | 140.0725 |
つくば市 | 安食 | 36.16775 | 140.0163 |
つくば市 | あしび野 | 35.96060 | 140.1122 |
つくば市 | 吾妻一丁目 | 36.08153 | 140.1129 |
sfパッケージ
sf
パッケージでデータフレームの座標情報を参照してポイントデータに変換するにはst_as_sf()
を使います。
第一引数に座標列を含む対象のデータフレーム、coords引数の値にX,Y座標となる列名を指定します。この時、座標参照系が判明している際はcrs引数によって明示しておきましょう。
sf_isj08220 <- df_isj08220 %>% sf::st_as_sf(coords = c("longitude", "latitude"), crs = 4326)
sf_isj08220 ## Simple feature collection with 299 features and 2 fields ## geometry type: POINT ## dimension: XY ## bbox: xmin: 140.0102 ymin: 35.95047 xmax: 140.1676 ymax: 36.22462 ## epsg (SRID): 4326 ## proj4string: +proj=longlat +datum=WGS84 +no_defs ## # A tibble: 299 x 3 ## city street_lv1 geometry ## <chr> <chr> <POINT [°]> ## 1 つくば市 赤塚 (140.1232 36.04268) ## 2 つくば市 明石 (140.0537 36.18207) ## 3 つくば市 旭 (140.0725 36.11289) ## 4 つくば市 安食 (140.0163 36.16775) ## 5 つくば市 あしび野 (140.1122 35.9606) ## 6 つくば市 吾妻一丁目 (140.1129 36.08153) ## 7 つくば市 吾妻二丁目 (140.1111 36.08443) ## 8 つくば市 吾妻三丁目 (140.1109 36.0889) ## 9 つくば市 吾妻四丁目 (140.1183 36.08722) ## 10 つくば市 天久保一丁目 (140.1087 36.0919) ## # … with 289 more rows
緯度経度の列を元にポイントデータが作成できました。地図上にマッピングしてみます。
mapview::mapview(sf_isj08220)
sfheadersパッケージ
続いてsfheaders
パッケージを使う方法です。sf::st_as_sf()
の実行結果と同じく、sfオブジェクトを作成します。
今回は対象がポイントデータなので、sf_point()
のx,y引数にそれぞれ経度と緯度の列名を与えます。
この時、keep引数の値をTRUEにしておくとデータフレームの他の列が残ります。FALSEではポイントのgeometry列のみしか残らないため注意です。
また、座標参照系もこのタイミングでは指定できないため、sf::st_set_crs()
で定義する必要が生じます。
df_isj08220 %>% sfheaders::sf_point(x = "longitude", y = "latitude", keep = TRUE) %>% st_set_crs(4326) %>% tibble::new_tibble(subclass = "sf", nrow = nrow(.))
sf_isj08220sfh ## Simple feature collection with 299 features and 2 fields ## geometry type: POINT ## dimension: XY ## bbox: xmin: 140.0102 ymin: 35.95047 xmax: 140.1676 ymax: 36.22462 ## z_range: zmin: NA zmax: NA ## m_range: mmin: NA mmax: NA ## epsg (SRID): 4326 ## proj4string: +proj=longlat +datum=WGS84 +no_defs ## # A tibble: 299 x 3 ## city street_lv1 geometry ## <chr> <chr> <POINT [°]> ## 1 つくば市 赤塚 (140.1232 36.04268) ## 2 つくば市 明石 (140.0537 36.18207) ## 3 つくば市 旭 (140.0725 36.11289) ## 4 つくば市 安食 (140.0163 36.16775) ## 5 つくば市 あしび野 (140.1122 35.9606) ## 6 つくば市 吾妻一丁目 (140.1129 36.08153) ## 7 つくば市 吾妻二丁目 (140.1111 36.08443) ## 8 つくば市 吾妻三丁目 (140.1109 36.0889) ## 9 つくば市 吾妻四丁目 (140.1183 36.08722) ## 10 つくば市 天久保一丁目 (140.1087 36.0919) ## # … with 289 more rows
おまけ: sfからdfに戻す
データフレーム(df)の緯度経度情報をもとにsfオブジェクトを作成する例を述べましたが、反対にsfからデータフレームへ、地理空間情報を取り除く方法も紹介します。
作成したsfオブジェクトに対してsf::st_drop_geometry()
ないしsf::st_set_geometry(value = NULL)
でgeometry情報を除外することでdfに変換されます。
sf_isj08220 %>% st_drop_geometry() sf_isj08220 %>% st_set_geometry(value = NULL)
この時、ポイントの情報も失われるので、データフレームの列として残したい場合は予め列を追加する必要が生じます。
sf_isj08220 %>% dplyr::mutate(coords = purrr::map(geometry, ~ as.data.frame(sf::st_coordinates(.x)))) %>% tidyr::unnest(cols = coords) %>% st_drop_geometry() ## # A tibble: 299 x 4 ## city street_lv1 X Y ## * <chr> <chr> <dbl> <dbl> ## 1 つくば市 赤塚 140. 36.0 ## 2 つくば市 明石 140. 36.2 ## 3 つくば市 旭 140. 36.1 ## 4 つくば市 安食 140. 36.2 ## 5 つくば市 あしび野 140. 36.0 ## 6 つくば市 吾妻一丁目 140. 36.1 ## 7 つくば市 吾妻二丁目 140. 36.1 ## 8 つくば市 吾妻三丁目 140. 36.1 ## 9 つくば市 吾妻四丁目 140. 36.1 ## 10 つくば市 天久保一丁目 140. 36.1 ## # … with 289 more rows
Python
import pandas as pd import geopandas
df = pd.read_csv("08220_2018.csv", encoding = "cp932", usecols = [3, 5, 6, 7], dtype = {'市区町村名': str, '大字町丁目名': str, '緯度': float, '経度': float}) df = df.rename(columns = {'市区町村名': 'city', '大字町丁目名': 'street_lv1', '緯度': 'latitude', '経度': 'longitude'})
geopandas
gdf = geopandas.GeoDataFrame(df, geometry = geopandas.points_from_xy(df.longitude, df.latitude))
gdf.head(10)
city | street_lv1 | longitude | latitude | geometry |
---|---|---|---|---|
つくば市 | 赤塚 | 140.1 | 36.04 | POINT (140.12315 36.042677) |
つくば市 | 明石 | 140.1 | 36.18 | POINT (140.053737 36.182065) |
つくば市 | 旭 | 140.1 | 36.11 | POINT (140.072495 36.11289) |
つくば市 | 安食 | 140.0 | 36.17 | POINT (140.016345 36.167751) |
つくば市 | あしび野 | 140.1 | 35.96 | POINT (140.112185 35.960604) |
つくば市 | 吾妻一丁目 | 140.1 | 36.08 | POINT (140.112938 36.081534) |
つくば市 | 吾妻二丁目 | 140.1 | 36.08 | POINT (140.111144 36.084425) |
つくば市 | 吾妻三丁目 | 140.1 | 36.09 | POINT (140.11092 36.088898) |
つくば市 | 吾妻四丁目 | 140.1 | 36.09 | POINT (140.118261 36.087219) |
つくば市 | 天久保一丁目 | 140.1 | 36.09 | POINT (140.108708 36.091901) |
せっかくなのでこちらもマッピング。
import geopatra m = gdf.folium.plot(zoom = 10) m
いいですね!Enjoy!