Wikidata:Tools/OpenRefine/Editing/Tutorials/Inverse Listeria
ListeriaはSPARQLクエリでウィキの表を生成して、さらにウィキデータとの同期を取れるパワフルなツールです。多くのウィキペディアで緻密な表を表示するのに利用されており、各ウィキペディアで重複作業を行う代わりに一箇所で保守するだけで済みます。しかしながら、それらの表の生成に必要なデータはウィキデータにはまだ無いということが頻繁にあります: これは最初の情報源からインポートする必要があります。このチュートリアルでは手動で保守された表をウィキペディアからウィキデータへインポートする方法を説明しています。
注意
ウィキペディアの表がすべてインポートに適している訳では無いということは注意しておく必要があります。すべてが信頼できて最新である訳ではありません。表内にある情報が信頼できる情報源のものでありインポートによって歪められるものでないかはチェックする必要があります。
表のインポート
このチュートリアルでは、地下鉄システムに関するデータをインポートします。イギリスのウィキペディアにはこうしたシステムをリスト化した印象的な表 があり、これが私たちが使うサンプルになります。
ウェブで見つけた表をインポートする方法のひとつは単純にマウスで選んでコピーしてOpenRefineのクリップボードのインポートエリアに貼り付けることです。これは多くの場合驚くほどうまく行き、ここで実施できます。しかしながら、ウィキペディアの場合、これは重要な情報を破棄してしまう欠点があります:
- 表に含まれるウィキリンクから照合される値は、それがリンクされているウィキページが(多くの異なるウィキデータ項目も参照できるので) 曖昧ですが、この場合はSkyTrain (Vancouver)という、SkyTrain (Q876780)にリンクしているウィキペディアページです。従ってこの情報を再利用すべきです。
- 各セル内の値で提供されている参照はその情報の出自を示しています: こうした情報源を破棄したくないので、代わりにウィキデータにインポートします。
![](http://upload.wikimedia.org/wikipedia/commons/thumb/f/f0/OR-WD-inverse-listeria-copy-wikicode.png/220px-OR-WD-inverse-listeria-copy-wikicode.png)
このため、私たちは専用のインポートツールを使ってその表からOpenRefineのプロジェクトを作成します。表のあるウィキペディア記事のセクション内でEditをクリック。この表のウィキコードを取得したいので、使っているのがビジュアルエディタでは無く、手動のテキストエディタであることを確認してください。表の全体({|
で始まり|}
で終わる部分)で、それをOpenRefineのクリップボードのインポートアリアに貼り付けます(ここにあるのは表がひとつだけなので、実際は全Listサブセクションをコピーできます: OpenRefineは表の外にあるものは全て無視します)をコピーします。
インポートのプレビューには少し時間が掛かります: これはウィキリンクとウィキデータ項目の間のリンクを解決するためにOpenRefineがウィキデータにクエリを投げるためです。デフォルトでは、OpenRefineはウィキコード内のテンプレートを無視しますが、私たちの場合、国といくつかの距離がテンプレートを使っていることを示しているのでInclude templates and images as raw wikicodeを選ぶことができます。ウィキテキストがどのウィキペディアから取得されたかを示すことも必要です(この欄はデフォルトでは英語版ウィキペディアを指し示していますが、私たちの場合はこれで合っています)。最後に、インポートを検証します: プロジェクトの作成もやや時間が掛かります(キャッシュがあるので多少は短めでしょう)。
![OpenRefineでのウィキデータ編集 - Listeriaからの転置チュートリアル。ウィキテーブル向けのインポートオプション。](http://upload.wikimedia.org/wikipedia/commons/6/69/OR-WD-inverse-listeria-import-options.png)
![](http://upload.wikimedia.org/wikipedia/commons/thumb/4/40/OR-WD-inverse-listeria-reconciliation-check.png/220px-OR-WD-inverse-listeria-reconciliation-check.png)
いちどプロジェクトを作成すると、他のインポートツールと少し違うのに気がつくでしょう:
- 既に多くのセルが照合済みです: 一意のウィキリンクを持ったセルで、ウィキデータ項目に関連するページにリンクしています。
- 新しいカラムが作成され、セル内にある参照から抽出されたURLがあります。これらの参照カラムは抽出元の内容のカラムの右側に置かれています。
![元の値の構造と参照。](http://upload.wikimedia.org/wikipedia/commons/d/d6/OR-WD-inverse-listeria-reference-extraction.png)
セルが自動的に照合されたとしても、これらのマッチングの品質は必ずチェックしてください。例えば、ウィキリンクが曖昧さ回避ページをポイントすることはよくあり、その場合セルは曖昧さ回避ページに間違ってマッチすることになるでしょう。これらのマッチの品質についてのアイデアを得る単純な方法のひとつは、照合された値で単にカラムをひとつ追加し (Edit column → Add columns from reconciled column)、instance of (P31)などのようなプロパティやあなたの表(date of official opening (P1619)のような)の内容に関連するものを閲覧することです。ファセットを使ってこれらの値を調べ、その項目がどのように見えるのかという感覚を身につけてください。
データのクリーンアップ
![](http://upload.wikimedia.org/wikipedia/commons/thumb/c/c1/OR-WD-inverse-listeria-invalid-values.png/220px-OR-WD-inverse-listeria-invalid-values.png)
この表のridershipカラムをインポートするとします。このカラムには302.8 (2016)
といった値が含まれています: 最初に年から実際の乗降者数を分離して、これをきれいにする必要があります。例えば正規表現でこれを行うことができます。このカラムでよく使われる形式は以下のようなものです: 数量(数字と小数点で構成)、空白、左括弧、年、右括弧。これは正規表現[\d.]+ \(\d{4}\)
に一致するでしょう。これは最初からすぐに取得する必要はありません: このカラムでText filterを作成し、Regular expressionを選び、そこであなたの表現を組み立てます。OpenRefineはあなたの表現をリアルタイムでコンパイルしてそれに一致する行を表示します。invertを選んで、表現に一致しない行を見ることもできます。これらは値が提供されていないかもしくはソースが見つからない行です。そのため私たちはインポートからこれらの行を除外することができます。
![](http://upload.wikimedia.org/wikipedia/commons/thumb/3/3a/OR-WD-inverse-listeria-extracting-amounts.png/220px-OR-WD-inverse-listeria-extracting-amounts.png)
これで私たちはこれらのセルを捕捉する正規表現を考えだしたので、これを使って内容を2つの部分に分けることもできます。[1]私たちは最初にその部分を抽出できるように、グループを追加しようとしています: ([\d.]+) \((\d{4})\)
。最初のグループは数量を捕捉し、2番めのものは年です。これで、私たちは各グループ用に新しいカラムを作成できます。ridershipカラムをクリックして、Edit column → Add column based on this columnと選びます。表現言語としてPython / Jythonを選んで、次の表現を使います:
import re # これは正規表現モジュールをインポートします
match = re.search(r'([\d.]+) \((\d{4})\)', value) # これは私たちの正規表現に対する値にマッチします
return match.group(1) # これはマッチしたものからキャラクターの最初のグループを抽出します
![](http://upload.wikimedia.org/wikipedia/commons/thumb/c/c3/OR-WD-inverse-listeria-fixing-amounts.png/220px-OR-WD-inverse-listeria-fixing-amounts.png)
カラムに名前(例えばridership_amount(乗降客数)) を付けて確認してください。操作を繰り返します。今回は2つめのグループで2番めのカラムridership_year(乗降年)を作成します。もう終わりですか?まだです。カラムヘッダーが、乗降客が百万単位で表現されていると言っているので、私たちはそれに合わせて値を掛け算する必要があります。これを簡単にやる方法はこのカラム内のセルを変換(Edit cells → Transform)して単に値の最後に"e6"を付けることです(これは数量を百万単位で表す工学的記数法です)。
スキーマの作成
これで私たちのデータはクリーンアップされたので、通常通りウィキデータのスキーマを作成できます。最初のステップは、どのプロパティを使うかを考えることです。Algiers Metro (Q728045)などの地下鉄システムの項目をウィキデータで開いて、"ridership"プロパティで新しい文を追加しようとしてみてください。 ウィキデータはpatronage (P3872)を提案してきます。これはそのプロパティページを確認してみると適切に思えます。このプロパティの用法を見ると乗降客が計測された暦年を示すためにpoint in time (P585)修飾子を使うように提案しています。
Wikidata → Edit Wikidata schemaとクリックして、これらのプロパティを使ってスキーマを組み立てます。ウィキテーブル・インポートツールのおかげで、私たちはウィキデータの情報源を作成するのに右手にあるカラム内の抽出された参照URLを使うことができます。私たちがこのデータをウィキペディア経由でインポートしたことを記録するのも役に立ちます: そのために私たちは、抽出を実行するのに使った版へのパーマネントリンク(https://en.wikipedia.org/w/index.php?title=List_of_metro_systems&oldid=830817609 など)をWikimedia import URL (P4656)に使うことができます。
![OpenRefineでのウィキデータ編集 - Listeriaからの転置チュートリアル。ウィキデータに乗降客の情報を追加するためのシンプルなスキーマ。](http://upload.wikimedia.org/wikipedia/commons/1/16/OR-WD-inverse-listeria-schema.png)
もちろん、私たちは別のカラムにも同じようなことをしたり、それをスキーマに追加したりできるため、これらは一度にウィキデータにアップロードできます。例えば、オープン日をdate of official opening (P1619)で追加できるでしょう。スキーマに満足したら、OpenRefineを使ってUpload to Wikidata操作で直接、もしくはQuickStatementsを使っていつものように編集を行うことができます。
![OpenRefine Wikidata Inverse Listeria tutorial, 乗降客情報追加時のプレビュー](http://upload.wikimedia.org/wikipedia/commons/7/76/OR-WD-inverse-listeria-preview.png)
編集履歴
このチュートリアルで説明した操作は以下のJSON編集履歴を使ってプロジェクトに再度適用することができます。もちろん、それは特定の表の構造に特有のものです。
Extended content |
---|
[
{
"op": "core/extend-reconciled-data",
"description": "Extend data at index 3 based on column Name",
"engineConfig": {
"mode": "row-based",
"facets": []
},
"columnInsertIndex": 3,
"baseColumnName": "Name",
"endpoint": "https://wikidata.reconci.link/en/api",
"identifierSpace": "http://www.wikidata.org/entity/",
"schemaSpace": "http://www.wikidata.org/prop/direct/",
"extension": {
"properties": [
{
"name": "instance of",
"id": "P31"
},
{
"name": "date of official opening",
"id": "P1619"
}
]
}
},
{
"op": "core/column-addition",
"description": "Create column ridership_amount at index 15 based on column Ridership\n(millions) using expression jython:import re\nmatch = re.search(r'([\\d.]+) \\((\\d{4})\\)', value)\nreturn match.group(1)",
"engineConfig": {
"mode": "row-based",
"facets": [
{
"mode": "regex",
"invert": false,
"caseSensitive": false,
"query": "([\\d.]+) \\((\\d{4})\\)",
"name": "Ridership\n(millions)",
"type": "text",
"columnName": "Ridership\n(millions)"
}
]
},
"newColumnName": "ridership_amount",
"columnInsertIndex": 15,
"baseColumnName": "Ridership\n(millions)",
"expression": "jython:import re\nmatch = re.search(r'([\\d.]+) \\((\\d{4})\\)', value)\nreturn match.group(1)",
"onError": "set-to-blank"
},
{
"op": "core/column-addition",
"description": "Create column ridership_year at index 15 based on column Ridership\n(millions) using expression jython:import re\nmatch = re.search(r'([\\d.]+) \\((\\d{4})\\)', value)\nreturn match.group(2)",
"engineConfig": {
"mode": "row-based",
"facets": [
{
"mode": "regex",
"invert": false,
"caseSensitive": false,
"query": "([\\d.]+) \\((\\d{4})\\)",
"name": "Ridership\n(millions)",
"type": "text",
"columnName": "Ridership\n(millions)"
}
]
},
"newColumnName": "ridership_year",
"columnInsertIndex": 15,
"baseColumnName": "Ridership\n(millions)",
"expression": "jython:import re\nmatch = re.search(r'([\\d.]+) \\((\\d{4})\\)', value)\nreturn match.group(2)",
"onError": "set-to-blank"
},
{
"op": "core/text-transform",
"description": "Text transform on cells in column ridership_amount using expression jython:return value+'e6'",
"engineConfig": {
"mode": "row-based",
"facets": [
{
"mode": "regex",
"invert": false,
"caseSensitive": false,
"query": "([\\d.]+) \\((\\d{4})\\)",
"name": "Ridership\n(millions)",
"type": "text",
"columnName": "Ridership\n(millions)"
}
]
},
"columnName": "ridership_amount",
"expression": "jython:return value+'e6'",
"onError": "keep-original",
"repeat": false,
"repeatCount": 10
},
{
"op": "wikidata/save-wikibase-schema",
"description": "Save Wikibase schema skeleton",
"schema": {
"itemDocuments": [
{
"subject": {
"type": "wbitemvariable",
"columnName": "Name"
},
"statementGroups": [
{
"property": {
"datatype": "quantity",
"pid": "P3872",
"label": "patronage",
"type": "wbpropconstant"
},
"statements": [
{
"references": [
{
"snaks": [
{
"prop": {
"datatype": "url",
"pid": "P854",
"label": "reference URL",
"type": "wbpropconstant"
},
"value": {
"type": "wbstringvariable",
"columnName": "Column6"
}
},
{
"prop": {
"datatype": "url",
"pid": "P4656",
"label": "Wikimedia import URL",
"type": "wbpropconstant"
},
"value": {
"type": "wbstringconstant",
"value": "https://en.wikipedia.org/w/index.php?title=List_of_metro_systems&oldid=838442291"
}
},
{
"prop": {
"datatype": "time",
"pid": "P813",
"label": "retrieved",
"type": "wbpropconstant"
},
"value": {
"type": "wbdateconstant",
"value": "2018-04-27"
}
}
]
}
],
"qualifiers": [
{
"prop": {
"datatype": "time",
"pid": "P585",
"label": "point in time",
"type": "wbpropconstant"
},
"value": {
"type": "wbdatevariable",
"columnName": "ridership_year"
}
}
],
"value": {
"amount": {
"type": "wbstringvariable",
"columnName": "ridership_amount"
},
"unit": null,
"type": "wbquantityexpr"
}
}
]
}
],
"nameDescs": []
}
]
}
}
]
|
脚注
- ↑ OpenRefineでの正規表現利用に関する背景はOpenRefineのウィキ上にあります。