中古車購入に向けてのデータ分析をしてみたかった【python, scraping】
中古車を対象としたなんちゃってデータ分析をしてみた。以下の本を読んでなんか作ってみたくなったので。n番煎じなのは気にしない。
Pythonクローリング&スクレイピング -データ収集・解析のための実践開発ガイド-
- 作者: 加藤耕太
- 出版社/メーカー: 技術評論社
- 発売日: 2016/12/16
- メディア: 大型本
- この商品を含むブログ (3件) を見る
動機
若者の車離れが叫ばれて(?)久しいが、自分としては昔からマイカーは憧れの象徴なので車が欲しい。 当然お金はないので中古車を買うことにはなるが、中古車は様々な要素から価格が決まってくる。
年式、走行距離
修復歴あり or なし
カーナビなどオプションの有無
値段に強く影響しそうなのはこの辺な気がする。車の素人が購入を判断するための材料が欲しいので、色々データをいじってみる次第である。 まずはwebサイトから各種情報をとってくるところから始める。
スクレイピング
ざっくり流れ
requests
でHTTP接続し、 lxml.html
でパースする。今回はログインなどはせず、ステートレスなクロールを行うので特に複雑な処理は発生しない。取得したデータはpymongo
でMongoDBに保存する。
MongoDB初めて使ったけど便利だなこれ。
カーセンサーのページを対象とする。カーセンサーは特定の条件で検索すると、その条件に合致した中古車の一覧ページが生成され、その一覧から気になった車をクリックすると その車の詳細ページを閲覧できる。なので「一覧ページを取得 -> 詳細ページのhtml取得 -> スクレイピング」という手順となる。
ソースコード
コードは以下。
動作環境は
- MongoDB v4.0.1
- pymongo 3.7.1
- scikit-learn 0.20.0
- statsmodel 0.9.0
ぐらいあれば動くと思う。
car_scrape.py
がスクレイピング実行してMongoDBにデータ保存するスクリプト。実行時にコマンドライン引数で車種を指定する。とりあえずPRIUS, VEZEL, FITに対応しているが、URLを追加すれば他の車種も取得可能。
車一台につき固有のIDを割り当てて車両情報と一緒にDBに保存し、次にスクリプトを実行するときはIDが未登録の車両のみをDBに追加することができる。新たに追加された中古車を登録するのに便利な設計(ただし
車両価格更新には対応できない...)。オプション引数に--reset_db
を指定すると、MongoDBのcollectionを削除して一からスクレイピングを行う。
中身はえらいごちゃごちゃしてしまったが、CSS selectorとスクレイプのとこが冗長になってしまっただけなので、処理自体は単純。scrape_list_page()
で一覧ページを読み込み、その中でscrape_detail_page()
を順次呼び出して
詳細ページのhtmlを取得する。また今回は車種だけ指定し、その他の条件(グレード等)は特に指定せずにスクレイピングする形をとった。
visualize.ipynb
では取得したデータの可視化を行い、analyze.ipynb
で簡単な分析ごっこをしてみた。後述。
可視化してみる
カーセンサーに掲載されている中で数が最も多い普通車がプリウスっぽかったので、プリウスについて調べた。
年式 - 本体価格
まずは年式と本体価格の関係を散布図で見てみる。
横軸のmodel_year
は年式、縦軸のbase_price
は車両本体価格(単位:万円)となっている。赤い線とプロットは各年代の中央値を示している。まあ当然っちゃ当然だが、年式が新しいほうが価格が高い。そしてパッと見、分布の重心は価格の低い方に位置しており、高価な車両はまばらに分布していることがわかる。これはカスタムすればするだけ車は高くなるので、正規分布より若干ロングテール気味になるからであると思われる。
上の散布図を見ると、2015年から2016年で価格が大きく上がっているように見える。確認のために本体価格のヒストグラムをプロットしてみる。
これを見ると明らかに山が二つあり、年式の違いで価格に大きな隔たりがあることが確認できる。もうちょい詳しく見たいのでプロットする年式を絞ってみる。
やはり2015年と2016年の分布に隔たりがある。中央値だと50~60万円ほど変わってくるか。実はプリウスは2015年12月にフルモデルチェンジされており、その影響で旧モデルとの価格差が顕著になっている。 ちなみにその前のフルモデルチェンジは2009年5月であり、2008 ~ 2009年でも価格が見受けられる(ただし価格差は直近のモデルチェンジよりは控えめ)。要は旧モデルは露骨に安くなることがわかったので、特にこだわりがなければモデルチェンジ後の車両なら比較的安く手に入れられる。逆にモデルチェンジが発表された車種はちょっと購入を遅らせてみてもよいのかもしれない。
走行距離 - 本体価格
次に走行距離を見てみる。ネットで中古車購入の手引き的なページを見ると、
走行距離〇万km(3万, 5万とか)を超えると値段がかくっと下がる
といった記述が散見される。4.9万kmと5.1万kmでは心理的なハードルが違ってくるかららしい。まあ何となくそんな気もしなくはない。
確かめるために、横軸に走行距離distance
(単位:万km)、縦軸に本体価格base_price
をとり、年式ごとにプロットする。
色が赤に近づくほど年式が新しくなる。年式は新しいほど価格が上がり、走行距離が伸びると価格が下がるといったことが読み取れる。まあ当たり前だけど。
色が重なりすぎて見づらいので2015年以降でプロット
最新の年式は試走等の目的で使われた後中古に流れたいわゆる新古車が多く、ほぼ0kmのものが多い。カスタム内容を選ばなければ意外と安く最新モデルが手に入りそうだ。 そして前述の通り16年と15年には価格の隔たりがある。16年は6万kmを超えたあたりから価格の下落が大きくなっているような気がする。
ついでに2011年 ~ 2015年もプロットする。
この辺の年式は結構値段が似通ってるので、分布ががっつり重なってくる。11年は若干安いくらいか。こうしてみると、どうせ値段同じくらいなんだし14年の車買ったほうがお得なんじゃないかと思えてくる (他の条件を無視しているので実際はわからん)。 そして肝心の、「〇万km超えると安くなる説」はこの図からはほぼ読み取れない。実際全く同じ色、グレード、カスタムの車種を比べると気持ち〇万km超えのほうが安くなるのかもしれないが、 中古市場において全く同条件の車両が出回ることはほぼあり得ないので、走行距離の〇万kmはほぼ意識しなくてよいと結論付けることにした。そこにこだわるくらいなら別のとここだわったほうが良い。
分析あれこれ
なんかデータ分析っぽいことがしてみたかったので、やってみた。
特徴選択
車両の価格に影響しそうな情報として、オプションがどの程度ついているかという情報を取得した。
走行距離、年式に加えて上記のオプション情報を使用して、車両価格を推定する。これらは全て二値のダミー変数として扱う。 カーナビは種類が複数あり(CD, DVD, HDD, メモリナビ)、面倒なのでHDD、メモリナビは1, それ以外は0とする。同じ理由でヘッドランプもディスチャージドランプとLEDランプはまとめて1とする。オーディオはカーナビと 一体となっている車が多いので使用せず、他にも3列シートとかウォークスルーとか車種に依存しそうな情報は抜きにした。あとは禁煙車などを加味して、結果的に全部で22項目を使用することになった。 走行距離、年式は平均0, 分散1になるように正規化する。
まずはどの特徴が価格に大きく寄与しているのかを調べる。
特徴選択の方法は種々あって、重回帰分析でよく利用されるのは変数増減法とからしい。scikit-learnにもいくつか用意されている(指定した評価指標で上位k個を選択するSelectKBest
, 変数減少法のRFE
, モデルから算出される
重要度や係数を使用するSelectFromModel
)。
今回はscikit-learnのRandomForestRegressor
を使用し、feature_importance_
を
算出して重要度が大きい順に特徴を選択してみる(それぞれの特徴が相対的に見てどれくらい重要度が高いかをみたかったので、ここではSelectFromModel
は使用しなかった)。
RandomForestはブートストラップサンプルに対して決定木を学習させるアンサンブル手法で、out-of-bag誤り率を算出することで特徴の重要度を図ることができる
手法である。このサイトとかはじパタとか読めばわかりやすいと思う。
以下analyze.ipynb
のコードの一部を抜粋
念の為データをtest と trainに分けて、trainデータのみで特徴選択をしている。
rf = RandomForestRegressor(n_estimators=200, random_state=50) rf.fit(x, y) fi = rf.feature_importances_ result = [] for i, label in zip(fi, x_data_df.columns): result.append((i, label)) result.sort(reverse=True) v = [] for i, label in result: print("{0:15} {1:0.6}".format(label, i)) v.append(label)
出力は以下
model_year 0.836925 distance 0.0789052 lowdown 0.0168161 aero 0.00976041 repare 0.00806706 cruise 0.00589656 auto_brake 0.00579045 record_book 0.0051595 sheat_heater 0.00469167 camera 0.00400534 ETC 0.00370045 anti_theft 0.00357377 navi 0.00314469 AS_sensor 0.00273345 ESC 0.00260764 parking_assist 0.00197162 cold_area 0.00177578 smartkey 0.00158297 alumi_wheel 0.00135012 keyless 0.000664804 ABS 0.000528251 sheat_air 0.000165102 around_camera 0.000112198 liftup 7.20092e-05
重要度降順結果。年式、走行距離に続いてローダウン、フルエアロ、修復歴、クルーズコントロール、衝突被害軽減ブレーキ・・・と続いていくことがわかる。 ローダウンとフルエアロあたりが装備されている車は前オーナーが車好きである可能性が高く、そういう車はほかにもいっぱいオプションがついてたりするので価格が高くなる傾向にあるのかもしれない(未確認)。 その次が修復歴なので、やっぱり事故車は価格にかなり影響するのだなあと実感。
次に、適当にモデルを構築してみる。重要度上位10個の特徴を使用した場合と全て使用した場合について、三つのモデル(線形回帰、RandomForest, SVR)でcross validationしてみた。
以下コード抜粋
# cross validationで各モデルを学習・評価 # 評価指標には adjusted r2 # linear regression, random forest, svrを使用 x2 = x_data_df.loc[:, v[:10]].values linear_reg = linear_model.LinearRegression() rf = RandomForestRegressor(n_estimators=200, random_state=50) svr = SVR(gamma='scale') num_y = y.shape[0] // 10 lr_scores_sub = cross_val_score(linear_reg, x2, y, cv=10, scoring='r2') rf_scores_sub = cross_val_score(rf, x2, y, cv=10, scoring='r2') svr_scores_sub = cross_val_score(svr, x2, y, cv=10, scoring='r2') lr_scores_all = cross_val_score(linear_reg, x, y, cv=10, scoring='r2') rf_scores_all = cross_val_score(rf, x, y, cv=10, scoring='r2') svr_scores_all = cross_val_score(svr, x, y, cv=10, scoring='r2') lr_adr2_sub = adjusted_r2(lr_scores_sub, num_y, x2.shape[1]) rf_adr2_sub = adjusted_r2(rf_scores_sub, num_y, x2.shape[1]) svr_adr2_sub = adjusted_r2(svr_scores_sub, num_y, x2.shape[1]) lr_adr2_all = adjusted_r2(lr_scores_all, num_y, x.shape[1]) rf_adr2_all = adjusted_r2(rf_scores_all, num_y, x.shape[1]) svr_adr2_all = adjusted_r2(svr_scores_all, num_y, x.shape[1]) for a in [lr_adr2_sub, rf_adr2_sub, svr_adr2_sub, lr_adr2_all, rf_adr2_all, svr_adr2_all]: print('mean:{0:.5} std:{1:.5}'.format(np.mean(a), np.std(a)))
相変わらず見づらいクソコードである。結果は以下
mean:0.87579 std:0.0078976 mean:0.90187 std:0.0049071 mean:0.89518 std:0.0054207 mean:0.87769 std:0.0073689 mean:0.90777 std:0.0063641 mean:0.89033 std:0.0057512
10 foldのcross validationで、平均と標準偏差を算出した。上三つが特徴量10個、下三つが全特徴使用。上から順に線形回帰、RandomForest、SVR、・・・の結果となる。
ここでは特徴の数が多いほうが精度が少し上がっているように見える。線形回帰においては多重共線性のある特徴が含まれていると精度が下がるはずなので、
- 評価指標に問題があった
- 特徴同士の相関が低かった
が原因かと思った。変数が増えるとモデルの近似がうまくいってなくてもR2は勝手に増加するそうで、それを調整したのがadjusted R2なのだが、なにか使い方に問題があったのかも知れない… 。 まあお遊びなのでそこまで厳密にする必要はないのだけれども。
特徴同士の相関が低い、とは思えない。なぜならスマートキーがついてるのにキーレスじゃないとかありえないし、衝突被害軽減ブレーキがついてたら障害物センサーもついてるんじゃないの?と思うから。 というか大半がダミー変数の場合の回帰ってうまくいくのだろうか。本職の人はどう判断するのか気になります。
あと特徴選択するなら各fold毎に重要度を求めてやらないと意味ないのだが、ここはめんどくさくてさぼってしまった。これをちゃんとしたら案外うまくいくのかもしれない。
statsmodelによる分析
statsmodelなるライブラリを使うと回帰分析のsummaryがすぐ見れちゃうとのことなので使ってみた。 先ほど選択した特徴量を入力として全データに対して回帰分析してみる。
以下コード抜粋
x_sm_sub = sm.add_constant(x_data_df.loc[:, v[:10]]) model = sm.OLS(y, x_sm_sub) results = model.fit() print(results.summary())
結果
OLS Regression Results ============================================================================== Dep. Variable: y R-squared: 0.878 Model: OLS Adj. R-squared: 0.878 Method: Least Squares F-statistic: 5791. Date: Mon, 26 Nov 2018 Prob (F-statistic): 0.00 Time: 23:46:59 Log-Likelihood: -36688. No. Observations: 8070 AIC: 7.340e+04 Df Residuals: 8059 BIC: 7.348e+04 Df Model: 10 Covariance Type: nonrobust ================================================================================ coef std err t P>|t| [0.025 0.975] -------------------------------------------------------------------------------- const 121.1046 0.553 219.193 0.000 120.022 122.188 model_year 40.0663 0.351 114.053 0.000 39.378 40.755 distance -17.3005 0.326 -53.136 0.000 -17.939 -16.662 lowdown 22.0338 1.130 19.507 0.000 19.820 24.248 aero 16.5364 1.067 15.504 0.000 14.446 18.627 repare -14.6507 0.832 -17.604 0.000 -16.282 -13.019 cruise 10.7129 0.690 15.536 0.000 9.361 12.065 auto_brake 14.4923 0.990 14.633 0.000 12.551 16.434 record_book -4.2196 0.534 -7.905 0.000 -5.266 -3.173 sheat_heater 24.9746 1.023 24.423 0.000 22.970 26.979 camera 1.2611 0.593 2.126 0.034 0.098 2.424 ============================================================================== Omnibus: 1373.771 Durbin-Watson: 1.990 Prob(Omnibus): 0.000 Jarque-Bera (JB): 4903.483 Skew: 0.835 Prob(JB): 0.00 Kurtosis: 6.434 Cond. No. 7.58 ============================================================================== Warnings: [1] Standard Errors assume that the covariance matrix of the errors is correctly specified.
いっぱい数字が出てきて焦る。coefとかはわかるとして、横に続くのはt値、p値、95%信頼区間か。上段はR2, adjusted R2, F値、対数尤度なんかも出してくれている。この辺をすべて理解して使いこなすには もう少し統計の勉強が必要である。statsmodelsの公式ドキュメントはこちら
これを見ると、まあ年式が一番値段に影響してて、次いでヒートシーター、ローダウン、衝突被害軽減ブレーキ、クルーズコントロールか。走行距離と修復歴にはしっかり負の相関が確認できる。 修復歴があるのとないのとでは平均で14.6万円程変わってくるが、これを高いとみるか安いとみるか。修復歴ありの車は骨格やシャーシにダメージがあるほどの事故があった車であり、そういった車はドアの開閉や 直進性など何かと問題が出てくることが多い(某知恵袋から得た知識)。軽微な事故車もあるらしいが、素人には到底見分けはつかないので十数万円ケチって命を乗せる車を買うくらいならおとなしく年式を下げたほうが良い。 まあ調べたらどのサイトでも同じことを言ってるけど、具体的な数字が出せたのはちょっとうれしい。
ただこの結果の中で、定期点検記録簿の有無に負の相関がある理由はわからない。ダミー変数だらけで、車両価格を近似するのに説明変数(というか情報量)が足りなかったとか?迷宮入りだ… 。
まとめ
- フルモデルチェンジ後の旧モデルは価格が大幅に下落
プリウスの場合は中央値で約50万円ほど変わる - 「〇万km超えたら値段が下がる!」は嘘
- 修復歴ありとなしでは平均で約15万円の価格差
修復歴ありはやめといたほうがいい
こうしてみると案外当たり前のことしか発見できてなかったりする。。でも色んな記事を見てると、データ分析をしても新たな知見が得られないことは往々にしてあることらしく、だからこそ本職のデータアナリストの方々は 最初の目的(何を明らかにしたいのか)をしっかり決めるんだろうなあ、と素人ながらに思った。
大変だけど面白そうな仕事で憧れます。おわり。
pathlibとかいう優秀すぎる標準ライブラリ(python)
自分は今までpythonでファイル操作を行うときはos.pathとかglobとかを使っていたが、pathlibという優秀なものがあると聞いて使ってみた。
python3.4以降なら使わない手はない。
以下優れている点
- os, glob の組み合わせで行ってきた操作が大体pathlib一つでできるようになる
- メソッドチェーン的に記述でき、可読性が上がる
open()
などのファイル読み込み系の操作と親和性が高い- windowsだとファイルパスにエスケープ二つ
\\
入れる必要があるが、/
区切りで解釈してくれる
以下もうひとつな点
- 一部ライブラリではPathオブジェクトを受け付けず、
str()
でキャストする必要がある copy
など一部未対応のメソッドがある
公式ドキュメントはこちら
主な使用方法
import, インスタンス生成
基本はPath オブジェクトを生成して操作することになる。
インスタンス生成時にファイルまたはディレクトリのパスを指定する。(絶対パスでも相対パスでもよい)
>>> from pathlib import Path >>> p = Path('aaa/bbb/ccc.txt')
pはPath
のサブクラスであり、windowsならWindowsPath
、linux, maxならPosixPath
オブジェクトとなる。
使い方はほぼ同じなので気にする必要はない。
引数を指定しないとカレントディレクトリのリンクが自動的にパスに入る。
>>> Path()
WindowsPath('.')
カレントディレクトリ、ホームディレクトリ取得
# カレントディレクトリ取得 >>> p.cwd() # ホームディレクトリ取得 >>> p.home()
上記メソッドは新たなパスが格納されたPathオブジェクトを返す。
これに限らず、Path
オブジェクトのメソッドは新たなPath
を返すため、文字列を直に操作する必要がなくなる。
また、上記メソッドの出力はインスタンス生成時の引数に依らず、常に同じである。
Path
オブジェクトならいつでもカレント、ホームディレクトリを呼び出せる。
絶対パス取得
まずは絶対パスを取得する。
# シンボリックリンクを解決して絶対パスを返す >>> p = Path('.') >>> p.resolve() WindowsPath('D:/project/path_test') # なんかこっちでもいけるっぽい >>> p.absolute()
公式ドキュメントには書いてなかったが、p.absolute()
でも同じことができるっぽい。内部では同じメソッドを呼び出しているのだろうか。
コードの中身を見てないのでわかりません。
ついでに絶対パスかどうかの確認
>>> p.is_absolute()
True
絶対パスならTrueを返す。
ファイル名、拡張子の取得
ファイルまでのパスがPath
オブジェクトに入っているなら以下でファイル名を取得できる
拡張子や、拡張子を除いた名前部分(stem)を取得することもできる。戻り値は文字列なので注意
# ファイル名取得 戻り値は文字列 >>> p.name 'aaa.txt' # 拡張子取得 戻り値は文字列 >>> p.suffix '.txt' # .tar.gzみたいなのは.suffixes でリスト取得できる >>> p.suffixes ['.tar', '.gz'] # 拡張子を除いたファイル名を取得 戻り値は文字列 >>> p.stem 'aaa'
ファイル、ディレクトリ削除、権限変更
パスがファイルかディレクトリかでメソッドが変わる。
# ファイル削除 >>> p.unlink() # ディレクトリ削除 ただし空ディレクトリに限る >>> p.rmdir() # 権限変更 ファイル、ディレクトリ問わず適用可能 >>> p.chmod(755) >>> p.cwd(755)
ディレクトリが空じゃない場合はおとなしくshutil.rmtree
とかを使う。
パス結合
これが一番便利かもしれない。
Path
オブジェクトでは/
演算子がパスの結合として再定義されている。
# Pathオブジェクトに文字列で除算するとパス結合されたPathオブジェクトが返る >>> Path('a/b/c') / 'd' Path('a/b/c/d') # windowsでのエスケープ二つと混ぜても同じ結果が得られる >>> Path('a\\b\\c') / 'd' WindowsPath('a/b/c/d') # 一応メソッドもある >>> Path('a/b/c').joinpath('d') WindowsPath('a/b/c/d')
ファイル一覧取得、検索
指定したパス内のファイル、ディレクトリを一覧表示・検索できる。
検索に関しては、標準ライブラリのglob
と使い方がほぼ同じである。
ただし、いずれもメソッドの戻り値はジェネレータであることに注意する。
# パス内のファイル、ディレクトリ一覧のジェネレータを返す >>> p.iterdir() <generator object Path.iterdir at 0x00000197DA6D3BF8> # パス内の.py ファイルを検索、ジェネレータを返す >>> p.glob('*.py') <generator object Path.glob at 0x000002804AEC6C50> # リストとして取り出したければキャストする >>> list(p.glob('*.py')) # パス以下を再帰的に検索したい場合は以下のように指定する >>> p.glob('**/*.py')
ファイルを開く
Path
オブジェクトにはファイルを開くメソッドも用意されている。
テキストとして開くならこれで問題ない。当然だがパスはファイルが指定されている必要がある。
# ファイルを開く >>> f = p.open('r') # 組み込み関数にPathオブジェクトを渡すこともできる >>> f = open(p, 'r')
注意すべきは、Pathオブジェクトに対応していない外部ライブラリも存在するということ。
ここによると、どうやらopenCVのcv2.imread
には対応していないらしい。
そんな時は文字列にキャストしてからライブラリに渡せば問題ない。
>>> p = Path('aaa/bbb/ccc.txt') # str()でキャストできる UNIX環境 >>> str(p) 'aaa/bbb/ccc.txt' # windows 環境でも使える >>> str(p) 'aaa\\bbb\\ccc.txt' # .as_posix()でもできるが、windows環境下でも / で区切られる >>> p.as_posix() 'aaa/bbb/ccc.txt'
as_posix()
は / で区切られた文字列が返されるため、windows環境では使用できない。
じゃあwindows用のメソッドがあるかと思いきや用意されていないっぽいので、環境に依存したくなければstr()
を使うようにすべきか。
判定系
以下のメソッドはTrueかFalseで判定を返す。
# 絶対パスかどうかを判定 >>> p.is_absolute() # 現在のパスが与えられたパターンと一致するかどうかを判定 (パターンはglob形式で指定) >>> p.match('a/*txt') # パスのファイル、またはディレクトリが存在しているかどうかを判定 >>> p.exists() # ディレクトリかどうか判定 >>> p.is_dir() # ファイルかどうか >>> p.is_file() # シンボリックリンクかどうか >>> p.is_symlink() # Pathオブジェクトが指定するファイルと引数で指定したファイルが同じファイルを参照しているかどうか # 引数にはPathオブジェクトか文字列をとる >>> p.samefile(other_path)
ファイル名変更など
# 指定したファイルまたはディレクトリをtgtにリネームする >>> p.rename(tgt) # パスの末尾のファイルまたはディレクトリ名をtgtに置き換える # 存在する場合はリネームする >>> p.replace(tgt)
os.pathは潔く捨てる
ちょっとした作業用スクリプトを作るときにも便利なので、
pythonを使っているならぜひとも享受していきたいメリットである。
参考
Pythonでフォルダ内のファイルリストを取得する - Qiita
Pythonでのファイル操作をosとpathlibで比較 - Qiita
Python3.4以降ならos.pathはさっさと捨ててpathlibを使うべき - Qiita
Python、pathlibモジュールを使う - naritoブログ
MongoDBインストール(windows, ubuntu, macOS)
リレーショナルデータベースも触ったことのない人間がいきなりMongoDBを導入してみたのでメモ。
ついでにインストールはwindows, ubuntu, macからそれぞれ行ってみた。
公式ページには大体書いてる。
2018/9/6時点ではv4.0.2が最新らしい。
Install MongoDB Community Edition — MongoDB Manual
Community EditionとEnterprise Editionの二つがあるが、個人&ローカル利用ならCommunity Editionで事足りるのでそちらを入れる。
Enterpriseはセキュリティとかの機能がサポートされて有料になるらしい。詳しくは公式を。
インストール(windows)
以下のURLにアクセス。
MongoDB Download Center | MongoDB
[Community Server] ->[Windows] とタブを開き、VersionはOSのビットを選択(画面ではWindows 64-bit)
後はインストーラの指示に従ってインストール。ある意味らくちんかもしれない。
途中でMongoDB Compass Communityというソフトも入れるかどうか聞かれるが、これはクライアントGUIツールと呼ばれるものである。要はGUIでデータベースをいじれる。
こういうツールの使い方も覚えておくと後々便利かもしれない。
参考↓
dev.classmethod.jp
インストールできたらpathを通す。
[windowsキー] → 「環境変数」で検索し環境変数を編集する
Pathを選択し編集し、MongoDB\Server\4.0\binまでのpathを追加↓
できたらコマンドプロンプトを起動し、
mongod --version
でバージョン表示されるか確認する。
インストール(ubuntu)
Ubuntu公式リポジトリのmongoDBはバージョンが古く、最新バージョンを取得するには一手間必要である。
公式リポジトリ以外からパッケージを取得するためには、そのリポジトリを認証するための公開鍵をキーチェーンに取り込まなければならない。
まず公開鍵と取り込む
sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv 9DA31620334BD75D9DCB49F368818C72E52529D4
その後ソースリストの作成
ubuntu14.04の場合
echo "deb [ arch=amd64 ] https://repo.mongodb.org/apt/ubuntu trusty/mongodb-org/4.0 multiverse" | sudo tee /etc/apt/sources.list.d/mongodb-org-4.0.list
ubuntu16.04の場合
echo "deb [ arch=amd64,arm64 ] https://repo.mongodb.org/apt/ubuntu xenial/mongodb-org/4.0 multiverse" | sudo tee /etc/apt/sources.list.d/mongodb-org-4.0.list
ubuntu18.04の場合
echo "deb [ arch=amd64 ] https://repo.mongodb.org/apt/ubuntu bionic/mongodb-org/4.0 multiverse" | sudo tee /etc/apt/sources.list.d/mongodb-org-4.0.list
あとはリポジトリ更新してインストール
sudo apt update sudo apt install mongodb-org
ターミナルで
mongod --version
とか打ち込んでバージョン情報が表示されるならインストールできてる。
ちなみに最初に取得した公開鍵のことをGPGキーとか言ったりする。GNU Privacy Guardという暗号化ソフトで生成されるらしいが詳しいことはわからないので気が向いたらまた調べる。
一応参考サイト
概要のみ↓
tech.nikkeibp.co.jp
GPGの使い方とか↓
qiita.com
インストール(mac)
homebrewでさくっと。
brew update brew install mongodb
らくちんすぎる。
手動で入れたい場合は公式からtarファイルを落とす。
以下URLから[Community Server] → [OSX]と選択してtarファイルをダウンロード。
ターミナルで以下のコマンドをたたき展開。
tar -zxvf mongodb-osx-ssl-x86_64-4.0.2.tgz
展開されたディレクトリを適当な場所に移し、ディレクトリ内の/binにパスを通す。
~/.bashrcに以下を追加。
export PATH=<path-to-mongodb-directory>/bin:$PATH
参考とか
使い方
Karl Seguinj氏のThe Little MongoDB Bookというのが勉強になるらしい。しかも無料。
githubでもtexソースが公開されてる。
GitHub - karlseguin/the-little-mongodb-book: The Little MongoDB Book
各言語への訳が有志で行われており、日本語ではMongoDBの薄い本という邦訳が有名っぽい。もうちょい他に訳あったやろ
この薄い本が検索上位に来ることが多いが、内容が古いらしいので以下の「MongoDBの手引き」のほうが良いかも
github.com
困ったときの公式ドキュメント
The MongoDB 4.0 Manual — MongoDB Manual
Markdownが書きたいのでAtomとVSCodeを整備して比較する
Markdownを書くための環境設定などをメモする。
普段はVSCodeを使っているが、github開発のAtomもmarkdownと親和性が高そうなので比べてみた。
環境はmacbook pro、macOS Sierra 10.12.6
Atom
Atomはデフォルトでmarkdownに対応しており、macならctrl + shift + m
でリアルタイムプレビューを表示できる。
それに加えて拡張機能も豊富であり、以下のサイトで色々紹介されている。
qiita.com
とりあえず以下の拡張は便利だった。
markdown-writer
各種ショートカットが追加され、キーバインドなどを設定可能。
便利。この後のtool-bar-markdown-writerがもっと便利。
tool-bar-markdown-writer
markdown編集時に、エディタ上部にtool-barが表示される。
markdownの記法を覚えてなくてもGUIで直感的に扱えるようになる。テーブル整形とかも便利。
tool-bar
とmarkdown-writer
のパッケージが必要。
markdown-pdf
Atomはデフォルトでhtml出力には対応しているが、pdfなどで出力するにはこのパッケージが必要。
コード部分なども綺麗に出る。
Atomはプレビューや出力のhtml, pdfのデザインなどがデフォルトで綺麗なとこが最大の利点かもしれない。
以下のはちょっと問題があった。
markdown-scroll-sync
プレビューをスクロールすると自動で該当するテキスト部分までスクロールしてくれる。
機能自体は便利で良いのでが、自分の環境ではなぜか動作しなかった。。
Mac以外なら動くのかもしれない。アプデ待ち。
markdown-toc
目次を自動生成してくれるパッケージ。
トピック名を変更しても上書き保存時に目次も変更してくれるのでよい。
が、これで生成したhtmlやpdfのリンクは機能しない。。意味ねえ。。
当然プレビューのリンクも効いていない。
ググってみて、先人がいたと思ったらなんかちょっと違った。
take-she12.hatenablog.com
日本語はidが生成されなくてリンクが正常にいかないらしいということはわかったが、英語でもリンクされない。
何故なのか・・・。
Atom側の問題なのかもしれない。解決できる気がしないのでとりあえず放置。
と思ったらすごいのがあった。
markdown-preview-enhanced
プレビュー、TOC作成、プレビューとスクロール同期に加えてlatex数式埋め込みからPDF、html、ebook出力などめっちゃ多機能である。
数式埋め込みなど全ての機能を使うには別途パッケージが必要だが、これを入れるだけでとりあえず
- スクロール同期プレビュー
- TOC自動作成
- html出力(リンク生きてる, ただし日本語はだめ)
の三つは実現できる。もうこれだけでいいね!
PDF出力はpuppeteer, phantomJS, princexmlの三つに対応している。princexmlは有償なのでよくわからない。
残り二つについて試してみた
puppeteer
Nodeのライブラリ。今までNode.jsとかいうのに触れた機会がなく、基礎知識など皆無だがとりあえず使う方法だけメモしておく。
Node.jsについての説明は以下だけ読んだ。
qiita.com
qiita.com
macで導入するにはまずhomebrewを導入する。多分↓のでできる。
qiita.com
その後nodeをインストールする。
brew install node echo 'export PATH="/usr/local/share/npm/bin:$PATH"' >> ~/.bash_profile
するとnpmが使えるようになっているので、
npm install -g puppeteer
とするとpuppeteerでのPDF出力が可能となる。
ここまでやってから、どうやらnodebrewとやらがあるということに気がついた
mmorley.hatenablog.com
homebrewではNode.jsのバージョン管理ができないらしい。
今はよくわかんないので必要になってからでいいかな・・・
VSCode
VSCodeもデフォルトでmarkdownプレビューに対応している。
しかし自動で分割してくれず、shift + command + V
で同じ領域の別タブにプレビュー→自分で画面分割という手順を踏む必要があり、あまりスマートな感じがしない。
以下のパッケージが非常に役に立つ。
Markdown Preview Enhanced
MPE再び。デフォルトでは微妙なmarkdownプレビューを改善してくれる。
Atomと同じctrl + shift + m
(またはcommand + K からの V
)でMPE Previewを表示でき、自動で画面分割してくれるので余計な操作はいらない。
もはやこれでほぼ事足りる。
一応こんなのもある。
Markdown PDF
VScodeデフォルトのプレビューをPDF変換する。
上書き保存時に自動変換する機能や、スタイルシートを指定して自分好みのpdfを出力できる機能がついており、拡張性が高い。
ただデフォルトだとVScodeのプレビューのまま出てくる上にフォントサイズが少々大きい。
色々いじりたい人向け。ドキュメントが日本語で読みやすい
Markdown All in One
ショートカット、テーブルフォーマット、アウトライン表示などなど、編集する際に役立つ機能が詰まった拡張。
VScodeでがっつりmarkdownを編集する人にはいいかもしれない。
ただしbold体、italic体をトグルするショートカットがVScode自体のショートカットと重複するので注意が必要。
.bstファイルをいじって著者名表記を変える
bibtexで引用する際に注意すべき点として、
- 引用順をどうするか
- 著者名表記をどうするか
がまずあげられる。分野によると思うが、自分がよく使うのは
- 文献を引用された順にソート
- 著者名のファーストネームはイニシャル
なので、それに合わせて.bstファイルをいじる方法をメモする。
デフォルトのテンプレ
欧文用ではplain.bst, unsrt.bstを使い、和文にはjplain.bst, junsrt.bstを使う。
plainでは参考文献がアルファベット順に出力し、
unsrtでは引用された順に出力する。
特に設定を書き換えない場合は参考文献を載せたい場所で
\bibliographystyle{plain} \bibliography{reference.bib}
みたいに書けば良いが、自分でいじった.bstファイルを使う場合はtexソースと同じディレクトリに.bstファイルを置く。
ここではjunsrt.bst
をいじって自分用のmyjunsrt.bst
をつくる。
/usr/local/texlive/2016/texmf-dist/pbibtex/bst/junsrt.bst
を適当にコピー。
jplain.bst
も同じ場所にある。バージョンとかは適宜読み換える。
見つからない場合は
find /usr/local/ -name junsrt.bst
とかしたら出てくる。windowsもtexlive/以下にあるんじゃないかな。知らんけど。
書き換え
.bstファイル内では、
FUNCTION {---定義名---} { ----定義の内容---- }
という形で各種表記の仕方が定義される。
こんな感じ↓
FUNCTION {format.names} { 's := #1 'nameptr := s num.names$ 'numnames := numnames 'namesleft := { namesleft #0 > } { s nameptr "{ff}{ll}" format.name$ is.kanji.str$ {s nameptr "{ff}{ll}" format.name$ 't :=} {s nameptr "{ff~}{vv~}{ll}{, jj}" format.name$ 't :=} if$ nameptr #1 > { namesleft #1 > {", " * t * } { t "others" = { s is.kanji.str$ {"$B$[$+(B" * } {", et~al." * } if$ } { s is.kanji.str$ {", " * t * } { numnames #2 = {" and " * t * } {", and " * t * } if$ } if$ } if$ } if$ } 't if$ nameptr #1 + 'nameptr := namesleft #1 - 'namesleft := } while$ }
著者名の出力を変えるにはFUNCTION {format.names}
の中身を書き換える。
上記のnameptr
とか書いているあたりを見る
{s nameptr "{ff~}{vv~}{ll}{, jj}" format.name$ 't :=}
この部分。
{ff~}{vv~}{ll}{, jj}
で著者名の表記を指定する。
- {f}でファーストネームを頭文字のみ表示、{ff}で全て表示
- {l}でラストネームを頭文字のみ表示、{ll}で全て表示
- {v}でミドルネームを頭文字のみ表示、{vv}で全て表示
- {j}でJr.を頭文字のみ表示、{jj}でJr.全て表示
- `~`をつけるとそこで改行されなくなる。姓と名で改行されないようにするために使われる。
- `.`をつけるとその位置にピリオドを表示
- `, `をつけるとその位置にカンマを表示
で変えられる。
例えばJohn Fitzgerald Kennedyが著者名の時、
- {f.~}{v.~}{ll}{, jj} で J. F. Kennedy
- {ff~}{v.~}{l.}{, jj} でJohn F. K.
みたいになる。
【追記 18/2/5】
一行前の
{s nameptr "{ff}{ll}" format.name$ 't :=}
の部分は日本語表記に使用される。ここを書き換えると漢字の苗字の一文字目だけ表示されたりするのでいじらない。
他にもタイトルや出版年の出力を変えることができるらしい。
少なくとも情報系の学会や研究会ではtexフォーマットが与えられることが多いので使う機会はなさそうだが・・・
自前で作る必要がある場合に役立つかもしれない。
○参考元
bst ファイルのカスタマイズ - Okomeda Net
LaTeXで参考文献の形式を変更する方法(bstファイルの編集) - けつあご日記