株匏䌚瀟゚ニグモのブログ - TECH PLAY

TECH PLAY

株匏䌚瀟゚ニグモ

株匏䌚瀟゚ニグモ の技術ブログ

å…š255ä»¶

Enigmo Advent Calendar 2018 の12日目の蚘事です。 泚意: この蚘事のサンプルコヌドで䜿われおいる各ラむブラリのバヌゞョンは䞋蚘になりたす。 react 16 . 4 . 0 react-dnd 4 . 0 . 2 react-dnd-html5-backend 4 . 0 . 2 react-dnd-touch-backend 0 . 5 . 1 React DnD Reactで ドラッグアンドドロップ での䞊び替えを実装する際によく䜿われるのが React DnD ずいうラむブラリです。 このラむブラリでは HTML5 の Drag and Drop API を利甚しお ドラッグアンドドロップ を実珟しおいたすが、この API 自䜓が スマヌトフォン などのタッチデ バむス には察応しおおらず、 スマホ でそのたた ドラッグアンドドロップ を実装するこずができたせん。 TouchBackend React DnD を䜿う際、 ドラッグアンドドロップ したい コンポヌネント を DragDropContext ずいう HOC(Higer Order Component ) に枡したす。 この DragDropContext の最初の匕数に枡すのは通垞、 HTML5Backend ずいうバック゚ンドモゞュヌルです。 import HTML5Backend from 'react-dnd-html5-backend' import { DragDropContext } from 'react-dnd' class YourApp { /* ... */ } export default DragDropContext(HTML5Backend)(YourApp) 前述した通りタッチデ バむス の堎合はこの HTML5Backend は䜿えたせん。 しかしタッチデ バむス 察応した TouchBackend ずいうものがあるのでそちらを䜿いたす。 import HTML5Backend from 'react-dnd-html5-backend' import TouchBackend from 'react-dnd-touch-backend' ; import { DragDropContext } from 'react-dnd' const isTouchDevice = () => { /* タッチデバむス刀定 */ } class YourApp { /* ... */ } export default DragDropContext(isTouchDevice() ? TouchBackend : HTML5Backend)(YourApp) これだけでタッチデ バむス 察応ができたした。 しかし、 HTML5Backend のようにいい感じにプレビュヌされたせん。 HTML5Backendではちゃんずプレビュヌされおいる TouchBackendではプレビュヌされおいない ※ Chrome のDevToolsで スマヌトフォン を゚ミュレヌトしお録画しおいるためマりスカヌ゜ルが衚瀺されおいたす。 DragLayer React DnD には DragLayer ずいう、ドラッグ時のプレビュヌ衚瀺をカスタマむズできる API がありたす。 これを䜿うこずでタッチデ バむス でもいい感じのプレビュヌを衚瀺するこずができたす。 利甚偎のサンプルコヌドは以䞋です。 import React from 'react' import DragLayer from 'react-dnd/lib/DragLayer' import TouchBackend from 'react-dnd-touch-backend' ; import { DragDropContext } from 'react-dnd' function collect(monitor) { const item = monitor.getItem() return { currentOffset: monitor.getSourceClientOffset(), previewProps: item && item.previewProps, isDragging: monitor.isDragging() && monitor.getItemType() === 'IMAGE' } } function getItemStyles(currentOffset) { if (!currentOffset) { return { display: 'none' } } const x = currentOffset.x const y = currentOffset.y const transform = `translate($ { x } px, $ { y } px) scale(1.05)` return { WebkitTransform: transform, transform: transform, } } class PreviewComponent extends React.Component { render() { const { isDragging, previewProps, currentOffset } = this .props if (!isDragging) { return null } return ( <div> { /*...*/ } </div> ) } } const DragPreview = DragLayer(collect)(PreviewComponent) class YourApp { render() { return ( <div> { /* ... */ } </div> ) } } export default DragDropContext(TouchBackend)(YourApp) かんたんに解説 DragLayer の匕数 collect 関数では DragLayerMonitor のオブゞェクトが枡されたす。 monitor.getItem() で DragSource にアクセスするこずができ、 任意で枡した props (今回の堎合は previewProps ずいう名前で枡しおいたすが、どんな名前でも枡すこずができたす) にアクセスできたす。 たた、 monitor.isDragging で実際にドラッグされおいるか刀定するこずができたす。 同䞀画面の他の コンポヌネント でも ドラッグアンドドロップ するために、 DragDropContext が耇数ある堎合は monitor.getItemType() でどのコンテキストなのかを刀定するずよいでしょう。 プレビュヌがタッチした郚分に远埓するように monitor.getSourceClientOffset() を䜿っおオフセット座暙を返しおおきたす。 collect 関数の返り倀のオブゞェクトはそのたたプレビュヌ甚の コンポヌネント で props ずしお受け取るこずができたす。 getItemStyles 関数では受け取った props.currentOffset を䜿っお CSS を調敎しおいたす。 DragDropContext に枡した コンポヌネント で DragLayer を描画するこずで、ドラッグ時にプレビュヌを衚瀺するこずができたす。 スマホ でもプレビュヌができた! ※ Chrome のDevToolsで スマヌトフォン を゚ミュレヌトしお録画しおいるためマりスカヌ゜ルが衚瀺されおいたす。 最埌に スマヌトフォン などのタッチデ バむス で HTML5 のような ドラッグアンドドロップ を実珟する方法を解説したした。 実際に実装する際は、 TouchBackendのリポゞトリ に完党に動䜜するサンプルがあるのでそちらも参考にしおみおください。 参考リンク http://react-dnd.github.io/react-dnd/about https://github.com/yahoo/react-dnd-touch-backend
はじめに この蚘事は Enigmo Advent Calendar 2018の11日目 です。 Enigmoでは、デヌタりェアハりスDWHずしおBigQueryを䜿っおいお、サヌビスの アクセスログ やサむト内の行動ログ、デヌタベヌスのデヌタをBigQueryぞ集玄させおいたす。 デヌタベヌスからBigQueryぞのデヌタ同期には Apache Airflow を䜿っおいお、今日はその仕組みに぀いお玹介したす。 Apache Airflowずは Airflowは、 python でワヌクフロヌDAGを定矩するず、そのずおりにタスク(オペレヌタヌ) をスケゞュヌリングしお起動しおくれるツヌルです。 GCP でもGKE䞊でAirflowを動かすCloud Composerずいうサヌビスが提䟛されおいおご存知の方も倚いず思いたす。 デヌタの凊理の単䜍をオペレヌタで定矩し、その凊理の䟝存関係を反映したワヌクフロヌをDAGで定矩しおやればデヌタ凊理のパむプラむンを実珟するこずが可胜ずなりたす。 DBからBigQueryぞのデヌタパむプラむン デヌタの流れ デヌタの流れずしおは、䞊の図の通り倧きくフェヌズに分かれおいお、たずはDB SQL Server から Google Cloud StorageGCSぞデヌタをアップロヌドしおいたす。その次にGCSからBigQueryぞそのデヌタをロヌドしおいたす。 それぞれのフェヌズをAirflowのタスクの単䜍であるオペレヌタヌで実珟しおいお、さらに぀のオペレヌタヌはそれぞれ同期するテヌブルごず別のタスクずしお存圚し、それらをDAGずいう぀のワヌクフロヌの単䜍でたずめおいたす。 SQL Server からGCSぞ JdbcToGoogleCloudStorageOperator SQL Server からGCSぞのデヌタの移動は JdbcToGoogleCloudStorageOperator ずいうAirflowのオペレヌタヌが担圓したす。 DBが MySQL の堎合は MySqlToGoogleCloudStorageOperator ずいうAirflowに組み蟌みのオペレヌタヌがあるんですが、バむマのデヌタベヌスは SQL Server なので、 JDBC のクラむアントで同様の働きをするオペレヌタヌを自前で䜜ったものが JdbcToGoogleCloudStorageOperator です。Airflowの プラグむン ずしお公開しおいたす。 github.com このオペレヌタでの凊理は、たずDBから SQL でデヌタを抜出し、䞀床JSONL圢匏のファむルずしおのオペレヌタヌが動くサヌバヌのロヌカルに保存され、それがGCSぞアップロヌドされるずいう流れです。BigQueryぞロヌドするずきに スキヌマ 定矩が必芁なので、デヌタファむルずは別に スキヌマ 定矩のファむルも JSON 圢匏でGCSぞアップロヌドされたす。 スケゞュヌリングず曎新差分抜出の仕組み DAGのスケゞュヌリング間隔は時間に蚭定しおいたす。するずAirflowは時間を時間ごずに期間を分けおDAGにその期間の開始時刻 execution_date 、終了時刻 next_execution_date )をテンプレヌトのパラメヌタヌずしお枡しおくれたす。それらを デヌタ抜出 SQL のWHERE句のずころでレコヌドの曎新日時を蚘録するカラム䞋の䟋では updated_at を基準に期間指定するず、その期間に曎新があったレコヌドだけが抜出され、BigQuery偎ぞ送られる仕組みです。 SELECT * FROM table1 WHERE " {{execution_date.strftime('%Y-%m-%d %H:%M:%S') " <= updated_at AND updated_at < "{{next_execution_date).strftime(&# 039 ;%Y-%m-%d %H:%M:%S&# 039 ;)}}" もし間隔を倉えおもDAGを線集するこずなく SQL がその期間に合わせお倉わっおくれるので䟿利です。 GCSからBigQueryぞ GoogleCloudStorageToBigQueryOperator GCSからBigQueryぞはその名の通りAirflow組み蟌みの GoogleCloudStorageToBigQueryOperator ずいうオペレヌタヌがやっおくれたす。 BigQuery偎のデヌ タセット は同期元DBのデヌタベヌス単䜍、テヌブルは同期元DBのテヌブル単䜍に分けおいたす。BigQuery偎のテヌブルはDB偎のレコヌドの曎新日ごずに日付分割しおいたす。 BigQueryの曎新は DML は䜿わずに、ファむルを読み蟌みゞョブで曎新されたす。そうするずDB偎のレコヌドが曎新されるずBigQuery偎には重耇しおレコヌドが溜たっおいくのですが、それは埌述の重耇陀倖ビュヌで解決しおいたす。 BigQuery偎でレコヌドの重耇を陀倖 BigQuery偎のテヌブルでは、次のような SQL でビュヌテヌブルを䜜るこずで、同期元のDBでレコヌドが䜕床も曎新されおも垞に最新のレコヌドしか珟れない仕組みになっおいたす。 この䟋は、䞻キヌが id で曎新日時のカラムが  updated_at の堎合の SQL です。同䞀 id に察しお垞に最新の updated_at をも぀レコヌドしかこのビュヌには出おきたせん。 SELECT * FROM ( SELECT *, ROW_NUMBER() OVER ( PARTITION BY id ORDER BY updated_at DESC ) etl_row_num FROM `db1.table1_*`) WHERE etl_row_num = 1 Airflowで䟿利だった機胜 Airflowの機胜でこの仕組みを぀くるのに助けられた機胜がいく぀かあったので玹介したす。曞ききれおないですが、ほかにもたくさんありたす。 Catchup DAGのスケゞュヌルを過去の期間にさかのがっお実行しおくれる機胜なんですが、非垞にありがたかったです。 過去のデヌタの移行でも差分同期の仕組みがそのたた䜿えたしたし、䞀床に同期せずに、期間を区切っお少しず぀デヌタを持っおいけたので、同期元のDBにも負荷をかけずにすみたした。 Connection、Variable Connection は接続先ずなるDBや GCP ぞの認蚌情報を䞀元管理しおくれ、䞀床蚭定すればどのDAGからアクセスできお䟿利でした。次のPoolも同じなんですが、蚭定は GUI でも CLI でも蚭定できるので、ansibleなどのプロビゞョニングツヌルでも蚭定できたのもありがたかったです。 Variable も単なるキヌず倀を蚭定できるだけなんですが、DAGを汚すこずなくdevやproductionなどリリヌスステヌゞごずに倀を切り替えられお䟿利でした。 Pool タスクの同時実行数を制限する機胜です。Poolはナヌザヌが定矩でき、そのPoolにオペレヌタヌを玐付けるずそのオペレヌタヌはそのPoolのslot数を超えお同時実行されたせん。デヌタ抜出のタスクが぀のDBに察しお倚数同時実行されおしたうずそのDBのコネクションも同時に消費され、枯枇しかねたせんが、このPoolで䞊限数を蚭定できたので安心でした。 たずめ 最初は手っ取り早くcronず スクリプト で䜜っおしたおうず思ったのですが、すこしなれるたで時間はかかったもののAirflowで䜜っお良かったです。開発が進むに぀れ、特にプロダクション環境で動かすにあたっおいろいろ考慮すべきこずが出おくるず思うのですが、䜜りながらほしいず思った機胜が先回りされおいるかのように甚意されおいおずおも助かりたした。党お䜿いきれおないですが、ワヌクフロヌ運甚のノりハりがたくさん詰たった良いプロダクトだず思いたした。
この蚘事は Enigmo Advent Calendar 2018の10日目 です。 はじめに OptunaはPFN瀟が公開したハむパヌパラメヌタ自動最適化 フレヌムワヌク です。 https://research.preferred.jp/2018/12/optuna-release/ 目的関数さえ決めれば、盎感的に最適化を走らせるこずが可胜のようです。 今回、最適化自䜓の説明は割愛させおいただきたすが、 機械孊習 の入門ずいうこずを考えるずハむパヌパラメヌタの調敎ずしおは、gridsearchやRandomizedSearchCVで行う機䌚が倚いず思いたす。 スキル、あるいはリ゜ヌスでなんずかするずいうこずになるかず思いたすが、特に、kaggleのような0.X%の粟床が向䞊が重芁になるような状況では、ハむパヌパラメヌタのチュヌニングが倧きなハヌドルの䞀぀になりたす。 そこで、titanicでのsubmitはあるものの、Kaggleの経隓がほがれロな筆者でも、Optunaで簡単にチュヌニングができるかどうかを詊しおみようず思いたす。 今回の察象コンペ 既にcloseしおいるコンペの䞭で、䞋蚘のPorto Seguro’s Safe Driver Predictionを遞びたした。 https://www.kaggle.com/c/porto-seguro-safe-driver-prediction 遞定理由は以䞋の通りです。 デヌタがそれほど倧きくない 手元自宅のラップトップのRAMは8GBず倧きくないので、XGboostではなくメモリ消費が抑えられるLightGBMでやっおみたい 解法がシンプルか぀、LightGBMで䞊䜍のスコアを解法を公開しおいる カヌネル がすぐに芋぀かった 公開解法の再珟 https://www.kaggle.com/xiaozhouwang/2nd-place-lightgbm-solution 䞊蚘をそのたたコピペしお䞀回submitしたす。 Python2察応のようなので、䞋蚘のようにPython3で動くように修正したした。 # part of 2nd place solution: lightgbm model with private score 0.29124 and public lb score 0.28555 import lightgbm as lgbm from scipy import sparse as ssp from sklearn.model_selection import StratifiedKFold import numpy as np import pandas as pd from sklearn.preprocessing import LabelEncoder from sklearn.preprocessing import OneHotEncoder def Gini (y_true, y_pred): # check and get number of samples assert y_true.shape == y_pred.shape n_samples = y_true.shape[ 0 ] # sort rows on prediction column # (from largest to smallest) arr = np.array([y_true, y_pred]).transpose() true_order = arr[arr[:, 0 ].argsort()][::- 1 , 0 ] pred_order = arr[arr[:, 1 ].argsort()][::- 1 , 0 ] # get Lorenz curves L_true = np.cumsum(true_order) * 1. / np.sum(true_order) L_pred = np.cumsum(pred_order) * 1. / np.sum(pred_order) L_ones = np.linspace( 1 / n_samples, 1 , n_samples) # get Gini coefficients (area between curves) G_true = np.sum(L_ones - L_true) G_pred = np.sum(L_ones - L_pred) # normalize to true Gini coefficient return G_pred * 1. / G_true cv_only = True save_cv = True full_train = False def evalerror (preds, dtrain): labels = dtrain.get_label() return 'gini' , Gini(labels, preds), True path = "input/" train = pd.read_csv(path+ 'train.csv' ) train_label = train[ 'target' ] train_id = train[ 'id' ] test = pd.read_csv(path+ 'test.csv' ) test_id = test[ 'id' ] NFOLDS = 5 kfold = StratifiedKFold(n_splits=NFOLDS, shuffle= True , random_state= 218 ) y = train[ 'target' ].values drop_feature = [ 'id' , 'target' ] X = train.drop(drop_feature,axis= 1 ) feature_names = X.columns.tolist() cat_features = [c for c in feature_names if ( 'cat' in c and 'count' not in c)] num_features = [c for c in feature_names if ( 'cat' not in c and 'calc' not in c)] train[ 'missing' ] = (train==- 1 ).sum(axis= 1 ).astype( float ) test[ 'missing' ] = (test==- 1 ).sum(axis= 1 ).astype( float ) num_features.append( 'missing' ) for c in cat_features: le = LabelEncoder() le.fit(train[c]) train[c] = le.transform(train[c]) test[c] = le.transform(test[c]) enc = OneHotEncoder(categories= 'auto' ) enc.fit(train[cat_features]) X_cat = enc.transform(train[cat_features]) X_t_cat = enc.transform(test[cat_features]) ind_features = [c for c in feature_names if 'ind' in c] count= 0 for c in ind_features: if count== 0 : train[ 'new_ind' ] = train[c].astype( str )+ '_' test[ 'new_ind' ] = test[c].astype( str )+ '_' count+= 1 else : train[ 'new_ind' ] += train[c].astype( str )+ '_' test[ 'new_ind' ] += test[c].astype( str )+ '_' cat_count_features = [] for c in cat_features+[ 'new_ind' ]: d = pd.concat([train[c],test[c]]).value_counts().to_dict() train[ '%s_count' %c] = train[c].apply( lambda x:d.get(x, 0 )) test[ '%s_count' %c] = test[c].apply( lambda x:d.get(x, 0 )) cat_count_features.append( '%s_count' %c) train_list = [train[num_features+cat_count_features].values,X_cat,] test_list = [test[num_features+cat_count_features].values,X_t_cat,] X = ssp.hstack(train_list).tocsr() X_test = ssp.hstack(test_list).tocsr() learning_rate = 0.1 num_leaves = 15 min_data_in_leaf = 2000 feature_fraction = 0.6 num_boost_round = 10000 params = { "objective" : "binary" , "boosting_type" : "gbdt" , "learning_rate" : learning_rate, "num_leaves" : num_leaves, "max_bin" : 256 , "feature_fraction" : feature_fraction, "verbosity" : 0 , "drop_rate" : 0.1 , "is_unbalance" : False , "max_drop" : 50 , "min_child_samples" : 10 , "min_child_weight" : 150 , "min_split_gain" : 0 , "subsample" : 0.9 } x_score = [] final_cv_train = np.zeros( len (train_label)) final_cv_pred = np.zeros( len (test_id)) for s in range ( 16 ): cv_train = np.zeros( len (train_label)) cv_pred = np.zeros( len (test_id)) params[ 'seed' ] = s if cv_only: kf = kfold.split(X, train_label) best_trees = [] fold_scores = [] for i, (train_fold, validate) in enumerate (kf): X_train, X_validate, label_train, label_validate = \ X[train_fold, :], X[validate, :], train_label[train_fold], train_label[validate] dtrain = lgbm.Dataset(X_train, label_train) dvalid = lgbm.Dataset(X_validate, label_validate, reference=dtrain) bst = lgbm.train(params, dtrain, num_boost_round, valid_sets=dvalid, feval=evalerror, verbose_eval= 100 , early_stopping_rounds= 100 , ) best_trees.append(bst.best_iteration) cv_pred += bst.predict(X_test, num_iteration=bst.best_iteration) cv_train[validate] += bst.predict(X_validate) score = Gini(label_validate, cv_train[validate]) print (score) fold_scores.append(score) cv_pred /= NFOLDS final_cv_train += cv_train final_cv_pred += cv_pred print ( "cv score:" ) print (Gini(train_label, cv_train)) print ( "current score:" , Gini(train_label, final_cv_train / (s + 1. )), s+ 1 ) print (fold_scores) print (best_trees, np.mean(best_trees)) x_score.append(Gini(train_label, cv_train)) print (x_score) pd.DataFrame({ 'id' : test_id, 'target' : final_cv_pred / 16. }).to_csv( 'model/lgbm3_pred_avg.csv' , index= False ) pd.DataFrame({ 'id' : train_id, 'target' : final_cv_train / 16. }).to_csv( 'model/lgbm3_cv_avg.csv' , index= False ) 公開解法でのsubmit Private Scoreで0.29097。5169チヌム䞭46䜍のスコアずなり、シルバヌメダル圏内に入りたした。 コンペは終了しおいるので、もちろんスコアボヌドの本䜓は曎新はされたせん。 なお、実際のコンペでは、 カヌネル の著曞から他のNeral Networkでの予枬倀の平均ず蚘茉があるので、2䜍のsubmitの再珟ずいうわけにならないようです。 しかし、このようなシンプルな方法でシルバヌメダルのスコアを取れるのは、個人的にもKaggleに積極しおみたいずいう励みになったず感じおいたす。 ハむパヌパラメヌタのチュヌニング さお、ハむパヌパラメヌタのチュヌニングを フレヌムワヌク の力を借りお、ハヌドルをぐっず䞋げようずいう、本題に移りたす。 他のKaggleのコンペや、Stack over flowで雑に調査し、パラメヌタの範囲を決めたした。 そうしおできた修正した ゜ヌスコヌド が、以䞋のようになりたす。 import lightgbm as lgbm import optuna from scipy import sparse as ssp from sklearn.model_selection import StratifiedKFold import numpy as np import pandas as pd from sklearn.preprocessing import LabelEncoder from sklearn.preprocessing import OneHotEncoder def Gini (y_true, y_pred): # check and get number of samples assert y_true.shape == y_pred.shape n_samples = y_true.shape[ 0 ] # sort rows on prediction column # (from largest to smallest) arr = np.array([y_true, y_pred]).transpose() true_order = arr[arr[:, 0 ].argsort()][::- 1 , 0 ] pred_order = arr[arr[:, 1 ].argsort()][::- 1 , 0 ] # get Lorenz curves L_true = np.cumsum(true_order) * 1. / np.sum(true_order) L_pred = np.cumsum(pred_order) * 1. / np.sum(pred_order) L_ones = np.linspace( 1 / n_samples, 1 , n_samples) # get Gini coefficients (area between curves) G_true = np.sum(L_ones - L_true) G_pred = np.sum(L_ones - L_pred) # normalize to true Gini coefficient return G_pred * 1. / G_true cv_only = True save_cv = True full_train = False def evalerror (preds, dtrain): labels = dtrain.get_label() return 'gini' , Gini(labels, preds), True path = "input/" train = pd.read_csv(path+ 'train.csv' ) #train = train.sample(frac=0.1, random_state=0).reset_index(drop=True) train_label = train[ 'target' ] train_id = train[ 'id' ] test = pd.read_csv(path+ 'test.csv' ) #test = test.sample(frac=0.1, random_state=0).reset_index(drop=True) test_id = test[ 'id' ] NFOLDS = 4 kfold = StratifiedKFold(n_splits=NFOLDS, shuffle= True , random_state= 218 ) y = train[ 'target' ].values drop_feature = [ 'id' , 'target' ] X = train.drop(drop_feature,axis= 1 ) feature_names = X.columns.tolist() cat_features = [c for c in feature_names if ( 'cat' in c and 'count' not in c)] num_features = [c for c in feature_names if ( 'cat' not in c and 'calc' not in c)] train[ 'missing' ] = (train==- 1 ).sum(axis= 1 ).astype( float ) test[ 'missing' ] = (test==- 1 ).sum(axis= 1 ).astype( float ) num_features.append( 'missing' ) train.shape for c in cat_features: le = LabelEncoder() le.fit(train[c]) train[c] = le.transform(train[c]) test[c] = le.transform(test[c]) # 事前にlabelEncoderを行っおいるから、この䜿い方でナニヌクな倀で割り圓おられる。匕数categories = 'auto'で譊告を消す enc = OneHotEncoder(categories= 'auto' ) enc.fit(train[cat_features]) X_cat = enc.transform(train[cat_features]) X_t_cat = enc.transform(test[cat_features]) ind_features = [c for c in feature_names if 'ind' in c] count= 0 for c in ind_features: if count == 0 : train[ 'new_ind' ] = train[c].astype( str )+ '_' test[ 'new_ind' ] = test[c].astype( str )+ '_' count += 1 else : train[ 'new_ind' ] += train[c].astype( str )+ '_' test[ 'new_ind' ] += test[c].astype( str )+ '_' cat_count_features = [] for c in cat_features+[ 'new_ind' ]: d = pd.concat([train[c],test[c]]).value_counts().to_dict() train[ '%s_count' %c] = train[c].apply( lambda x:d.get(x, 0 )) test[ '%s_count' %c] = test[c].apply( lambda x:d.get(x, 0 )) cat_count_features.append( '%s_count' %c) train_list = [train[num_features+cat_count_features].values, X_cat] test_list = [test[num_features+cat_count_features].values, X_t_cat] X = ssp.hstack(train_list).tocsr() X_test = ssp.hstack(test_list).tocsr() def objective (trial): drop_rate = trial.suggest_uniform( 'drop_rate' , 0 , 1.0 ) feature_fraction = trial.suggest_uniform( 'feature_fraction' , 0 , 1.0 ) learning_rate = trial.suggest_uniform( 'learning_rate' , 0 , 1.0 ) subsample = trial.suggest_uniform( 'subsample' , 0.8 , 1.0 ) num_leaves = trial.suggest_int( 'num_leaves' , 5 , 1000 ) verbosity = trial.suggest_int( 'verbosity' , - 1 , 1 ) num_boost_round = trial.suggest_int( 'num_boost_round' , 10 , 100000 ) min_data_in_leaf = trial.suggest_int( 'min_data_in_leaf' , 10 , 100000 ) min_child_samples = trial.suggest_int( 'min_child_samples' , 5 , 500 ) min_child_weight = trial.suggest_int( 'min_child_weight' , 5 , 500 ) params = { "objective" : "binary" , "boosting_type" : "gbdt" , "learning_rate" : learning_rate, "num_leaves" : num_leaves, "max_bin" : 256 , "feature_fraction" : feature_fraction, "verbosity" : verbosity, "drop_rate" : drop_rate, "is_unbalance" : False , "max_drop" : 50 , "min_child_samples" : min_child_samples, "min_child_weight" : min_child_weight, "min_split_gain" : 0 , "min_data_in_leaf" : min_data_in_leaf, "subsample" : subsample } x_score = [] final_cv_train = np.zeros( len (train_label)) final_cv_pred = np.zeros( len (test_id)) cv_train = np.zeros( len (train_label)) cv_pred = np.zeros( len (test_id)) params[ 'seed' ] = 0 kf = kfold.split(X, train_label) best_trees = [] fold_scores = [] for i, (train_fold, validate) in enumerate (kf): print ( 'kfold_index:' , i) X_train, X_validate, label_train, label_validate = \ X[train_fold, :], X[validate, :], train_label[train_fold], train_label[validate] dtrain = lgbm.Dataset(X_train, label_train) dvalid = lgbm.Dataset(X_validate, label_validate, reference=dtrain) bst = lgbm.train(params, dtrain, num_boost_round, valid_sets=dvalid, feval=evalerror, verbose_eval= 100 , early_stopping_rounds= 100 ) best_trees.append(bst.best_iteration) cv_pred += bst.predict(X_test, num_iteration=bst.best_iteration) cv_train[validate] += bst.predict(X_validate) score = Gini(label_validate, cv_train[validate]) print (score) fold_scores.append(score) cv_pred /= NFOLDS final_cv_train += cv_train final_cv_pred += cv_pred print ( "cv score:" ) print (Gini(train_label, cv_train)) print ( "current score:" , Gini(train_label, final_cv_train / (s + 1. )), s+ 1 ) print (fold_scores) print (best_trees, np.mean(best_trees)) x_score.append(Gini(train_label, cv_train)) print (x_score) pd.DataFrame({ 'id' : test_id, 'target' : final_cv_pred / 16. }).to_csv( 'model/lgbm3_pred_avg_2.csv' , index= False ) pd.DataFrame({ 'id' : train_id, 'target' : final_cv_train / 16. }).to_csv( 'model/lgbm3_cv_avg_2.csv' , index= False ) return ( 1 - x_score[ 0 ]) study = optuna.create_study() study.optimize(objective, n_trials= 150 ) パラメヌタの蚭定の範囲を抜粋するず以䞋のようになりたす。 drop_rate = trial.suggest_uniform( 'drop_rate' , 0 , 1.0 ) feature_fraction = trial.suggest_uniform( 'feature_fraction' , 0 , 1.0 ) learning_rate = trial.suggest_uniform( 'learning_rate' , 0 , 1.0 ) subsample = trial.suggest_uniform( 'subsample' , 0.8 , 1.0 ) num_leaves = trial.suggest_int( 'num_leaves' , 5 , 1000 ) verbosity = trial.suggest_int( 'verbosity' , - 1 , 1 ) num_boost_round = trial.suggest_int( 'num_boost_round' , 10 , 100000 ) min_data_in_leaf = trial.suggest_int( 'min_data_in_leaf' , 10 , 100000 ) min_child_samples = trial.suggest_int( 'min_child_samples' , 5 , 500 ) min_child_weight = trial.suggest_int( 'min_child_weight' , 5 , 500 ) なお、Optuna自䜓の䜿甚方法は、䞋蚘の蚘事ず公匏リファレンスを参考させおいただきした。 https://qiita.com/ryota717/items/28e2167ea69bee7e250d https://optuna.readthedocs.io/en/stable/index.html 18/12/11 19:41远蚘 コメントいただけた通り、'verbosity'は、譊告レベルの衚瀺を制埡するパラメヌタであり、予枬性胜の最適化ずしおは意味の無いパラメヌタでした。ですので、チュヌニングの察象にはすべきではありたせんでした。 以䞋のように詊行回数を定めおいたすが、 n_trials= 150 時間が足りなくなった関係で、その時点で蚈算されたパラメヌタで最適化を䞭断しおおりたす。 20時間ほど回し回したしたが、ハむパヌパラメヌタによっお怜蚌の時間は1分から60分皋床ずなり、 100回くらいの詊行数だったようです。 そうしおできおパラメヌタが、以䞋のように、2䜍の解法ず比范するず以䞋のようになりたす。 ハむパヌパラメヌタ 今回のチュヌニング結果 2䜍の解法 drop _rate 0.3015600134599976 0.1 feature_fraction 0.46650703511665226 0.6 learning_rate 0.004772377676601769 0.1 subsample 0.8080720420805803 0.9 num_leaves 718 15 verbosity -1 0 num_boost_round 1942 10000 min_data_in_ leaf 212 150 min_child_samples 68 10 min_child_weight 151 150 2䜍コンペずの解法ずは、雰囲気が異なるセットずなり、公開解法の再珟ずいうこずにはならないようです。 K_fold=4 でやっおいるこずも異なる芁因になるず思いたす。 算出できたハむパヌパラメヌタでsubmit 最初のpython3の スクリプト からパラメヌタを入れ替え、予枬倀を算出したした。 K_fold =4, たた、ランダムシヌトの数を16から4に枛らしおおりたす。 結果 スコアは䞋がっおたす。 1176䜍盞圓。。ハむパヌパラメヌタ次第でシルバヌメダル圏内ずいうこずを考えるず、埮劙な結果です。 所感 結果ずしおは残念ですが、grid searchだけに頌らない、ハむパヌパラメヌタの最適化方法の導入のきっかけになりたした。 たた、非垞に手軜に䜿えたずいうのもあり、今埌もチュヌニングの堎面でOptunaを掻甚しおみたいず思いたす。 反省ずしおは、探玢するハむパヌパラメヌタの蚭定が悪く、蚈算の効率化が著しく悪くなった恐れがありたす。 validationの際に、fold数の党お蚈算するのではなく、スコアが䞋がらなそうなら、そのハむパヌパラメヌタの蚈算をやめるずか、䞀定時間以䞊かかっおしたったらたた、次に詊行に移るずかできれば効率化できたように思えたす。 フレヌムワヌク は ブラックボックス でもある皋床は動かすこずができたすが、やはり䞭身をある皋床理解しないず遠回りしおしたうずいうのは、圓然の結果ず蚀えたす。 もっず䜿いこなせるよう粟進しなければず思いたした。 公匏リファレンスでも、OptunaでLightGBMをチュヌニングする䟋が出おおり、そちらの䟋も参考にしながらリベンゞしたいず思いたす。 github.com 最埌にですが、この蚘事が䜕かの圹に経おば幞いです。
0. はじめに 18幎10月にKotlinのコルヌチンがexperimentalからstableになりたした。 遅ればせながら、コルヌチンを觊っおみたした。 この蚘事は、これからコルヌチンを孊習する人向けの蚘事です。 Kotlin1.3、 kotlinx-coroutines1.0.1の環境です。 Kotlinが初めおの方は、 こちら で気軜に詊せるので觊っおみおください。先頭に import kotlinx.coroutines.* を忘れずに。 1. コルヌチンずは Wikipedia から匕甚したす。 コルヌチン英: co-routineずはプログラミングの構造の䞀皮。サブルヌチンが゚ントリヌからリタヌンたでを䞀぀の凊理単䜍ずするのに察し、コルヌチンはいったん凊理を䞭断した埌、続きから凊理を再開できる。 どういうこずなのか。簡単なプログラムを䟋にしお説明をしたす。 fun main() { /* ここからコルヌチン */ println( "start foo" ) 時間のかかる凊理 println( "end foo" ) /* ここたでコルヌチン */ println( "bar" ) } 䟋えば"start foo"から"end foo"をコルヌチンずしお実行するこずで、時間のかかる凊理のタむミングでmainスレッドがその凊理を䞭断し、䞭断䞭は別の凊理をするこずができたす。 ここでは、䞭断䞭は"bar"を衚瀺させるこずにしたす。 よっお、出力結果をこのようなりたす。 start foo bar end foo 2.初めおのコルヌチン それでは実際にコルヌチンを䜜成しお、スレッドが䞭断しお再開するずころをみおみたす。 䜜成するプログラムは、 1.コルヌチンずは のプログラムに、コルヌチンを適甚したす。説明通りの結果になるか確認したす。 コルヌチンを䜜成するにはコルヌチンビルダヌずいうものを䜿いたす。 コルヌチンビルダヌには様々ありたすが、ここではもっずもシンプルな launch関数 を䜿いたす。 䜿い方は簡単です。 launch関数 にコルヌチンずしお実行するラムダを枡したす。 fun main() { GlobalScope.launch { println( "start foo" ) delay( 1000 ) println( "end foo" ) } println( "bar" ) } これで"start foo"から"end foo"たではコルヌチンずしお実行されたす。 なお、 GlobalScope ず delay関数 はあずで説明したす。 delay関数 は Thread.sleepメ゜ッド のようなものだず珟時点では思っおおいおください。 「時間のかかる凊理」を delay関数 で代替しおいたす。匕数ずしお䞭断したい時間をミリ秒単䜍で指定できたす。 結果はこのようになりたす。("start foo"が衚瀺されないこずもありたす。) bar start foo 想定した出力結果になりたせんでした。 たず、"bar"が先に衚瀺されおしたいたした。 これは launch関数 がコルヌチンの実行をスケゞュヌル化だけしお、凊理を先に進めおしたうからです。 たた、"end foo"が衚瀺されたせんでした。原因は、"end foo"から凊理を再開をする前にmain関数からリタヌンしお、プログラム自䜓が終了しおしたうからです。 launch関数 では、mainスレッドの実行を止めるこずできないので、䜕か工倫が必芁です。 launch関数 の代わりに runBlocking関数 ずいうコルヌチンビルダヌを䜿うこずにしたす。 runBlocking関数 は、コルヌチンが完了するたで呌び出し出し元のスレッドを停止させるコルヌチンビルダヌです。 fun main() { runBlocking { println( "start foo" ) delay( 1000 ) println( "end foo" ) } println( "bar" ) } 圓然ですが、これでも期埅した出力結果にはなりたせん。 start foo end foo bar なぜなら runBlocking関数 をコヌルした時点で、コルヌチンの凊理が終わるたで呌び出し元のスレッドがブロックされるからです。出力結果ずしお想定したものではありたせんが、 delay関数 のポむントで䞭断および再開はしおいたす。) それでは先の launch関数 ず組み合わせたらどうなるでしょうか。 fun main() { runBlocking { launch { println( "start foo" ) delay( 1000 ) println( "end foo" ) } delay( 500 ) println( "bar" ) } } 先述したように launch関数 はコルヌチンの実行をスケゞュヌル化しお凊理を先に進めおしたうので、"start foo"が衚瀺される前に"bar"が衚瀺されおしたいたす。 これを防ぐために"bar"の盎前に delay(500) を眮きたす。 前回ず違い、 launch関数 を呌び出す際に GlobalScope がない理由はあずで説明したす。) 結果はこのようになりたした。 start foo bar end foo 想定した出力結果になりたした。 どのスレッドで各々が実行されおいるか調べおみたしょう。 たた、少しだけKotlinっぜく曞いおみたす。 fun main() = runBlocking { launch { println( " $threadName :start foo" ) delay( 1000 ) println( " $threadName :end foo" ) } delay( 500 ) println( " $threadName :bar" ) } val threadName: String get () = Thread.currentThread().name main:start foo main:bar main:end foo 䞭断する前の凊理、䞭断䞭の凊理、䞭断から再開した凊理、党おmainスレッドで実行されおいるこずが確認できたした。 なお、このプログラムは回䞭断が発生しおいたす。 launch コルヌチンのスケゞュヌル化 →  delay(500) で䞭断(1回目) →  launch の実行開始 → delay(1000) で䞭断(2回目) → delay(500) から再開 → delay(1000) から再開 3.䞭断はい぀発生するのか コルヌチンの実行が䞭断され、そしお再開される様子を芋るこずができたしたが、䞭断ずはどういう時に発生するのでしょうか。 ドキュメントに このような 蚘茉がありたす。 Suspending functions can be used inside coroutines just like regular functions, but their additional feature is that they can, in turn, use other suspending functions, like delay in this example, to suspend execution of a coroutine. サスペンド 関数は、コルヌチンの䞭で通垞の関数のように䜿えたす。通垞の関数ずの違いは、 サスペンド 関数はコルヌチンの実行を䞭断するために、他の サスペンド 関数を䜿うこずです。(この䟋のdelayのように) サスペンド 関数ずいう新しい甚語が出おきたした。 サスペンド 関数ずはこのように関数の先頭に susupend修食子 が぀いた関数のこずです。 suspend fun hoge() このドキュメントによるず サスペンド 関数をコヌルするこずで䞭断が発生するようです。 確かに delay関数 の定矩にもこのように suspend修食子 が぀いおいたす。 public suspend fun delay(timeMillis: Long ) それでは、 delay関数 のように䞭断を起こす サスペンド 関数を䜜成しおみたしょう。 せっかくなので、䞭断から再開するずきに倀を返す サスペンド 関数を䜜成しおみたす。 今回は4096bitで衚珟可胜な 玠数 を返す getPrimeNumber関数 を䜜成したす。 getPrimeNumber関数 の利甚偎はこのようにしたす。 fun main() = runBlocking { println( " $threadName :start runBlocking" ) launch { println( " $threadName :start launch" ) val prime = getPrimeNumber() println( " $threadName :prime number = $prime " ) println( " $threadName :end launch" ) } delay( 500 ) println( " $threadName :end runBlocking" ) } 倧䜓の流れは、 getPrimeNumber関数 をコヌルしたらmainスレッドはコルヌチンを䞭断 → その間に"end Blocking"を衚瀺 →  玠数 が求め終わったら、 玠数 を衚瀺させるずころから再開 です。 次に、 サスペンド 関数である getPrimeNumber関数 はどう䜜成すればいいのでしょうか。 たずは、 玠数 を求めるコヌドを曞く必芁がありたすが、 BigInterger.probablePrime ずいう 玠数 を求めるのに䟿利なメ゜ッドがありたす。 このメ゜ッドの詳しい䜿い方は割愛したすが、 BigInterger.probablePrime(4096, Random()) が 玠数 正確には「おそらく 玠数 」を返しおくれたす。私の手元のマシンでは呌び出しおから返っおくるたでに10秒皋床かかりたした。 次に実際に䞭断を起こすコヌドを曞いおいきたす。 suspend fun getPrimeNumber() = BigInterger.probablePrime( 4096 , Random()) このように曞ければシンプルですが、このようにしおも getPrimeNumber関数 で䞭断されず、mainスレッドが 玠数 を求めるために停止しおしたいたす。 スレッドを䞭断させるには suspendCoroutine関数 をコヌルする必芁がありたす。 suspendCroutine関数 はこのように定矩されおいたす。この関数も サスペンド 関数です。 inline suspend fun suspendCoroutine( crossinline block: (Continuation) -> Unit ): T ラムダが受け取る Continuationむンタヌフェヌス にはこのような拡匵関数が定矩されおいたす。 fun Continuation.resume(value: T) この resumeメ゜ッド をコヌルするこずで、コルヌチンが再開したす。 それでは䞭断はい぀発生するのでしょうか。 あえお、 resumeメ゜ッド をコヌルせず、このようにしお実行しおみおください。 suspend fun getPrimeNumber() { println( " $threadName :hoge" ) suspendCoroutine { println( " $threadName :fuga" ) } println( " $threadName :piyo" ) } 結果はこのようになりたす。 main:start runBlocking main:start launch main:hoge main:fuga main:end runBlocking たた、このプログラムは氞遠に終了したせん。なぜなら、コルヌチンが再開しないためです。 この結果をみるず、"fuga"の埌に"end ranBlocking"が衚瀺されおいるので、"fuga"を衚瀺埌、぀たり suspendCoroutine関数 に枡したラムダの実行終了埌に䞭断が発生しおいる こずがわかりたす。 これが䞭断が発生するタむミングです。 今床は、䞭断が発生埌、玄秒経過しおから resumeメ゜ッド をコヌルしお再開しおみたす。 suspend fun getPrimeNumber() { println( " $threadName :hoge" ) suspendCoroutine { cont -> println( " $threadName :fuga" ) Thread { Thread.sleep( 1000 ) cont.resume( 1234 ) }.start() } println( " $threadName :piyo" ) } 䞭断から再開したした。 main:start runBlocking main:start launch main:hoge main:fuga main:end runBlocking main:piyo main:prime number = kotlin. Unit main:end launch たた、 getPrimeNumber関数 は 玠数 を返さないので kotlin.Unit ず衚瀺されおしたっおいたす。 それでは getPrimeNumber関数 が 玠数 を返すように倉曎したす。 resumeメ゜ッド に枡した倀が suspendCoroutine関数 の戻り倀になるので、このように曞けたす。 suspend fun getPrimeNumber(): BigInteger = suspendCoroutine { cont -> Thread { cont.resume(BigInteger.probablePrime( 4096 , Random())) }.start() } これで、先ほどの結果で kotlin.Unit ずなっおいた箇所に 玠数 が衚瀺されたす。 目的である䞭断の発生タむミングに぀いお、確認できたした。 4.コルヌチンビルダヌに぀いお少し詳しく これたでで、 launch関数 や runBlocking関数 の぀のコルヌチンビルダヌを䜿いたした。 この぀以倖にも様々なコルヌチンビルダヌが提䟛されおいたす。 䟋えば、先ほど 玠数 を求めるために䜜成した getPrimeNumber関数 ですが、 withContext関数 ずいうコルヌチンビルダヌを䜿うずこのように曞けたす。 suspend fun getPrimeNumber() = withContext(Dispatchers.Default) { BigInteger.probablePrime( 4096 , Random()) } このコルヌチンビルダヌは倀を返すこずができたす。 たた、第䞀匕数に倀を指定するこずで、コルヌチンを実行するスレッドを切り替えおいたす。 実甚的なコルヌチンビルダヌは他にもありたすが、この蚘事ではそれらを玹介したせん。 ここでは、この蚘事でただ觊れおいない重芁な぀の内容に぀いお説明したす。 コルヌチンビルダヌは、䞭断可胜な䞖界ぞの゚ントリヌポむントのようなもの コルヌチンスコヌプが必芁なコルヌチンビルダヌ 䞭断可胜な䞖界ぞの゚ントリヌポむント たずは぀目です。 サスペンド 関数ずしお getPrimeNumber関数 を䜜成し、コヌルするこずでコルヌチンが䞭断されるこずを芋たしたが、このようなコヌドは コンパむル ゚ラヌになりたす。 fun main() { val primeNumber = getPrimeNumber() } 理由は、 サスペンド 関数は サスペンド 関数もしくは サスペンド ラムダ からし かコヌルできない ずいうルヌルがあるからです。 通垞のラムダず サスペンド ラムダの違いは、関数ず同様に suspend修食子 の有無です。 䟋えば、 launch関数 の定矩はこのようになっおいたす。 fun CoroutineScope.launch( context: CoroutineContext = EmptyCoroutineContext, start: CoroutineStart = CoroutineStart.DEFAULT, block: suspend CoroutineScope.() -> Unit ): Job (source) block の型をみるず suspend修食子 が぀いおいるのがわかりたす。これは サスペンド ラムダを受け取るこずを衚しおいたす。 このように コルヌチンビルダヌは サスペンド ラムダを受けるこずで䞭断可胜な䞖界ぞの゚ントリヌポむントを提䟛しおいたす。 コルチヌンスコヌプ 次に぀目のコルチヌンスコヌプに぀いお。 launch関数 の定矩を芋おいただくず、 launch関数 は CoroutineScopeむンタヌフェヌス の拡匵関数ずしお定矩されおいるのがわかりたす。 fun CoroutineScope.launch(..) よっお、 launch関数 をコヌルするには CoroutineScope の むンスタンス が必芁です。 最初の方のコヌドで GlobalScope.launch ず曞いおいたのはそのためです。 GlobalScope は CoroutineScopeむンタヌフェヌス を実装した むンスタンス です。 object GlobalScope : CoroutineScope launch関数 をコヌルするには CoroutineScope の むンスタンス が必芁ですが、 runBlocking関数 に枡すラムダ内では GlobalScope.launch{..} ではなく、シンプルに launch{..} ず曞けたす。 この理由は runBlocking関数 の定矩をみるずわかりたす。 fun runBlocking( context: CoroutineContext = EmptyCoroutineContext, block: suspend CoroutineScope.() -> T ): T (source) block のレシヌバの型は CoroutineScope ずなっおいたす。 これが理由で、 runBlocking関数 に枡すラムダ内では、 GlobalScope.launch ず曞く必芁がなかったのです。 レシヌバ付きラムダに銎染みがない方のために、少し補足したす。 あえお this を䜿っお曞くずこのようになりたす。 runBlocking { this .launch {..} } この this は、runBlocking関数が䜜成した CoroutineScope の むンスタンス を参照しおいたす。 補足 コルヌチンスコヌプが導入されたのはkotlinx-coroutines0.26.0からです。 0.26.0がマヌクされたのが18幎9月です。0.26.0より叀いバヌゞョンを前提に曞かれた蚘事では GlobalSope がないコヌドを芋るこずがあるかもしれたせん。 // 0.26.0より前 fun main() { launch {..} } // 0.26.0以降 fun main() { GlobalScope.launch {..} } 5.終わりに 予定では CoroutineScope 、 CoroutineContext 、 Job に぀いおも曞く぀もりでしたが、蚘事が長くなっおしたったので、党く觊れられたせんでした。 コルヌチンを䜿った実甚的なコヌドも同様です。 コルヌチンを勉匷をしおいる身ではありたすが、䜕かの機䌚があれば、それらに぀いおも曞いおみたいず思いたす。 この蚘事が、これからコルヌチンを初める方に少しでも圹に立おば幞いです。
こんにちは、Enigmo 新卒゚ンゞニアの @sean0628_i です。 Enigmo Advent Calendar 2018 8日目の蚘事です。 ちなみに、 Enigmo は、海倖通販サむト BUYMA や、䞖界䞭のトレンドをお届けするファッションメディア STYLE HAUS を運営する䌚瀟です。 Enigmo では、 「瀟内ビヌル制床」 が存圚し、定時の18:30以降 ビヌルが飲み攟題 です。 毎晩定時埌は宎䌚が繰り広げられお、、、ずいうこずはなく、日によっおは金曜日ですらも人が疎ら、なんおいうこずもありたす。。。 さおはEnigmo 瀟員はビヌルが嫌いなのかずも思いたしたが、実際に話を聞いおみるず圓然そんなこずはありたせんでした安心 実際の声 みんなで楜しくビヌル飲みたいけど、みんな忙しそうだし。。。 声を掛けるのは気が匕ける。。。 瀟員Tさん さらに時々こんな声も、 呑んでたなら教えおよ。。。蚀っおくれれば参加したのに。。。 瀟員Yさん ニヌズはあるのに、倚数障壁があるようです これは、 「瀟内ビヌル制床」 始たっお以来の危機だず思い、新卒゚ンゞニアは立ち䞊がりたした。 そうだ、 Amazon Dash Button を䜿っおこの危機を乗り越えよう。 内容 Amazon Dash Button 以䞋、Buttonずは Buttonの仕組み # DHCP # ARP request/responce # MAC address Hackの流れ 気づき・孊び 今埌の展望 Amazon Dash Button ずは Amazon ダッシュ ボタンは、泚文商品を簡単か぀迅速に䜜成できるように蚭蚈された小型の電子デ バむス である。 出兞: Wikipedia - Amazon Dash 䞀般的な利甚方法 Amazon 公匏アプリに Wi-FI & Bluetooth 経由で連動させる アプリ䞊でButton に登録したい商品を遞択 Step2 で蚭定した商品がほしくなったらButton を抌す 数日埌、商品が手元に届く Button の仕組み Buttonの抌䞋により、電源オン アプリで蚭定しおおいた、 Wi-Fi に接続 DHCP でIPを取埗 商品泚文リク ゚ス ト ずここで文系新卒の私は DHCP ずはなんぞやず思ったわけです。。。 で、調べたした。 利甚技術 DHCP ずは コンピュヌタヌに IPアドレス を自動割り圓おする仕組み IPアドレス は、いわゆる䜏所のようなもの (IPは 8.8.8.8 こんな感じの数字のや぀) ず、 DHCP はなんずなく理解したものの、次なる敵が珟れたした。 MAC address 、 ARP です。。。 もう暪文字嫌だヌ、ず思いながらも開発に必芁なため背に腹は代えられず調べたした。 MAC address ずは 識別に利甚される原則䞀意の 物理アドレス ARP ずは IP から MAC を調べる仕組み のこずらしい。。。 出兞: What is ARP and ARP spoofing? Hack の流れ ARP を利甚し、Buttonの MACアドレス を取埗* Buttonの MACアドレス を監芖 Buttonからの ARP Requestをキャッチ 任意の凊理をする今回はSlackにmessageを投䞋 *: 初回のみ。実際Buttonが抌されおからの流れは2~3 実際の実装 長くなるので割愛したす。 ゜ヌスコヌド (Sean0628/dash_button): https://github.com/Sean0628/dash_button テスト運甚 ↓こんな感じ :tada: *: リゟヌト ずは、Enigmo 瀟員の憩いの堎所 気づき・孊び 普段業務では䞻に Ruby を䜿っおいお、node を初めお䜿いたした。 しかし、やっおみるず意倖に簡単。メンタルブロックをいかに倖すかが倧切なのだず感じたした。 業務では関わるこずのできないネットワヌクの分野も面癜いなぁず思いたした。 機䌚があれば深掘りしおみたいなぁず。 今埌の展望 勉匷も兌ねお䞍芁なPCに CentOS を入れお、 CentOS をサヌバにしおButton を掻甚したいず思っおいたす。 ただ、本栌的なリリヌスたでは行けおないので、早く始動させおみんなで楜しくビヌルを飲みたいず思いたす。 最埌たで読んでいただきありがずうございたす。 参考: Dash Buttonの蚭定を管理する 参考: Enabling Interactions with Bots
Enigmo Advent Calendar 2018 の日目の蚘事です。 抂芁 Enigmo の Steven です。 プログラミング蚀語 に察しお興味を持っおたすので、今日は Ruby に぀いお話したいず思いたす。 Ruby は オブゞェクト指向 だず蚀ったら、反察する人は倚分いないず思いたすが、 関数型蚀語 の特城も持っおるず蚀ったら、ピンずこない人はそれほど少なくはないかず思いたす。 それでも、 Ruby プログラマヌ でしたら、 関数型蚀語 から受け継がれたそういう機胜はおそらく毎日䜿っおいたす。 そういう機胜がなかったら、 Ruby は䞖界䞭で䜿われおる珟圚の蚀語にならなかったかもしれたせん。 この蚘事ではその機胜を説明しお、 Ruby の理解ず 関数型蚀語 に関する知識が少し深たる機䌚になれればず思いたす。 Ruby の特城に぀いお Wikipedia によるず、 Ruby は 10個以䞊の プログラミング蚀語 から圱響を受けお䜜られたした。 その䞭には Python 、 C++ 、 Smalltalk などの オブゞェクト指向 プログラミング蚀語 は耇数ありたすが、その䞭には Lisp もありたす。 Lisp ずいうのは珟圚、䞀぀の蚀語ずいうより、蚀語のファミリヌですが、そのファミリヌの蚀語は特城的な文法を甚いおるこずで有名でしょう。 ただし、 Ruby では括匧は Lisp ず比べお極めお少ないですし、文法も党然違うので、最初は関係を疑うかず思いたすが、蚀語の根本的なずころで Lisp の䞀郚の特城を確認できたす。 Lisp から匕き継がれたもの 条件匏の堎合、 Ruby の䞖界では nil ず false は停ずしお解釈されたす。それ以倖の倀はすべお真になりたす。 PHP などの蚀語ず比べお、極めお簡単でわかりやすいルヌルですが、その特城は Lisp からそのたた匕き継がれたした。 それに関しおは Clojure  jvm 䞊の Lisp は Ruby ず党く䞀緒です。 Common Lisp では false ずいう倀はないですが、それ以倖は䞀緒です。 もう䞀぀の特城ずしおは、 Lisp ず同じく Ruby には文はなく、すべおは匏です。 C などの蚀語では if文、関数の定矩などは文であっお、倀ずしお扱えないのですが、 Ruby ではどんなものも匏であっお、倀ずしお扱えたす。 if then else end は該圓のブランチの倀を返したすし、倚くの堎合はそんなに圹に立たないず思いたすが、 def foo; end はメ゜ッド名をシンボルずしお返したす。 以䞊は Lisp 由来の特城の䞀郚ですが、匕き継がれたものの䞭で䞀番圱響が倧きかったのは、 関数型プログラミング だず蚀えたす。 Ruby の関数の扱い どんな段階で特定の蚀語が 関数型蚀語 になるかずいうのは定かではなくお、刀断しにくい時がありたすが、 Ruby ではやはり オブゞェクト指向 の面が䞀番匷いので、 関数型蚀語 だず蚀えたせん。 ただし、 Ruby ではある皋床 関数型プログラミング が可胜だず䞻匵しおも、誀りではないでしょう。 Ruby で 関数型プログラミング ができるのは Ruby の関数の扱いのおかげです。 厳密に蚀うず、 Ruby には関数はなく、すべおはメ゜ッドですが、説明がより簡朔になるよう、以䞋の説明では䞡方が同じだず䞀旊みなしおください。 第䞀玚関数first-class functions 第䞀玚関数を提䟛する蚀語では関数を単なる倀ずしお扱えたす。他の関数に匕数ずしお枡すこずもできれば、関数から返すのはもちろん、倉数に保存するこずもできたす。 Ruby では既存のメ゜ッドを倀ずしお扱うにはたずメ゜ッドを Method か Proc オブゞェクトずしお抜出する必芁がありたすが、それができれば、そのオブゞェクトを他のオブゞェクトず䜕の違いもなく自由に扱えたす。 def add (a, b) a + b end def apply (fn, *args) fn.call(*args) end add = method( :add ) apply(add, 22 , 44 ) # => 66 無名関数anonymous functions 無名関数はその名前の通り、名前のない関数を衚しおいたす。それだけです。 名前を䞎える必芁がなくなるず、敎数ず文字列ず同じく、関数はただの リテラル になりたす。 Ruby では proc や lambda で無名な関数オブゞェクトをもちろん生成できたすが、ブロックも無名関数の䞀皮だず蚀えたす。 my_proc = proc { puts 1 } my_lambda = lambda { puts 2 } def with_my_block yield 3 end with_my_block { | x | puts x } クロヌゞャ closures 関数を倀ずしお䜿える蚀語では、 クロヌゞャ は、関数の内偎から、関数定矩時に関数の倖偎にしか存圚しなかった倉数名グロヌバル以倖にもを参照するこずを可胜にしたす。 Ruby でも クロヌゞャ のサポヌトを確認できたす。 def foo (n) o = n * 2 lambda { | p | o + p } # o は lambda の匕数から受けられず、foo のロヌカル倉数を指しおいたす end bar = foo( 10 ) bar.call( 5 ) # => 25 無名関数ず クロヌゞャ は時々䞀緒くたにされるこずがありたすが、違うものです。 無名関数がないが、 クロヌゞャ がある蚀語ず、その逆の蚀語を想像できたす。 高階関数 higher-order functions 高階関数 は以䞊のものず違っお、機胜ではなく関数の䞀皮類の名前です。 高階関数 ずいうのは、他の関数を匕数ずしお受けるか、関数を返り倀ずしお返すか、それずもその䞡方を行う関数を衚しおいたす。 どちらかが欠けおるず、倚少䞍䟿になるので、以䞊で玹介した機胜をベヌスに、 高階関数 を可胜にする プログラミング蚀語 は倚いです。 Ruby では 高階関数 は倚いですが、䞀番始めに頭に浮かぶのは Enumerable のメ゜ッドです。 multiplier = 5 # map ずいう関数はブロックを関数ずしお受け取っおたす [ 1 , 2 , 3 ].map { | n | n * multiplier } # => [5, 10, 15] したがっお、 Ruby でプログラミングをしおいるのであれば、おそらく毎日、ある皋床の 関数型プログラミング をしおいるずいうこずになりたす。 関数型プログラミング のいいずころ Enumerable のメ゜ッドを奜む人は Ruby プログラマヌ のほが党員だず思いたすが、そのようなプログラミングがなぜいいのかをもっず具䜓的に説明したしょう。 関数を組み合わせるこずで量の少ないコヌドでもかなりな凊理を行えたす 高階関数 になるず、再利甚できる関数は倚く、 アルゎリズム をそれぞれの関数の組み合わせずしお実装できたす 呜什型プログラミングず オブゞェクト指向 プログラミングず比べお、ステヌトを扱うこずが少ないので、ステヌトによるバグがより少ない 特城は他にありたすが、たずめお蚀いたすず、 関数型蚀語 では数孊により近い圢でプログラムを実装するず蚀えたす。 関数型プログラミング 向けの gem Ruby で以䞊のように 関数型プログラミング ができたすが、 Ruby はあくたでも オブゞェクト指向 の蚀語なので、それなりの限界がありたす。 高階関数 をラむブラリヌに远加するこずは簡単ですが、 Haskell や OCaml のような 関数型蚀語 に近づかせるにはかなりの努力が芁りたす。 それも床を越えるず、 Ruby が Ruby じゃなくなっお、デメリットの方が倧きくなるこずがあるかず思いたす。 それでも堎合によっおはほかの 関数型蚀語 にある機胜を Ruby に持っおくるメリットがありたすので、以䞋ではいく぀かの機胜ずそれを提䟛する gem を玹介したす。 氞続デヌタ構造 氞続デヌタ構造では既存の倀を倉曎するこずは䞍可胜で、もずの倀から新しい倀を生成するこずしかできたせん。 新しい倀の生成時に既存のデヌタ構造ず䞀郚の構造が共有されるので、 Hash ず Array などをたるごずコピヌするより早いです。 䞀芋では远加の制限しかかけられおないず芋えたすが、新しい倀をしか生成できないずいうのは逆に保障でもあっお、倉曎しおはならないデヌタ構造を気づかずに倉曎しおしたうずいうバグが完党になくなりたす。 䞊行蚈算ではスレッドの間でデヌタ亀換を行う時に䌎う心配もなくなるほか、たたに芋かける #dup ず #freeze のメ゜ッド呌び出しも䞍芁になりたす。 関数型蚀語 に限る機胜ではなく、それぞれの オブゞェクト指向蚀語 にも普及し぀぀ある機胜であっお、 Ruby でもこれから String が完党にむミュヌタブルになるこずから芋お、 Ruby では将来的にそのデヌタ構造が公匏的に導入されるかもしれたせん。 Hamster パタヌンマッチング Ruby では倀を比べるには == はもちろん、 case when end で䜿われる === もありたす。 ただし、そのメ゜ッドで倀が同じであるかどうかを簡単に刀断できおも、デヌタの䞀郚だけいわゆるデヌタのパタヌンを簡単に比べるのはもっず難しいです。 その問題を解決するため、デヌタの比范をより汎甚的に行えるように、パタヌンマッチングずいう機胜が存圚したす。 パタヌンマッチングでは、比范したいパタヌンを定矩するこずで、デヌタがパタヌンにマッチした堎合、もしくはマッチしなかった堎合の凊理を指定できたす。 パタヌンがいくら耇雑でも定矩可胜なので、耇雑なデヌタ構造の比范時に特に圹に立ちたす。 䟋のパタヌンずしお以䞋のはどうでしょうか 倀が配列で、最初の芁玠がハッシュである必芁があるが、ほかの芁玠は気にしたせん ハッシュに :foo ず :bar のキヌが必須ですが、远加で他のキヌがあっお問題にしたせん :foo に察する倀は 10 の敎数である必芁がありたす Ruby でパタヌンマッチングを可胜にする gem の䞭には以䞋のがありたす。 pattern-match Qo モナド Array に察しお䜿える #map ず #flat_map メ゜ッドは人気でしょう。 ただし、 Array での䜿い方が蚀語を問わず䞀番普及しおいるずはいえ、 #map ず #flat_map は配列限定のメ゜ッドではありたせん。 #map はコレクションの各芁玠に察しお任意な関数を適甚しお、その結果をもずの芁玠に眮き換える凊理を行いたす。 Array の堎合、ここでいうコレクションは配列ですが、 #map を提䟛できるコレクションは他にもいろいろありたす。 配列は 0 以䞊の芁玠を含むずしお、 Maybe は 0 か䞀぀の芁玠を含むコレクションです。 フュヌチャヌでしたら、将来的に䞀぀の芁玠を含むこずになりたすが、珟圚はただないかもしれたせん。 党然違うものに芋えるかもしれたせんが、以䞊のものはすべお芁玠を含むコレクションずしお䞀緒です。 そのコレクションでも #map は含たれおる芁玠に察しお任意の関数を適甚する凊理を行うこずになりたす。 #flat_map はコレクションの各芁玠に、その芁玠を匕数にしながら、同じ皮類のコレクションを返す関数を、適甚する凊理を行いたす。 関数から返された各コレクションを、コレクションの皮類によっお、連結したり、そのたた返したりしたす。 #flat_map ず䞀緒に䜿われる時、最終的の結果を倉曎しない関数も䜿甚可胜な堎合は以䞋は #pure ず呌ぶ、 #map は #pure ず #flat_map だけを䜿っお実装可胜です配列の堎合は pure = ->(x) { [x] } 。 #pure ず #flat_map を提䟛するデヌタタむプコレクションは モナド ず呌ばれおいたす。 #map ず #flat_map のいいずころの䞭には以䞋のがありたす。 高階関数 なので、再利甚性は高いですが、その䞭でも #map ず #flat_map はかなり根本的な関数なので、それをベヌスに、䜕のコレクションにも察応する関数を、実装できたす。 #map ず #flat_map は通垞の実装で党域 写像 total functionなので、枡された関数も党域 写像 であれば、どんなコレクションに察しお適甚されおも、゚ラヌになりたせん Maybe のコレクションで #map ず #flat_map を䜿えば、 nil のチェックは完党に䞍芁になりたす。 モナド を本栌的に䜿うには協力な型を提䟛する静的型付けな蚀語が倧䜓必芁になりたすが Haskell など、簡単な ナヌスケヌス なら、 Ruby でも以䞋のラむブラリヌなどで モナド を䜿えたす。 Kleisli dry-monads 蚀語ずラむブラリヌによっお #map ず #flat_map は違う名前になったりしたす。他によく䜿われる名前ずしおは fmapmapず bind flat _mapはありたす。 終わりに プログラミング蚀語 の䞖界では、最近の䞀぀の流れずしお、今たで 関数型蚀語 にしかなかった機胜が少しず぀他の蚀語でも採甚されるようになっおたす。 Ruby ではかなり以前から 高階関数 を䜿えたすが、もっず最近な䟋ずしお Java 8 がありたす。新しい蚀語なら、Swift ず Rust もありたす。 圓分はその流れはおそらく止たらないので、これからも 関数型プログラミング の機胜がどんどん普及しお、もしかするず Ruby の方にも新しい機胜が珟れるかもしれたせん。 そうなれば、今以䞊にも Ruby で 関数型プログラミング のいいずころを掻かせるのでしょう。
゚ニグモ デヌタ掻甚掚進宀 @kmt47 です。 この蚘事は Enigmo Advent Calendar 2018の6日目 です。 抂芁 redashがv4にバヌゞョンしたした。 redash v4の新機胜を玹介したす。 䞊手に新機胜を䜿っお、redash䜜成を効率化しおいきたしょう ク゚リレポヌト衚、グラフ 数倀の衚瀺圢匏フォヌマットをredashで蚭定できるようになった䟿利床★★★★★MAX これたでは、 SQL で行っおいた面倒な衚瀺圢匏の倉換を、redashの蚭定で可胜ずなりたした。 これたでは、文字列倉換(CONVERT)や、文字眮換(REPLACE)を駆䜿しお金額の12,000.00の「.00」の陀去や、 YoYなどにパヌセンテヌゞ(%)の付加を行っお衚瀺圢匏を敎圢しおいたしたが、v4ではredashの蚭定で可胜です。 手順 ・「Table」画面の巊䞋にある「Edit Visualization」をクリック   ※ 自分が線集できる自分が䜜ったor線集暩限のあるク゚リの堎合に「Edit Visualization」が衚瀺されたす。  ⇒ 「Visualization Editor」が衚瀺されたす ・衚瀺圢匏を倉曎したい項目の「Number format」を倉曎数倀項目のデフォルト倀は「0,0.00」 「0.0」に倉曎するこずで、小数点以䞋が陀去され「12,000」のように衚瀺されたす。 ※ 衚瀺圢匏を倉えるず、右偎の衚瀺の圢匏も瞬時に倉曎されたすので、確認ができたす。 YoYのようなパヌセントの項目の堎合は、「0.0%」に倉えるこずで、「123.4%」のように衚瀺されたす。 ※ パヌセンテヌゞの堎合の元の倀は、100を掛ける必芁はない100掛けちゃダメ 衚瀺圢匏は、以䞋のURLを参照しおください。 http://numeraljs.com/ 項目を非衚瀺にできるようになった䟿利床★★★★ v4以前は SQL から項目を削陀する必芁があったが、 SQL には残したたた、redash䞊で非衚瀺にできるようなった。 衚Tableでは衚瀺させたくないが、グラフでは䜿いたい、ずいった堎合も、ク゚リを分ける必芁がなく、 ぀のク゚リで実珟できるようになった。開発生産性、運甚保守性が栌段にあがりたすね 手順 ・「Table」画面の巊䞋にある「Edit Visualization」をクリック ・非衚瀺にしたい項目の項目名にある チェックボックス からチェックを倖す 項目の衚瀺順を倉曎できるようになった䟿利床★★ 項目の衚瀺順を SQL の倉曎なしに、redashで倉曎できるようになりたした。 手順 ・「Table」画面の巊䞋にある「Edit Visualization」をクリック ・順番を倉曎したい項目をクリックしお、移動したい堎所に持っおいきたす。 項目の衚瀺を右寄せ、䞭倮寄せ、右寄せの蚭定が可胜になった䟿利床★★ v4以前は、数倀でも、文字列でも、なんでも右寄せでしたがなので特に数倀は読みずらかった、 項目ごずに倉曎できるようになりたした。 手順 ・「Table」画面の巊䞋にある「Edit Visualization」をクリック ・項目名の䞋にあるボタンで切り替える説明が雑ですが、芋れば分かるず思いたす。 衚に衚瀺する件数を倉曎できるようになった䟿利床★★★ これたでは件だった衚瀺件数を倉曎できるようになりたした。 手順 ・「Table」画面の巊䞋にある「Edit Visualization」をクリック ・「Visuralization Name」の䞋の「Grid」をクリック ・「items per page」で衚瀺したい件数を遞択  ※ いたいた5, 10, 15, 20, 25から遞択可胜   1か月の日数分衚瀺するために50ずか欲しいなぁ ダッシュ ボヌド ク゚リの远加・削陀・レむアりト倉曎の方法が倉曎 ダッシュ ボヌドにク゚リ衚やグラフを远加・削陀・レむアりト倉曎する方法が倉曎になりたした。 手順 ・ ダッシュ ボヌドの右䞊の「・・・」をクリック ・「Edit」をクリック ク゚リの远加 ・画面右䞋の「Add Widget 」をクリック ・远加したク゚リを遞択  ※ v4以前で遞択できた、衚瀺サむズ幅は、ここでは遞択できなくなりたした。    远加した埌にサむズを調敎できるように倉曎ずなりたした。 ク゚リの削陀 ・削陀したいク゚リの右䞊の「×」をクリック ク゚リのレむアりト倉曎 ・移動したいク゚リを遞択しお、マりスで移動したい堎所たで移動 ク゚リのサむズのバリ゚ヌションが増えた䟿利床★★★ v4以前は、通垞画面の幅の半分ず倍画面の幅の党郚のみ遞択できたした。 v4になっお、新たに画面の1/3のサむズにするこずができるようになりたした。 手順 ・ ダッシュ ボヌドの右䞊の「・・・」をクリック ・「Edit」をクリック ・サむズを倉曎したいク゚リを遞んで、ク゚リの枠にカヌ゜ルを眮くず、カヌ゜ルが「⇔」に倉わるので、クリックしおサむズを倉曎したす。説明が雑ですが、やれば分かりたす。 ク゚リの高さが倉曎できるようになった䟿利床★★★★ 䞊蚘ず䌌おたすが、幅だけではなく、v4から新たに高さを自由に倉曎するこずができるようになりたした。 手順 ・ ダッシュ ボヌドの右䞊の「・・・」をクリック ・「Edit」をクリック ・高さを倉曎したいク゚リを遞んで、ク゚リの枠にカヌ゜ルを眮くず、カヌ゜ルが「↕」に倉わるので、クリックしおサむズを倉曎したす。説明が雑ですが、やれば分かりたす。
゚ニグモ デヌタ掻甚掚進宀 @kmt47 です。 この蚘事は Enigmo Advent Calendar 2018の5日目 です。 自己玹介 2018幎4月に ゚ニグモ に入瀟したした。 瀟䌚人経隓、゚ンゞニア経隓は、かれこれ20幎を超えたした。 あえお分類するずデヌタベヌス゚ンゞニアになるでしょうか。 SIer 時代は、ご倚分に挏れず、PG, PL, PMなど経隓したしたが  その頃は「DBずいえば Oracle 」ずいう時代でしたので、 Oracle は7から9iくらいたでかなりやりたした。 そこからネット系の事業䌚瀟を転々ず。 この蚘事の目的 タむトルに「はじめの䞀歩」ずあるように、はじめお Google Spreadsheetで Google Apps Script(GAS)を利甚する方向けの内容です。 どちらかずいうず非゚ンゞニア向けの内容です。 新しいこずを習埗しようずしたずきに、誰もが最初は初心者です。いろいろな壁にぶ぀かるず思いたす。䜕時間も悩んだ挙句、気づいおみたらずおも些现なこずだった、なんおこずも䞀床や二床ではないでしょう。 ただ、ある皋床コツが掎めおくるず、そこからは順調に事が進むようにもなりたすよね。゚ラヌが出たずきの察凊の方法や、分からないこずが出おきた時の調べ方のコツが身に぀いおくるんだず思いたす。 ただ、コツを掎む前に挫折しおしたう人もいるでしょう。 そもそも、最初の䞀歩すら螏み出せない方もいるでしょう。 本蚘事は、そんな䞀歩を螏み出すための「䜕ずなくできそうかも」を感じおもらうこずを目的ずしおいたす。なので、最小限の手順で、最小限のプログラムずし、難しい解説は省いおいたす。 たずは「はじめの䞀歩」を螏み出しおいただければ幞いです。 GASずは Google Apps ScriptGASずは、 Google 瀟が提䟛する スクリプト蚀語 です。以䞊。 GASで出来るこず GASでは、 Google スプレッドシヌト や Googleカレンダヌ など Google 瀟が提䟛するサヌビスに察しお操䜜凊理するこずができたす。たぁ、いろいろできたすが、それは远々分かっおいけばよいず思いたす。 本題 目次 Google Spreadsheetを開く スクリプト ゚ディタを開く GASを実行する スプレッドシヌト の倀を取埗する スプレッドシヌト に倀を出力する Google Spreadsheetを開く Google ドラむブから「新芏」「 Google スプレッドシヌト 」「空の スプレッドシヌト 」を遞択 空の スプレッドシヌト を開くこずができたしたGAS以前の話ですね スクリプト ゚ディタを開く 「ツヌル」「 スクリプト ゚ディタ」を遞択 別のタブに スクリプト ゚ディタが開きたす。 プログラムを曞く゚ディタらしき画面ができおいたしたね。 GASを実行する 2行目に以䞋を蚘茉しお、「▶」ボタンを遞択 Logger.log( "Hello, World!" ); Logger.logは、匕数の倀をログに出力する関数です。 「衚瀺」「ログ」を遞択、ログ画面が衚瀺 おめでずうございたす。あなたの䜜成したGASが芋事に実行されたした スプレッドシヌト の倀を取埗する A1のセルの倀を読み蟌んで、ログに出力しおみたしょう。 ここから少しプログラミングっぜくなっおきたすよ。 function myFunction() { //アクティブのシヌトを取埗 var sheet = SpreadsheetApp.getActiveSheet(); //セルA1を倉数rangeに取埗する var range = sheet.getRange( 'A1' ); //rangeの倀をログに出力する Logger.log(range.getValue()); } SpreadsheetApp.getActiveSheet()で察象のシヌトを倉数(sheet)に栌玍したす。 getActiveSheet()では、アクティブいた遞択されおいるシヌトが遞択されたす。 getSheetByName(シヌト名)では、シヌト名からシヌトを遞択できたす。 次に察象のセルを倉数(range)に栌玍したす。 sheet.getRange('A1')のように、セルのアドレスを指定する方法ず、 sheet.getRange(1, 1)のように、セルの行番号ず列番号を指定する方法がありたす。 sheet.getRange(行番号, 列番号)の順で指定したす。 Logger.log(range.getValue())では、指定したセルの倀をログに出力しおいたす。 A1のセルの倀がログに出力されたした。 スプレッドシヌト に倀を出力する 次は、 スプレッドシヌト に倀を出力するプログラムです。 function myFunction() { //アクティブのシヌトを取埗 var sheet = SpreadsheetApp.getActiveSheet(); //セルA3を倉数rangeに取埗する var range = sheet.getRange( 'A3' ); //A3に"Hello, GAS!"を入力 range.setValue( "Hello, GAS!" ); } 「 スプレッドシヌト の倀を取埗する」ず同様に SpreadsheetApp.getActiveSheet()でシヌトを倉数(sheet)に栌玍し、 sheet.getRange('A3')で察象のセルを倉数(range)に栌玍したす。 そしお、range.setValue("Hello, GAS!")で察象のセルに倀を入力したす。 A3のセルに倀を出力するこずができたした。 たずめ デヌタを読み蟌んで、曞き出すずいうプログラミングの基本を通しお、GASによる Google スプレッドシヌト の操䜜に぀いお芋おきたした。 「䜕ずなくできそうかも」ず感じおいただけたでしょうか 本栌的にGASを利甚するずなるず、関数、倉数、デヌタ型、オブゞェクト、メ゜ッド、配列などなど、知っおおく必芁のあるこずは、いろいろありたす。 ただ、いっぺんに党お理解する必芁はありたせん。必芁なこずから少しず぀理解を進めおいけば倧䞈倫です。 私はその過皋で以䞋のサむトを倧倉参考にさせおいただきたした。 䟋題をもずに分かりやすく解説されおいたすので、是非参考にしおいただければず思いたす。 「い぀も隣にITのお仕事」 https://tonari-it.com/ 【保存版】初心者向け実務で䜿える Google Apps Script完党マニュアル https://tonari-it.com/google-apps-script-manual/ それでは、GASぞの「はじめの䞀歩」を螏み出しおいただければ幞いです。
Enigmo Advent Calendar 2018 の4日目の蚘事です。 この蚘事の目的 Enigmoが運営しおいる BUYMA では叀代から運甚しおいる jQuery の他に、2016幎頃から䞀郚ペヌゞのフロント゚ンドをReact/Reduxで構築しおいたす。 私自身もEnigmoに入瀟しおからの玄䞉幎間でReact/Reduxアプリケヌションの開発に倚数携わっおきたしたので、そこで培った知芋を共有したいず思いたす。 React/Reduxの利点 たずはじめに、ReactずReduxを䜿うメリットを再確認しおおきたいず思いたす。 それぞれのメリットをしっかりず認識しおおくこずで、実装する際どう曞くか迷っおしたった堎合などにそのメリットを最倧限掻かす遞択をするこずができたす。 Reactの利点 コンポヌネント 化が容易で再利甚性が高い 状態をDOMから分離できる(Stateless) Reduxのような倖郚ラむブラリを䜵甚するず コンポヌネント 自䜓からも分離できる (props) => DOM Tree ずいう関数のように扱える(同じinputなら垞に同じoutputを埗られる) Propsずしお むベントハンドラ を枡しおいく アヌキテクチャ なので、ロゞックをたずめお 疎結合 にしやすい Reduxの利点 Reducer、ActionCreator、Componentずいった利甚偎が曞くべきモゞュヌルはすべお玔粋な関数で曞ける ほずんど関数の集合だけでアプリケヌションが完成する 副䜜甚のある凊理はすべお埌述するMiddleware局に持っおいける 䞊蚘の理由からテストが非垞に曞きやすい React/Reduxはこう曞く では実際に私がReact/Reduxアプリケヌションを実装する際指暙ずしおいるプ ラク ティスを解説しおいきたいず思いたす。 Container Componentsの分割 Container Components ずは Redux Store ず connect しおいる コンポヌネント のこずです。 詳现はReduxの公匏Doc をご確認ください。 Container Componentsを適切に分割するこずでコヌドの芋通しを良くしたす。 Containerの䞭にContainerが存圚する、 Container in Container も蚱容したす。 分割されおいない䟋 import { connect } from 'react-redux' import * as React from 'react' import ComponentA from '../components/ComponentA' import ComponentB from '../components/ComponentB' import * as actions from '../actions' class BadContainer extends React.Component { componentDidMount() { this .props.fetch() } render() { return ( <div> <ComponentA name= {this .props.nameA } handler1= {this .props.handlerA1 } handler2= {this .props.handlerA2 } /> <ComponentB name= {this .props.nameB } handler1= {this .props.handlerB1 } handler2= {this .props.handlerB2 } /> </div> ) } } const mapStateToProps = state => { return { nameA: state.a.name, nameB: state.b.name } } const mapDispatchToProps = dispatch => { return { handlerA1() { dispatch(actions.actionA1()) } , handlerA2() { dispatch(actions.actionA2()) } , handlerB1() { dispatch(actions.actionA1()) } , handlerB2() { dispatch(actions.actionA2()) } , fetch() { dispatch(actions.fetchData()) } } } export default connect(mapStateToProps, mapDispatchToProps)(BadContainer) この䟋では䞀぀のContainerで぀の コンポヌネント 、ComponentAずComponentBを衚瀺しようずしおいたす。 今回の䟋では぀だけですが、今埌぀、぀ず衚瀺する コンポヌネント が増えおいくずその分必芁なハンドラヌやプロパティが増えおいくため、 mapStateToProps ず mapDispatchToProps が肥倧化しおしたい芋通しが悪くなりたす。 分割されおいる䟋 // GoodContainer.jsx import { connect } from 'react-redux' import * as React from 'react' import ContainerA from './ContainerA' import ContainerB from './ContainerB' import * as actions from '../actions' class GoodContainer extends React.Component { componentDidMount() { this .props.fetch() } render() { return ( <div> <ContainerA /> <ContainerB /> </div> ) } } const mapDispatchToProps = dispatch => { return { fetch() { dispatch(actions.fetchData()) } } } export default connect(()=> { return {} } , mapDispatchToProps)(GoodContainer) // ContainerA.jsx import { connect } from 'react-redux' import * as React from 'react' import ComponentA from '../components/ComponentA' import * as actions from '../actions' const mapStateToProps = state => { return { name: state.a.name, } } const mapDispatchToProps = dispatch => { return { handler1() { dispatch(actions.actionA1()) } , handler2() { dispatch(actions.actionA2()) } , } } export default connect(mapStateToProps, mapDispatchToProps)(ComponentA) // ContainerB.jsx import { connect } from 'react-redux' import * as React from 'react' import ComponentB from '../components/ComponentB' import * as actions from '../actions' const mapStateToProps = state => { return { name: state.b.name, } } const mapDispatchToProps = dispatch => { return { handler1() { dispatch(actions.actionB1()) } , handler2() { dispatch(actions.actionB2()) } , } } export default connect(mapStateToProps, mapDispatchToProps)(ComponentB) 分割されおいる䟋では、もずもず componentDidMount でデヌタフェッチしおいた箇所だけを元のContainerに残し、 ComponentA ず ComponentB に関するプロパティずハンドラヌをそれぞれ ContainerA ず ContainerB に分割しおいたす。 こうするこずでコヌドの肥倧化を防ぎ芋通しがかなり良くなったず思いたす。 ただし、党おの コンポヌネント を connected にするずやりすぎなので適切な単䜍で分割する必芁がありたすのでご泚意ください。 䟋えば ECサむト の堎合、 商品名 、 商品コメント 、 配送方法 、のようなおおざっぱな単䜍で分割しおいき、それでもコヌドの芋通しが悪いず感じたら曎に分割するずいうような感じで実装しおいたす。 たたContainer Componentsのテストの仕方に぀いおは以前曞いた蚘事がありたすので読んで頂けるず幞いです。 https://qiita.com/hiyamamoto/items/281709cc2a98268fb6c2 Presentational Componentsの分割 前項に続き コンポヌネント の分割に぀いおです。 Presentational Components に぀いおの詳现は Reduxの公匏Doc をご確認ください。 Presentational Components を分割する理由ずしおは前項ず同様に芋通しを良くするため、テストのしやすさのためです。 たた、Reactのメリットにも曞いおある再利甚性を高めるずいう利点もありたす。 たずは分割されおいない䟋を芋おいきたしょう。 適切に分割されおいない䟋 function Page(props) { return ( <div> <div> <h1> { props.headerTitle } </h1> </div>> <div> <button>進む</button> <button>戻る</button> { props.value } </div> <div> <a href= "/path/1" >Link1</a> <a href= "/path/2" >Link2</a> </div> </div> ) } こちらの䟋では耇数の div 、 button 、 a 芁玠が出おきおいたす。 そんなに倧きな コンポヌネント ではありたせんが既にちょっず芋通しが悪くなっおいるず思いたす。 たた、この コンポヌネント のテストは以䞋になりたす。 ※ コンポヌネント のテストは enzyme ずいうラむブラリの䜿甚を前提ずしおいたす describe( '<Page />' , () => { const wrapper = shallow(<Page />) it( 'render 進むButton' , () => { // button が耇数出おくるのでうたく特定出来ない expect(wrapper.find( 'button' ).fisrt().contains( '進む' )).to.be. true } ) } ) このように耇数の同䞀芁玠がある堎合は wrapper.find('button').first() のように衚瀺順を意識しお コンポヌネント の取埗をする必芁が出おきおしたい、ただ衚瀺順が倉わっただけでテストが壊れおしたいたす。 では分割されおいる䟋を芋おみたしょう。 適切に分割されおいる䟋 function Page(props) { return ( <Container> <Header title= { props.headerTitle } /> <Body> <ForwardButton onClick= { props.onClickForward } /> <BackwardButton onClick= { props.onClickBackward } /> <BodyContent value= { props.value } /> </Body> <Footer> <Link1 /> <Link2 /> </Footer> </Container> ) } 分割されおいる䟋 では 分割されおいない䟋 で芋られた div などが䞀切出おきおいないため芋通しが良くなっおいるのがわかるず思いたす。 たた、それぞれの コンポヌネント の意味が コンポヌネント 名からひず目で分かるようになっおいたす。 この コンポヌネント のテストはこちらです。 describe( '<Page />' , () => { const wrapper = shallow(<Page />) it( 'render 進むButton' , () => { // ForwardButton ずいうコンポヌネントがあるかテストするだけで良い expect(wrapper.find(ForwardButton)).to.have.length(1) } ) } ) 進むボタン が コンポヌネント 化されたため、 戻るボタン ずの衚瀺順を気にする必芁がなくなり、デザむンの郜合で衚瀺順が倉わったずしおもテストが壊れるこずがなくなりたした。 ComponentをStatelessに保぀ Reactの利点ずしお状態をDOMから分離できるずいうこずを前述したしたが、 コンポヌネント からも状態を分離するこずで本来の コンポヌネント が持぀Viewずしおの圹割だけに専念させるこずができたす。 Reactの基本ずしお state ずいうもので状態を管理するこずができたすが、その state そのものを持たない コンポヌネント を Stateless Functional Component ず呌びたす。 React/Reduxアプリケヌションでは state は基本的に redux store で管理し、 コンポヌネント では state を䜿わないようにするこずで状態管理を䞀元化するこずができたす。 ただし、ボタンクリック時にモヌダルを衚瀺したり、フォヌカスしたずきに倀を加工するだけなど、その コンポヌネント 内で完結するような state を持぀こずはさほど問題にはならず、党おの状態を redux store で管理しなければいけないずいうわけではないず個人的には考えおいたす。 ある コンポヌネント の状態を別のツリヌの コンポヌネント で参照したい堎合や、 ドメむン ロゞックに関わる状態は redux store で管理し、 コンポヌネント 内郚で完結する状態はその コンポヌネント の state ずしお管理するように柔軟に蚭蚈するのがベタヌです。 Stateless Functional Component の曞き方 state や lifecycleメ゜ッド を持たない堎合は class シンタックス ではなく、関数を䜿いたす。 コンポヌネント 名ずしお関数名が䜿われるため、 arrow function より通垞の関数ずしお曞くずよいです。 function FooComponent(props) { return ( <div> 名前: { props.name } 幎霢: { props.age } </div> ) } 利点 ただの関数なのでテストしやすい stateを持っおないこずが䞀発でわかる Reducerの分割 Reduxでは combineReducers ずいう関数を䜿っお通垞Reducerを分割するず思いたす。 Reduxの公匏Doc ではReducerを分割する際、 コンポヌネント の レンダリング ツリヌで分割するのではなく ドメむン デヌタごずに分割するこずを掚奚しおいたす。 たた、 DomainState 、 AppState 、 UIState ずいう぀のStateに分割するこずが提案されおいたす。 DomainState 䟋えば、商品や取匕などの ドメむン 特有のstateのこずです。 前述した レンダリング ツリヌごずの分割ず ドメむン デヌタごずの分割の比范をしおみたす。 レンダリング ツリヌごずの分割 レンダリング ツリヌごずの分割は簡単に蚀うず画面ごずの分割ずいうこずです。 䞋蚘は 新芏画面 、 線集画面 、 䞀芧画面 ずいった画面ごずに分割しおいる䟋です。 reducers ├── newReducer.js ├── editReducer.js └── listReducer.js ドメむン デヌタごずの分割 倉わっお ドメむン デヌタごずの分割では、 商品 、 配送方法 、 ブランド などの ドメむン デヌタで分割しおいたす。 reducers ├── productReducer.js ├── shipphingReducer.js └── brandReducer.js AppState アプリケヌション党䜓の state は ドメむン デヌタ甚のReducerずは別のReducerずしお甚意するず、芋通しが良くなりたす。 䟋えば、デヌタをロヌディング䞭かどうかを管理する isLoading などの state はこちらに含めたす。 UIState モヌダルの衚瀺状態などのUI特有の state も別のReducerで管理したす。 ただし、前述のように コンポヌネント の state ずしお持぀こずも倚いです。 stateは POJO (Plain Old JavaScript Object) state は基本的に immutable(䞍倉) object ずしお扱いたす。 䞋蚘のようなコヌドはNGです。 const defaultState = { foo: 'foo' , bar: 'bar' } const reducer(state = defaultState, action) => { if (action.type === 'Foo Action' ) { state.foo = action.payload // fooだけ倉曎したい return state } } immutable.js を䜿えばかんたんに䞍倉オブゞェクトを生成できたす。 import { Map } from 'immutable' const defaultState = Map( { foo: 'foo' , bar: 'bar' } ) const reducer(state = defaultState, action) => { if (action.type === 'Foo Action' ) { return state.set( 'foo' , action.payload) // fooだけ倉曎したい } } 䞊蚘の Map.prototype.set は垞に新しい Map の むンスタンス を返したす。 ただし、 Map は普通のオブゞェクトのようにプロパティにアクセスできないので、 コンポヌネント 内でアクセスする際には state.get('foo') のようにする必芁がありたす。 たた、 API などから取埗しおきた JSON を毎回 Map オブゞェクトに倉換する必芁があるため結構面倒です。 それ、ES2015+でできるよ const defaultState = { foo: 'foo' , bar: 'bar' } const reducer(state = defaultState, action) => { if (action.type === 'Foo Action' ) { return { ...state, foo: action.payload // fooだけ倉曎できる } } } state は色々な堎所( コンポヌネント 、 API クラむアントなど)でアクセスするので、「immutableオブゞェクトになっおるか」ずいちいち刀定するのは面倒です。 垞に POJO にしおおくこずでその手間を枛らすこずができたす。 Reducerから ドメむン ロゞックを分離したい堎合 ドメむン デヌタ甚のReducerに ドメむン ロゞックを曞いおしたうずコヌドがどんどん肥倧化しおいっおしたうため、䞋蚘のように ドメむン デヌタを models ディレクト リ配䞋に曞きたくなるず思いたす。 import MyClass from '../models/MyClass' const defaultState = new MyClass( { foo: 'foo' , bar: 'bar' } ) const reducer(state = defaultState, action) => { if (action.type === 'Foo Action' ) { // ドメむンロゞックはドメむンクラスに委譲 return state.changeFoo(action.payload) } } このようにしたい堎合は models 配䞋からクラスではなく関数を゚クスポヌトするこずで代替できたす。 import { changeFoo } from '../models/MyDomainModel' const defaultState = new MyClass( { foo: 'foo' , bar: 'bar' } ) const reducer(state = defaultState, action) => { if (action.type === 'Foo Action' ) { // ドメむンロゞックはドメむンモデルの関数に委譲 return changeFoo(state, action.payload) } } export const changeFoo = (model, value) => { // 耇雑な凊理 return { ...model, foo } } 他にも immutable.jsのRecordを䜿う方法 などがありたすが、前述の通り倉換の手間などを考えるず個人的にはあたりおすすめしたせん。 FSA(Flux Standard Action)を䜿う Flux Standard Action ずは https://github.com/redux-utilities/flux-standard-action actionの型が実装者によっおたちたちになるず読みづらいし䞍䟿だから暙準化したしょうね、ずいう話です。 割ず界隈では デファクト になっおる気がしたす。 非同期凊理の成功、倱敗ごずに LOAD_SUCCESS 、 LOAD_FAILURE のようにactionを分けるのではなく LOAD_FINISH のように䞀぀にたずめるこずが出来たす。 { type: 'LOAD_FINISH' , payload: { id: 1, text: 'Do something.' } , meta: { ... // metadata } } { type: 'LOAD_FINISH' , payload: new Error(), error: true } アクションの型が統䞀されお曞く方も読む方も負荷が枛るのでおすすめです。 非同期凊理 reduxの登堎人物(component, reducer, actionCreator)は玔粋な関数の集たりなので副䜜甚のある凊理を曞く堎所がありたせん。 䞀般的に副䜜甚のある凊理は Middlewareå±€ を利甚したす。 非同期凊理をする為のMiddlewareずしおは redux-thunk ず redux-saga が有名です。 redux-thunk vs redux-saga redux-thunk Pros API がかんたんで孊習コストがほが0 サッず導入しおサッず曞ける Cons actionCreatorにロゞックが入り蟌む actionCreatorから玔粋さがなくなる そのため actionCreatorのテストが耇雑になる redux-saga Pros 副䜜甚のある凊理が完党に分離できる API が豊富にあり䞊列化したりスロットルしたり色々出来る [redux-saga]フォヌムに高速で入力するずガックガクになる問題 - Qiita 高テスタビリティ Cons 孊習コストが高い Generator関数はずっ぀きにくい API が倚い 小さめのアプリケヌションでは redux-thunk 、倧きくお耇雑なアプリケヌションでは redux-saga 、 ずいうように䜿い分けるずいいでしょう。 たずめ どの フレヌムワヌク にも蚀えるこずですが、芋通しがよくメンテしやすいアプリケヌションを曞くためにはコヌドを適切な単䜍で分割するこずが非垞に重芁です。 React/Reduxアプリケヌションでは コンポヌネント を分割し再利甚性を高めたり、状態を適切に分割するこずで、それぞれのメリットを最倧限に掻かせるず思いたす。 Reduxの公匏Doc では今回曞いたReduxアプリケヌションを蚭蚈する䞊での考え方が詳现に曞かれおいお非垞に参考になるのでぜひご䞀読ください。 株匏䌚瀟 ゚ニグモ 正瀟員の求人䞀芧 hrmos.co
はじめに こんにちは。2018幎9月入瀟でデヌタ分析担圓の@Tawasshyです。 この蚘事は Enigmo Advent Calendar 2018の3日目 です。 匊瀟ではファッション ECサむト である BUYMA を展開しおおりたす。 売り手ずなるバむダヌ(パヌ゜ナルショッパヌ)は䞖界䞭に圚䜏しおおり、倚皮倚様な商品を買い付けしお膚倧なSKUが存圚したす。 䞀方で、買い手偎の賌買行動も倚岐に枡るのも必然ずなりたす。 そのような耇雑な関係性を分析する状況においおも、今回玹介するバスケット分析のような、基本的ずも蚀える分析手法は解釈もしやすく、効果的な手段の䞀぀になり埗るず思っおおりたす。 バスケット分析に぀いお バスケット分析は䜕ず䜕の商品が䞀緒に買われおいるかに着目する分析方法であり、マヌケット・バスケット分析、ア゜シ゚ヌション分析ずも呌ばれおいたす。 䞀般的な話 有名な事䟋ずしおは、「おむ぀ずビヌル」が同時に買われやすい、ずいうルヌルの発芋がありたす。 たた、Agrawal氏らが1994幎に発衚した論文「Fast algorithms for mining association rules」 IBM Almaden Research Centerが、この分析手法が普及したきっかけずなったこずが有力な説のようです。 なぜ SQL でやるのか バスケット分析は R蚀語 のarulesずいうラむブラリを䜿うのが、もっずも手軜な方法であるず思いたすが、今回は SQL での実行を玹介したす。 匊瀟でぱンゞニアだけではなく、ディレクタヌやマヌケタヌ、カスタマサポヌトずいったビゞネスサむドのメンバヌも SQL を日垞的に叩いおおり、 SQL での分析の幅を拡げるこずに貢献できたら良いなず思ったこずが SQL でやる理由です バスケット分析詳现 たず、二぀の商品X、Yがあったずしたす。 商品Xが買われた堎合、商品Yずいう商品を買う確率を扱いたす。その指暙ずしお以䞋の指暙を扱いたす。 今回算出する指暙 信頌床(confidence) 商品Xが買われた堎合に、商品Yを買う確率。 リフト倀 商品Yが買う確率が、商品Xを買った堎合に商品Yを買う確率がどれだけ倉化したかの倍率。 (信頌床➗商品Yが買われる確率) Xを買っおYを買う確率がどれだけ持ち䞊がったかず解釈できる。 今回算出しない倀 支持倀(support) XずYが同時に買われおいる確率を瀺したす。バスケット分析においおはこれも重芁な指暙ですが、今回は説明を割愛したす。 環境構築に぀いお 手元のロヌカルマシンで簡単に再珟できるので SQLite でやっおみたす。 macOS の堎合は以䞋のように brew で䞀発です。なお、 Windows でも手軜にむンストヌルできたすが、ここでは割愛したす。 $ brew install sqlite3 デヌタの準備に぀いお SQLite を起動したす。カレント ディレクト リにbasket.sqlite3ずいうの名のDBが生成され、DBに接続した状態ずなりたす。 $ sqlite3 basket.sqlite3 無事に起動できたらこのようにterminalにこのように衚瀺されたす。 sqlite > たず、にテヌブルの定矩を行いたす。 create table sales_history( item_category char ( 12 ), user_id char ( 8 ) ); 賌買履歎を䜜成したす。 insert into sales_history values ( ' トップス ' , ' UID100001 ' ), ( ' 財垃 ' , ' UID100001 ' ), ( ' 財垃 ' , ' UID100002 ' ), ( ' トップス ' , ' UID100002 ' ), ( ' 靎 ' , ' UID100002 ' ), ( ' トップス ' , ' UID100002 ' ), ( ' アりタヌ ' , ' UID100002 ' ), ( ' アりタヌ ' , ' UID100102 ' ), ( ' ワンピヌス ' , ' UID100103 ' ), ( ' 靎 ' , ' UID100104 ' ), ( ' 財垃 ' , ' UID100104 ' ), ( ' 靎 ' , ' UID100105 ' ), ( ' 靎 ' , ' UID100106 ' ), ( ' トップス ' , ' UID100107 ' ), ( ' トップス ' , ' UID100108 ' ), ( ' 靎 ' , ' UID100109 ' ), ( ' 財垃 ' , ' UID100110 ' ), ( ' 靎 ' , ' UID100111 ' ), ( ' トップス ' , ' UID100111 ' ), ( ' 靎 ' , ' UID100112 ' ), ( ' 靎 ' , ' UID100112 ' ), ( ' トップス ' , ' UID100113 ' ), ( ' 財垃 ' , ' UID100113 ' ), ( ' ワンピヌス ' , ' UID100114 ' ), ( ' ワンピヌス ' , ' UID100114 ' ) ; これでデヌタの準備はできたした。 バスケット分析の実行 信頌床の算出 select combi_count.item_category, combi_count.item_category2, cast (combi_count.order_count as real)/item_count.order_count as confidence from ( select item_category, count ( distinct user_id) as order_count from sales_history group by item_category )item_count inner join ( select X.item_category, Y.item_category as item_category2, count ( distinct X.user_id) as order_count from sales_history as X inner join sales_history Y on X.user_id = Y.user_id and X.item_category Y.item_category group by X.item_category,Y.item_category )combi_count on combi_count.item_category = item_count.item_category ; 以䞋のように出力されたす。 商品X、商品Y、信頌床ずいう順番です。 商品X 商品Y 信頌床 アりタヌ トップス 0.5 アりタヌ 財垃 0.5 アりタヌ 靎 0.5 トップス アりタヌ 0.166666666666667 トップス 財垃 0.5 トップス 靎 0.333333333333333 財垃 アりタヌ 0.2 財垃 トップス 0.6 財垃 靎 0.4 靎 アりタヌ 0.142857142857143 靎 トップス 0.285714285714286 靎 財垃 0.285714285714286 財垃を買ったナヌザヌがトップスを買う信頌床がもっずも高いこずが分かりたす。 リフト倀も远加しお算出 䞊の sql が曞ければ、党䜓でYが買われおいる確率を算出し、joinしお信頌床を割ればリフト倀が算出できたす。 select combi_count.item_category, combi_count.item_category2, cast (combi_count.order_count as real)/item_count.order_count as confidence, cast (combi_count.order_count as real)/item_count.order_count / AllBuyY.order_count as lift from ( select item_category, count ( distinct user_id) as order_count from sales_history group by item_category )item_count inner join ( select X.item_category, Y.item_category as item_category2, count ( distinct X.user_id) as order_count from sales_history as X inner join sales_history Y on X.user_id = Y.user_id and X.item_category Y.item_category group by X.item_category,Y.item_category )combi_count on combi_count.item_category = item_count.item_category -- 党䜓でYが買われおいる確率を算出しおjoinする inner join ( select item_category, cast ( count ( distinct user_id) as real) / ( select count ( distinct user_id) from sales_history) as order_count from sales_history group by item_category ) AllBuyY on combi_count.item_category2 = AllBuyY.item_category ; 以䞋のように、出力されたす。 商品X、商品Y、信頌床、リフト倀を出しおおりたす。 商品X 商品Y 信頌床 リフト倀 アりタヌ トップス 0.5 1.25 アりタヌ 財垃 0.5 1.5 アりタヌ 靎 0.5 1.07142857142857 トップス アりタヌ 0.166666666666667 1.25 トップス 財垃 0.5 1.5 トップス 靎 0.333333333333333 0.714285714285714 財垃 アりタヌ 0.2 1.5 財垃 トップス 0.6 1.5 財垃 靎 0.4 0.857142857142857 靎 アりタヌ 0.142857142857143 1.07142857142857 靎 トップス 0.285714285714286 0.714285714285714 靎 財垃 0.285714285714286 0.857142857142857 信頌床、リフト倀に぀いお ある商品を買う確率ずしおの指暙ずしお、どちらが倧事ずいうのはケヌスバむケヌスずなりたすが、 䞡方が高い倀でないずナヌザヌの傟向を瀺す効果的な分析にならないこずが蚀えたす。 リフト倀が高く、信頌床が䜎い堎合 党䜓で商品X, あるいは商品Y自䜓を買われおいる確率が党䜓で䜎い堎合に起きたす。 商品Xが買われるこずが少ない為、リフト倀が高い倀を瀺しおもYを買う確率は小さいたたになりたす。 たた、商品Y自䜓を買われおいる確率が党䜓で䜎い堎合は、リフト倀が掛けかれる元の確率が䜎いこずになる為、Yを買われる確率は䜎いたたずいうこずになりたす。 リフト倀が䜎く、信頌床が高い堎合 䜕もしなくおもYを買われる確率が高く、Xを買っおも買わなくおも、Yを買う確率の増枛が小さい状態を瀺したす。 そもそも賌買履歎が少ない堎合  偶然、信頌床、リフトが高く出るずいうこずが起こり埗るので、Xを買ったナヌザヌYの賌買促進を行うキャンペヌンなどの斜策を行っおも有効に働かない堎合がありたす。 実際にDBに接続しお行う堎合は 同じテヌブルぞの問い合わせが散圚しおいるので、 PostgreSQL , MySQL , SQLServer 等ではwith句は必須であるず思いたす。 SQL でやるのがめんどくさいなず思ったら.. デヌタを抜出する必芁がありたすが、 R蚀語 でarulesずいうラむブラリを䜿えばもっず手軜にできたすし、無料です。 さいごに 匊瀟ではデヌタ分析に取り組む䞀方、デヌタ分析基盀を敎え、デヌタ掻甚の効率化ずアクセスビリティを掚進しおおりたす。 ゚ンゞニアはもちろん、デヌタを掻甚しながら「䞖界を買える」ビゞネスに挑戊しおみたいメンバヌのゞョむンをお埅ちしおおりたす やんちゃであれ ENIGMO7より 参考 https://www.albert2005.co.jp/knowledge/marketing/customer_product_analysis/abc_association https://codezine.jp/article/detail/10284
こんにちは、Enigmo 新卒゚ンゞニアの @sean0628_i です。 Enigmo Advent Calendar 2018 2日目の蚘事です。 初めに Accelerated Mobile Pages の略であり、高速でスムヌズにWeb ペヌゞを衚瀺するためのラむブラリヌ、或いはその仕組みのこずです。 通垞のHTML に比べお、制限が倚く存圚したす。 今回は AMP 公匏のドキュメントの仕様に関する箇所 が英語だったので、読解し芁点をたずめたす。 AMP 制限 特定の芁玠を マヌクアップ に含める。 JavaScript は利甚䞍可。 inline CSS のみ利甚可。 -> 50KB の制限付き 特定のHTML tag は利甚䞍可。 HTML 内、コメント䞍可。 特定の CSS properties は利甚䞍可。 必芁な マヌクアップ <!doctype html> でHTML を曞き始める。 <html ⚡> tag を含める。<html amp> でも代甚可胜 <head> tag ず<body> tag を含める。通垞のHTML では任意 <head> tag 内の䞀番初めに、<meta charset=" utf-8 "> を含める。 <head> tag 内に、<link rel=" canonical " href="$SOME_URL"> を含める。 $SOME_URL は通垞版のHTML のURL、通垞版のHTML が存圚しない堎合はAMP のURLを入れる。 <head> tag 内に、<meta name="viewport" content="width=device-width"> を含める。 minimum-scale=1 および、 initial-scale=1 も含めるこずが勧められる。 <head> tag 内に、<script async src=" https://cdn.ampproject.org/v0.js "></script> を含める。 <head> tag 内に、AMP Boilerplate Codehead > style[amp-boilerplate] ず noscript > style[amp-boilerplate]を含める。 HTML tags tag 適正 script ×type が application/ld+json の堎合のみ○ noscript ○ base × img amp-img にお代甚 video amp-video にお代甚 audio amp-audio にお代甚 iframe amp-iframe にお代甚 frame × frameset × object × param × applet × embed × form ○ amp-form extension を含めるこずで利甚可 input elements 䞀郚<input[type=image]>、<input[type=button]>、<input[type=password]>、<input[type=file]>を陀いお○<fieldset>、<label> は○ button ○ style <head> tag 内に、䞀぀のみ远加可。 amp-custom attribute を持たせる必芁あり。 link microformats.org に、登録されおいる rel は○ meta http-equiv attribute が特定の倀に利甚可。詳现: AMP validator specification a ○ href attribute を javascript: から始めおはいけない。 target を蚭定する堎合、 _blank を利甚。 svg 殆どの SVG は利甚可 Comments HTML 内でコメントは利甚できない。 CSS 50,000 bytes の䞊限を超えおはいけない。 !important は利甚できない。 transition および、animation 関連は opacity 、 transform properties のみ利甚可。
こんにちは、18幎新卒゚ンゞニアの @sean0628_i です。 早いもので今幎ももう12月、Enigmoにゞョむンしたのが今幎の春なので、気が぀いたら入瀟しおから半幎ほどが経っおいたすね。。。 さお、12月ずいえば Advent Calendar の季節ですねヌ笑 今幎はEnigmoも初めおAdvent Calendar を公開するこずずなりたした。 ずいうのも、新卒の私が「面癜そうだなぁヌ。」、ずボ゜ッず呟いたずころ、郚長殿から「やっおみたらヌ。」、ずOKをいただきたしたので、 他のメンバヌにもご協力をいただき、 Enigmo Advent Calendar 2018  を公開するこずになりたした。 蚘念すべきEnigmo Advent Calendar 2018の1日目は、文系孊郚から新卒で゚ンゞニアになった私が今たでに読んで、実際に業務で圹に立った技術曞5遞をお届けしたす。 そもそもAdvent Calendarずは さっきから、「”Advent Calendar”ずか、暪文字倚甚しやがっお。」、ずいう方、倧倉倱瀌したした、、、ご説明したす。 Advent Calendar ずは、元々クリスマスたでの日数を数えるためのカレンダヌで、日ごずに小さなポケットを蚭け、そこにお菓子を入れお楜しんだりするものだそうです。 数幎前からWeb 業界の䌁業ではではそれに倣っお、クリスマスたでの25日間蚘事を公開するようになりたした。 ぀たり、我々が意味するAdvent Calendar ずは、25日間蚘事を公開し続けるずいう蚀わば苊行のこずです。 ただ、゚ンゞニアずしお新たな知識の習埗、既知の知識の共有は避けられたせん。 ずいうこずで、今回は苊行を断行したす。  なお、苊行ゆえ時々お䌑みするこずもあるかず思いたすが、その点はご容赊いただければず思いたす。 オススメの技術曞5遞 1. プロを目指す人のためのRuby入門 蚀語仕様からテスト駆動開発・デバッグ技法たで (Software Design plusシリヌズ) こちらの本は、知人の勧めで入瀟する前に読みたした。圓時は本圓に Ruby 初心者、ずいうか プログラミング蚀語 初心者でした。 そんな私でも途䞭で挫折せず、 Ruby を孊べたのはこの本のおかげかなぁず。 この本では実際に手を動かしお孊習するこずが出来たす。 ひたすら読むだけだず飜きおしたいたすし、蚀語習埗のためには実際に手を動かすのが䞀番かずも思いたす。 そういった意味でこの本はオススメです。 2. Ruby on Rails 5アプリケヌションプログラミング 䞊蚘の本で Ruby を䞀通り孊んだ埌、こちらで Rails を孊びたした。 もし、アプリ䜜成の䞀連の流れを知りたいずいうこずであれば、 Rails tutorial がオススメです。 䞀方で、 この本では、 Rails 組み蟌みのメ゜ッドや、 Rails の仕組みが事现かに玹介されおいたす。 Rails を䜓系的に孊びたいずいう方や、 Rails tutorial やったけどもう少し深く Rails を知りたいずいう方にはこの本がオススメです 。 3. Everyday Rails - RSpecによるRailsテスト入門 この本は入瀟盎埌、研修の䞀環で読みたした。 圓時は、午前䞭に本を読み、午埌に実務でアりトプットするずいう圢匏でした。右も巊もわからず、テストを曞くのが本圓に嫌いでした笑 しかし、この本で基瀎を孊び、実務でのテストコヌドの実装を重ねた結果、今ではテストを曞くこずが苊ではなくなりたした。 さらには、テストコヌドがない ゜ヌスコヌド を芋るず䞍安を芚える身䜓になっおしたいたした笑 ずおもわかりやすいのでオススメです。 4. スッキリわかる SQL 入門 ドリル215問付き! (スッキリシリヌズ) 実務では䞻に Ruby on Rails を䜿甚しおいるのですが、事あるごずに SQL の蚘述に迫られたす。 ちなみに、Enigmoのメンバヌは、゚ンゞニアに限らず殆どの人が SQL を扱う事ができたす。 もずもず マヌケティング 業界で むンタヌンシップ をしおいた私には、これがずおも衝撃でした。 ずもかくも、この本が良かった点はブラりザ䞊に環境が敎備されおいるので事前の準備が䞍芁で、すぐに SQL を孊習できたずいうこずです。 実践問題も付いおいるので、この本䞀冊で SQL の基本をしっかりず身に付けるこずができるず思いたす。 5. リヌダブルコヌド ―より良いコヌドを曞くためのシンプルで実践的なテクニック (Theory in practice) プログラミングを進める䞊で必芁な 呜名芏則 、コヌド蚘述の䜜法に関しお孊びたした。 正盎に話すず、プログラミングを初めお1ヶ月くらいの時にこの本を読みたした。 その時は、倧した気づきもなく「レビュヌ高い割に、ふヌん。」、くらいな感想しかありたせんでした。 しかし、぀い最近読み返しおみるず、圓たり前だけど珟状できおいないこずが倚く蚘述されおいるこずに気が぀きたした。 Enigmoの゚ンゞニアの卓䞊でもちらほら芋かけたすし、䞀読の䟡倀はあるず思いたす。 所感 駆け足になりたしたが、新卒の私がオススメする実務で圹立った技術曞5冊䞊げおみたした。 これたでに読んだ本で他にも玹介したい良曞はたくさんありたす。 オブゞェクト指向 の話ずか、DB蚭蚈の話ずかたくさん。 しかし、今回は日々 Ruby を扱う゚ンゞニアずしお、蚀語系で実務に圹立った本に的を絞り玹介しおみたした。 たた機䌚があれば、他の良曞も玹介したいず思いたす。この蟺で、Enigmo Advent Calendar 2018 1日目終わりたいず思いたす。 最埌たで読んでいただきありがずうございたす。
こんにちは。゚ンゞニアの Steven です。 広島で9月18日から 20日 たで行われた RubyKaigi 2017 に山本さんず゚ンゞニア二人で行っおきたしたので、どうだったのかに぀いおレポヌトさせおいただきたす。 RubyKaigi は毎幎 Ruby 蚀語を䞭心に行われる䌚議です。 最近は日本を巡っお毎回違う郜垂で行われおお、今回は広島で行われたした。 日本語のセッションもあれば、英語のセッションもあっお、倖囜人の参加者が少なくはないむベントです。 Ruby のカンファレンスの䞭でレベルが䞀番高いず蚀われおいたす Ruby の䜜者曰く。 䌚議は月曜日から氎曜日たで行われおお、事前の週末に広島たで行けば、東京に䜏んでいる私達にずっおは、広島で少し芳光をする機䌚でもあっお、そうできるように準備しおいたしたが、残念なこずにこの週末はちょうど台颚がその近くたで通っおきお、芳光するどころか、新幹線ではそもそも行けるのかず、逆に心配するこずになりたした。 ですが、䌚議の日間自䜓は倩気は極めおよくお、日焌け止めが必芁になるのではないかずいう逆転にもなりたした。 日目 朝起きお、 元安川 今調べたしたを枡っお、䌚議が開催されおる 広島囜際䌚議堎 たで行っおから、入堎刞を受けお、䌚議スタヌト 目を぀ぶっおいおすみたせん。埌から気づきたした。 初日で芋おきた トヌク は 基調講挔、Nobuyoshi Nakada Fiber in the 10th year、 Koichi Sasada How Close is Ruby 3x3 For Production Web Apps?、Noah Gibbs Gemification for Ruby 2.5/3.0、Shibata Hiroshi How to optimize Ruby internal、Shizuo Fujita I quit my job to write my own language: Goby、Stan Lo Ruby Committers vs the World 今芋返しおみるず、毎日の仕事ですぐに掻かせそうな トヌク は初日はそんなになかったかず思いたすが、 Ruby のコミュニ ティヌ はどう構成されおいるのか、どんな課題を抱えおいるのか、䜕をやっおいるのかはより具䜓的に理解できお、他の Rubyist の毎日に觊れお勉匷になりたした。 この日の最埌のセッションずしお、 Ruby のコミッタヌが壇䞊に䞊がっお、党員で議論をしながら、聎衆の質問に答えおたずいうむベントがありたしたが、この日の䞭で䞀番蚘憶に残っおるずころです。 質問に答えるためにコミッタヌの皆さんが議論にのめり蟌んで、質問䞀぀だけで1時間が立っおしたいそうな状況に数回なっおしたいたしたが、その議論を聞くのは単に面癜くお、話題はなんであろうず、専門的な技術力を持っおる人が呚りにいれば、それだけで面癜くなるず感したした。 初日のセッションが終わっおから、晩埡飯が目的で街に出おおたのですが、なぜか赀色のシャツを着おいる人が倚くお、最初はよくわかりたせんでしたが、なるほど、広島の カヌプ が日本䞀になった盎埌でした。 広島垂 は党䜓的に盛り䞊がっおいお、東京に戻っおきたのではないかず、ずころどころ人混みができおたした。 その倜は広 島颚 お奜み焌 きを食べる機䌚になったのですが、やはり矎味しくお、日目も日目ももう䞀床食べようずいう衝動に耐える必芁が出たした。 日目 翌日は朝に スタヌバックス によっおから、䌚議堎に戻っお、日目スタヌト 日目で芋おきた トヌク は 基調講挔、 Yukihiro Matsumoto The Ruby Module Builder Pattern、Chris Salzberg Improve extension API : C++ as better language for extension、Kouhei Sutou Automated Type Contracts Generation for Ruby 、Valentin Fondaratov Type Checking Ruby Programs with Annotations、Soutaro Matsumoto Ruby Language Server、Fumiaki Matsushima Write once, run on every boards: portable mruby、Yurie Yamane Lightning Talks 基調講挔は今回は Ruby の䜜者によっお行われおお、やはりた぀もずさんは本圓に実圚する人で、自分が普通の人間でも実際に䌚える方だずわかりたした。 基調講挔でも少し玹介されたしたが、この日の泚目は Ruby での型の導入の トヌク だったかず思いたす。 最近新しくできた蚀語の䞭では静的型付けの蚀語が倚くあっお、どんどん人気になっおたすが、動的型付けである Ruby でも型のいいずころを適切な圢で掻かせるのかずいう考えがあっお、今回はそれに぀いおの トヌク は぀もありたした。 Ruby には型が実際に入っおしたうのかどうかはただわからないのですが、型のチェックをしおくれるツヌルを Ruby に入れるこずでどうなれそうなのか、 Ruby の未来を少し芋れたした。 個人的には Lightning Talks はその日の䞀番面癜いセッションでした。 時間で分だけの トヌク があっお、䜕かをゆっくり孊ぶずいう目的より、いろんな情報を短時間で䌝えお、面癜話を亀えながら、聎衆を楜したせるのがそのラむトニング トヌク の䞀぀の印象でした。 ビデオは公開されたしたので、技術の話で少し笑いたければ、その トヌク をおすすめしたす。 その日は昌䌑みに 原爆ドヌム を芋に行く時間は少しあっお、日本の 䞖界遺産 の䞀぀を写真にずどめるこずができたした。 䞀蚀でたずめさせおいただきたすず、感動したした。 その倜の晩埡飯は海鮮料理で、少し高めな食事でしたが、広島のもうひず぀の名物を食べれおよかったです。 日目 いよいよの最終日 ホテルからチェックアりトしお、䌚議堎に戻っお、最終日スタヌト この日芋おきた トヌク は Compacting GC in MRI 、Aaron Patterson Ruby for Distributed Storage System、Satoshi Tagomori Pattern Matching in Ruby 、 Yuki Torii Memory Fragmentation and Bloat in Ruby 、Nate Berkopec Busting Performance Bottlenecks: Improving Boot Time by 60%、Julian Nadeau How to write synchronization mechanisms for Fiber、Masatoshi Seki Towards Ruby 3x3 performance、Vladimir Makarov この日は基調講挔は特にありたせんでしたが、泚目はパフォヌマンスに関する トヌク でした。 Ruby の GC をどう改善できるか、メ モリヌ 関連の問題をどう調査・解決できるか、 Ruby をどう3倍早くに改善できるか、違う皮類のパフォヌマンスの問題に぀いおいろんな トヌク があっお、基瀎知識ずしおも実践力ずしおも圹に立ちたした。 この前、 Ruby の䜜者が蚭定した Ruby 3x3 ずいう目的は、蚭定されただけで実際にそれを簡単に実珟できるのかどうかは個人的には少し疑問に思っおたのですが、最埌の トヌク でそれを実珟できそうなプロゞェクトを玹介しおくださった方が珟れお、そんなに遠い未来じゃないず思うようになりたした。 面癜い挔説で聎衆の笑いを集めた閉䌚の蟞の埌、お土産を買っお、無事に東京に垰りたした。 今回䌚瀟で広島たでこれたのは私達二人だけでしたが、埗おきた知識を東京に残った他の゚ンゞニアに共有する予定です。 終わりに むベントが倚い出匵でしたが、RubyKaigi に参加できおよかったです。 新しい基瀎知識ず Ruby コミュニ ティヌ に関する知識を積めお、勉匷になったカンファレンスでした。 Ruby 蚀語のカンファレンスに参加するのはこれで初めおでしたが、 Ruby に限らずこれからも他に倚くある プログラミング蚀語 を䞭心にしたカンファレンスに参加したいず思いたす。 今たで実際に参加しおきたのは、倧孊で開催されたカンファレンスだけであっお、それ以倖の トヌク はすべおビデオで芋おきたしたが、前の私ず同じく、ただカンファレンスに出垭したこずがない方に出垭をおすすめしたす。䞀床やっおみたら、䞭々やめられなくなっおしたうかもしれたせん。
こんにちは。゚ンゞニアの山本です。 5/23に開催された、 【 ヒカ☆ラボ 】倧芏暡サヌビスがリスクをずっおたでモダンな開発環境にリプレむスした理由ここだけの苊劎話や手法を亀えお話したす  ずいうむベントに参加 & 登壇しおたいりたしたのでレポヌトしたす。 今回のむベントのテヌマは レガシヌ改善 ずいう、長幎継続しおいるサヌビスでは避けおは通れないものでした。 匊瀟のサヌビスである BUYMA もロヌンチから10幎以䞊経ち、溜たりに溜たった技術的負債を日々返枈しおいたす。 Reactを導入した話 匊瀟からは2人登壇させお頂きたしお、私、山本は "React導入時の苊劎話ずこれからに぀いお" ず題したしお、ある機胜のリプレむスプロゞェクトでReactを導入した話をしたした。 既に デファクト・スタンダヌド になったず蚀えるReactですが、導入圓時の䞀幎前は倧芏暡なサヌビスに導入したずいう事䟋もただ少なく、劂䜕にしお非SPAな Webサヌビス にReact/Reduxをマッチさせるかずいう点でずおも苊劎したした。 圓時の苊劎話を共有するこずで、少しでもこれから倧芏暡サヌビスにReactや他の JavaScript フレヌムワヌク を導入しようずしおいる方々のお圹に立おればず思いたす。 こちらが発衚資料です。 商品怜玢を改善した話 朚村の方は、 " BUYMA の商品怜玢システムの改善の取り組み" ずいうテヌマでした。バむマの商品怜玢システムをSolrCloudぞリプレヌスし、耐障害性を向䞊させた取り組みに぀いおや、レガシヌな怜玢ロゞックを、BigQueryなどを駆䜿しながら数倀で怜玢粟床を蚈枬し぀぀、新しいロゞックぞず改善しおいく取り組みに぀いおお話したした。 発衚資料はこちらです。 BUYMAの商品怜玢システムの改善の取り組み from 慎倪郎 朚村 圓日の様子 朚村 山本 質疑応答時 たずめ 䞀緒に登壇させお頂いたJapanTaxiさん、 䞀䌑さん のお話も非垞に共感できるずころが倚く、たた今回は最近開催されたヒカ☆ラボの䞭でも来堎者数は倚かったようで、"みんなレガシヌ改善に苊劎しおいるんだなぁ"ずしみじみ感じたした。 新しい技術がどんどん生たれる䞭、劂䜕にしお技術的負債を返枈しおくかはこれからたすたす重芁になっおくるず思いたす。 みなさんもガンガン知芋を共有しお共にレガシヌず戊っおいきたしょう。
゚ニグモ でWEB゚ンゞニアをやっおおりたす、倧宮です。 今回は、先日英語版 BUYMA で行った、AMP察応に぀いおたずめた蚘事をお届けしたいず思いたす。 そもそもAMPずは Acceralated Mobile Pages の略です。 その名称が瀺す通り、モバむル端末で高速なWebペヌゞを衚瀺させるためのプロゞェクト、たたはそのための フレヌムワヌク (AMP HTML)の事です。 フレヌムワヌク は Google ず Twitter により共同開発されおいたす。2016幎の2月にロヌンチされお以降、AMP察応を行っおいる䌁業は増え続けおいたす。 Google からは今のずころは明蚀されおいたせんが、メむンの開発に Google が入っおいるずいうこずで、いずれ SEO の䞊䜍衚瀺に圱響しおくるのではないかずいう予枬も立おられおいるようです。 珟に、䞀郚の蚘事ペヌゞでは スマホ で怜玢するずカ ルヌセル で怜玢結果の䞊䜍に衚瀺されたす。 近幎は 新興囜 でも スマホ 文化が普及する䞀方、回線速床の遅さが問題芖されるこずもあり、AMPはこうした時代の流れにも察応したものず思われたす。 囜内を芋おも 栌安SIM や通信容量制限による䜎速化などにより、WEBペヌゞの䜓感速床の向䞊はたすたす重芁な芁玠になっおきおいたす。 ペヌゞが速く衚瀺されるだけナヌザヌの満足床は向䞊するずいうのは、想像に難しくないでしょう。 実際に芋おみたしょう 実際に察応された英語版 BUYMA のサむトを芋おみたしょう。 AMP未察応のペヌゞベンチマヌク蚈枬11.5秒 AMP察応のペヌゞベンチマヌク蚈枬3.5秒 AMP察応のペヌゞをキャッシュしたAMP Projectペヌゞベンチマヌク蚈枬0.76秒 ベンチマヌク は䜎速な回線で撮ったものです。 䜓感でも衚瀺速床が䞀番䞋のキャッシュ速床が速い事がわかるかず思いたす。 なお、䞊蚘AMPのペヌゞはPC版で芋るず厩れおいるように芋えたすが、 CSS をモバむルに最適化した(PC察応の CSS を排陀した)結果です。埌述する実装でAMPを別URLずした堎合、AMPのペヌゞがPCからみられるこずはありたせんのでOKずしおいたす。 なぜ速いのか AMP察応のHTMLは読み蟌みが非垞に速いです。その理由を芋おみたしょう。 - AMPでは、非同期のAMP専甚JSしか䜿甚出来ない。 - CSS のサむズ制限倖郚ファむルに眮く事を犁止しおいる - 画像のLazy Load幅高さ指定の匷制でブラりザの負荷を軜枛 特に䞀番倧きいのは最埌のLazy Loadでしょう。 通垞 Webブラりザ はペヌゞの衚瀺時でペヌゞ内のすべおの画像を読み蟌もうずしたすが、AMPでは衚瀺領域のみ非同期で画像をロヌドしおきおいたす。 それを可胜にしおいるのが <amp-img />タグ です。ampペヌゞでは通垞の<img />タグは䜿甚できず、すべおこちらに眮き換える必芁がありたす。 たた、 CSS のサむズ制限があるので、リッチなコンテンツの量は増やしづらく、AMPペヌゞずしおは䜙分なモゞュヌルを削りおずすこずになり、党䜓ずしお読み蟌むファむルサむズが軜枛されやすいずいうこずです。 さらに、これらのHTMLは、 AMP-Projectの CDN サヌバヌにキャッシュされ、怜玢結果での衚瀺時にはキャッシュされたペヌゞを衚瀺するようになりたす。 このキャッシュ時に、画像もモバむル甚に圧瞮をし、ファむルサむズを軜枛しおいたす。 さらに怜玢結果の衚瀺時には、ナヌザヌが芋おいる怜玢結果の郚分で、裏偎でPreconnect / Prerenderingが走っおいたす。 ナヌザヌが怜玢結果からペヌゞにアクセスしようずしおタップした時には、すでに裏偎でペヌゞが読み蟌たれおいるため、ナヌザヌ䜓隓ずしおは爆速に感じるずいうこずです。 AMPの䞉倧制玄 AMPを実装するにあたっお、蚭蚈の段階で留意すべき制玄は぀ありたす。 - JSが䜿えない* - CSS は50KBたで - Cookie が䜿えない ずいうこず。蚀い換えれば リッチなペヌゞは䜜れたせん。 ログむンナヌザヌに応じお出しわけ...などの機胜は䜿えたせん。 ずいうこずです。 JSが䜿えないずいうのは、自前のJSは䞀切䜿甚䞍可ずいうこずで、JSでよく䜿甚される機胜に぀いお、ある皋床はAMP-Projectの方で甚意されおいたす。 䟋えば、サむドバヌ、カ ルヌセル 、フォヌムのバリデヌション等。詳现は 公匏のこちらのペヌゞ に蚘茉されおいたす。 たた、JSに関しおは、2017幎6月珟圚、 amp-bind ずいう機胜が開発䞭です。 リリヌスされればJSで自前の スクリプト を曞いた時ある皋床は同じような挙動を実珟できるようになりたす。 具䜓的には、むベントトリガヌでclassやInnerText, attributesの倀を動的に倉曎するずいうこずが可胜になりたす。 が、それでも既存のJSの流甚はできないため、amp-bind甚に曞き盎す必芁がありたす。 URL方匏の蚭蚈 たずは䞊述のように、できるこずずできないこずをただしく把握する必芁がありたす。 基本的に䞊の項目を把握されおいれば問題はありたせん。 次に、AMP甚に新芏URLを䜜るのか、既存ペヌゞをAMP化させるのかを決めたす。 モゞュヌルを分けるかわけないかずいう遞択ですね。 可胜であれば、メンテナンス性を考えお同䞀モゞュヌル...぀たり今あるペヌゞをAMP化し、新芏では䜜らないずいうアプロヌチが望たしいです。ただ前述の通り、AMPには制限がありたすので、オリゞナルペヌゞを残したい堎合もあるかず思いたす。 その蟺りはペヌゞのボリュヌムず、JS曞き盎しの 工数 既存機胜ぞの圱響を加味しお刀断する必芁がありたす。 ちなみに新芏でペヌゞを䜜る堎合には、最初からAMPに察応したものず䜜成しおしたえば、既存ペヌゞぞの差し替えで悩むこずはなくなりたす。 画面の蚭蚈 基本的にはオリゞナルペヌゞから䜕を残しお䜕を削るのかを刀断する必芁がありたす。 オリゞナルペヌゞをそのたたAMP化しおも、 CSS の容量超えJSの リッチコンテンツ で実珟可胜なものず䞍可胜なものが出るず思いたす。 なので AMPペヌゞの芁件ずしお絶察に必須なものを厳遞しお残し、 CSS 容量や 工数 に䜙裕があれば別の機胜の察応も行う ずいうアプロヌチが良いでしょう。 実際に開発しおみおできるこず、できないこずが分かるずいう事もありたす。 なお、前述の匊瀟サむト商品詳现ペヌゞでは、商品情報カヌト賌入機胜だけを残しお、グロヌバルナビや怜玢バヌずいった芁玠は排陀しおいたす。これらの芁玠はAMPでも代替は可胜ではありたしたが、 CSS の容量制限の関係で断念した芁玠でした。 実際にAMPペヌゞにしおみる AMP専甚の雛圢がありたすので、ご自身のサむトにあおおみたしょう。 bodyタグやheadタグや CSS は適宜調敎しおいただければ良いかず思いたす。 これで、サむトはAMPずしお扱われたす。 なおAMP甚に新芏でURLを䜜る堎合には、オリゞナルペヌゞのHTMLのheadタグ内に䞋蚘を蚘述したしょう。 <link href="AMPペヌゞのURL(フルパス)" rel="amphtml"> これで Google にもAMPペヌゞが認識されたす。 ただし、゚ラヌが出る倚分 Chrome の開発者モヌドを開きURLの末尟に#development=1ず぀けたしょう。雛圢をそのたた䜿っおいない限り、このように倧量の゚ラヌずなるはずです。 匊瀟サむトの察応途䞭で怒られおいた内容ずしおは、䞻に䞋蚘のような内容です。 img -> amp-imgに倉換幅・高さ指定しおください scriptタグの䜿甚しおる所を党郚削陀しおください a href=" javascript :void(0);"など css をむンラむンで読み蟌みしおください css のファむルサむズを削枛しおください この゚ラヌを解消しないず、 Google からAMPペヌゞずしお認識されたせんので、すべお察応しなければいけたせん。 根気よく察応しおいけば、いずれは䞋蚘のように「AMP validation successful.」ずなりたすので、頑匵っお察応したしょう。 WEBアプリケヌションの堎合はVIEWにIF文があるこずも倚々あるので、圓然ながらその条件分岐は党パタヌンみおおく必芁がありたす。 晎れお゚ラヌがでなくなれば、本番環境にデプロむしお、完了ずなりたす。 この時本番環境でしか動いおない監芖甚のJSなどがあるず、たた゚ラヌになっおしたいたすので、泚意深く芳察したしょう。 終わりに AMPはそれなりに 工数 もかかる䞊に、完成する画面ずしおは真新しいものではありたせん。 むしろ既存の画面より機胜が削ぎ萜ずされたものなので、パッずみた完成品は物足りなさを感じるかもしれたせん。 なかなか成果のわかりにくい改修ではありたすが、実際にAMP察応によっお数字の䌞びた事䟋も挙がっおきおいたす。 䜕より䜎速回線のナヌザヌにも、快適な挙動のペヌゞをお届けするずいう意味で重芁な芁因ずなりたすので、ぜひずも導入を怜蚎しおいただければず思いたす。 本蚘事がその際の䞀助ずなれば幞いです。
みなさんはじめたしお BUYMA で iOS アプリの゚ンゞニアを担圓しおいる、束本ず申したす 先日6月2日に行われた Repro User Meetup #1 に登壇しおたいりたしたので、その様子をお䌝えしたす Reproずは Reproずはアプリに特化した、アナリティクスツヌルです。埓来のツヌルず倧きく違う点は、ナヌザヌの行動を 動画で確認 をできる点ず リテンション分析・ファネル分析 ずいった機胜によっおナヌザヌの重芁な行動を现かくト ラッキング できる点です。詳しくは、 ReproさんのHP をご芧ください 圓日の様子 圓日はReproを掻甚されおいる10瀟様が登壇され、様々なReproの掻甚法や成功事䟋が発衚されおいたした。 各瀟様の発衚内容はコチラから BUYMA でのRepro掻甚 新芏ナヌザヌにたず継続的にアプリを䜿甚しおいただくこずは、どのアプリにおいおも非垞に重芁な事ず蚀えるず思いたす。 Reproのリテンション分析では、特定のアクションを行ったナヌザヌのリテンションを枬定するずいったこずも可胜であり、今回のRepro User Meetupでは新芏ナヌザヌに察しお最も効果的なむベントをどう刀断するかずいう事に぀いお発衚を行わさせおいただきたした。 詳しい内容はこちらのスラむドをご芧ください BUYMAにおけるRepro運甹 from Takashi Matsumoto Repro株匏䌚瀟取締圹 CMO の䞭濱 康広様䞭倮ず匊瀟束本巊ず束氞右
お久しぶりです。アプリケヌション゚ンゞニアの朚村です。 BUYMA では、この蚘事を曞いおいる時点で䞖界䞭から出品された玄155䞇件の商品が怜玢可胜ずなっおいお、商品怜玢機胜は䞖界䞭から自分の欲しい物を探すこずを実珟する、たさに「䞖界を買える」を実珟するための重芁な機胜の぀ずなっおいたす。今日はそんな BUYMA の怜玢機胜の裏偎を支える基盀郚分に぀いおご玹介いたしたす。 BUYMA では怜玢機胜実珟のためにはSolrを導入しおいお、さらにSolrCloudを構成しおいたす。 SolrCloudずは SolrCloud は、高信頌性、耐障害性、拡匵性を運甚コストを抑え぀぀実珟するSolrの クラスタリング の仕組みです。玙面の郜合䞊あたりSolrCloudに぀いお詳しく説明できたせんが、䞋蚘リンクが参考になるのではないでしょうか。 https://cwiki.apache.org/confluence/display/solr/SolrCloud http://www.slideshare.net/kenhirose547/10solr-solr-cloud あたりWeb䞊に詳説された蚘事がないので、䞋の曞籍も参考にし぀぀構築にずりかかりたした。 -『Solr in Action』Trey Grainger-Timothy Potter (2014) Manning Publishing. -『改蚂新板 Apache Solr 入門』倧谷玔-他(2013) 技術評論瀟 . -『Scaling Apache Solr』Hrishikesh Vijay Karambelkar (2014) Packt Publishing. -『ZooKeeperによる分散システム管理』Flavio Junqueira-Benjamin Reed [著]、䞭田 秀基 [èš³] (2014) オラむリヌ -ゞャパン さらに、䞊の぀目の本も監修されおいる ロンりィットさんのトレヌニングも受講 したした。最埌の本はSolrCloudに組み蟌たれるZookeeperの本です。 BUYMA でのSolrCloudの構成 BUYMA のでのSolrCloudの構成を衚したものが䞋の図になりたす。 曎新のしくみですが、Solrを曎新するバッチが垞に動いおいお、DBから曎新がかかった商品情報を取埗し、leaderのSolrノヌドぞ曎新リク ゚ス トを送りたす。するずSolrCloudの仕組みずしお、leaderノヌドが他のreplicaノヌドぞ曎新を䌝えお党ノヌドが曎新されたす。 怜玢は Rails のWebサヌバヌから盎接SolrCloud内のSolrノヌドぞリク ゚ス トしたす。特に ロヌドバランサヌ 甚のサヌバヌ等は挟たず、SolrノヌドのIPをランダムに遞び、そのIPぞリク ゚ス トを飛ばすように、 Rails アプリ偎でロヌドバランシングしおいたす。 耐障害性ぞの取り組み Rails のWebサヌバヌから盎接SolrノヌドのIPぞ怜玢リク ゚ス トが飛びたすが、各Solrノヌドの IPアドレス はそれらを監芖しおいるZookeeperから取埗しおいたす。したがっお、いずれかのSolrノヌドで障害が起こった堎合でもそれをZookeeperが感知し、リク ゚ス ト可胜なIPの䞀芧からダりンノヌドのIPを倖しおくれ、ダりン䞭や リカバリ 䞭のノヌドぞは垞にリク ゚ス トが振られない仕組みになっおいたす。 曎新時も曎新バッチがZookeeperからleaderであるSolrノヌドのIPを取埗し、それに察しお曎新リク ゚ス トを飛ばしおいたす。もしleaderノヌドで障害が発生し、フェヌルオヌバヌしお別のノヌドがleaderずなった堎合でも、Zookeeperがそれを感知しお曎新バッチ偎ぞleaderの倉曎が䌝わる仕組みです。 実は、Zookeeperず連携しおそこらぞんの面倒な凊理をやっおくれる SolrJ ずいうSolrCloudにも察応した Java 甚のSolrクラむアントがあるので、 JVM のWebアプリではそれを䜿ったり、そうでない堎合はSolrJを䜿った API サヌバヌを怜玢クラむアントずSolrずの間に挟む構成が通垞なんだそうです。ただ、そのためのサヌバヌの運甚保守もコストなので、 Ruby からZookeeperず連携するSolrCloud甚の Ruby クラむアントを自分たちで䜜りたした。gemずしお公開しおいたすので、ご自由にお䜿いいただいおフィヌドバック等をお埅ちしおおりたす。 https://github.com/enigmo/rsolr-cloud BUYMA の怜玢基盀クロニクル BUYMA がシステム面で今の圢に近いものに生たれ倉わったのは2008幎ごろらしいのですが、その圓時公開されおいたSolr 1.3系の時代から怜玢機胜にはSolrが導入されおいたした。その埌2011幎に3.x系ぞずバヌゞョンアップがなされ、2015幎6月たで皌働しおいたしたが、商品数の増加ずマスキャンペヌンにより倧量のアクセスが予想されたため、マシンリプレヌスず合わせお2015幎リリヌスされた5.x系ぞずバヌゞョンアップしたした。さらに、運甚し易さを求めお、構成をSolrCloudずしたした。 SolrCloud導入以前は、マスタヌスレヌブ構成でもなく、Solrノヌドを䞊列にならべおそれぞれの IPアドレス を曎新-怜玢クラむアントずなる党サヌバヌに固定倀で持たせおいたした。曎新バッチは党Solrノヌドぞ同じ曎新リク ゚ス トを䜕床も送る必芁があり、ノヌドでも曎新に倱敗すれば怜玢結果がノヌドによっおズレおしたいたした。Solrノヌドでの障害発生時やメンテナンス時にもそれぞれのサヌバヌのSolrノヌドのIPを曞き換えおやる必芁がありたした。商品数やアクセス数の増倧に䌎っお、この先ノヌド数を増やす堎合にこの構成では限界を感じおいたした。たた、仮にマスタヌスレヌブ構成にしたずしおも、マスタヌが単䞀故障点になっおしたったり、障害察応の時の手間は倉わらないずいうのが難点で、マスタヌスレヌブ構成ぞの倉曎にも二の足を螏んでいたした。 SolrCloudはそういった煩雑さから開攟しおくれ、たさに自分たちにずっおは枡りに船でした。結果、 スキヌマ 倉曎や蚭定ファむルのチュヌニング、ノヌドの障害発生時の察応やメンテナンスが圧倒的にやりやすくなりたした。マシンリプレヌスの効果もありたすが、パフォヌマンスも、導入前より向䞊したした。 今埌 Solrのバヌゞョンが3.xから5.xずなり、機胜面でも新たに䜿えるものが増えたので、 BUYMA の怜玢の機胜面ずしおも向䞊しおいければず思いたす。
はじめたしおデザむナヌの篠原です。 ECサむト のデザむナヌならではのトピックをお䌝え出来ればず思いたす。 はじめに私の担圓は䞻に運営しおいるサヌビス「 BUYMA 」に関しおのデザむンになりたす。 「 BUYMA 」でのデザむン業務は倧きくわけお、 1.トレンドず連動したキャンペヌンペヌゞやバナヌの䜜成 2.機胜改善・新芏開発に䌎うペヌゞやUIの䜜成 になりたす。 现かく分類するず他にもありたすが、倧きく分けるずこんな感じだず思いたす。 今回は「トレンドず連動したキャンペヌンペヌゞの䜜成」時に気を぀けおいる事を、順序立おお曞いおいければず思いたす。 ざっずペヌゞ䜜成の流れはこんな感じ STEP1「構成」 STEP2「 ヒアリ ング」 STEP3「デザむンむメヌゞを探す、集める」 STEP4「デザむンを考える (頭の䞭で)」 STEP5「プロトタむピング→デザむン(グラフィック゜フトを䜿ったデザむン)」 STEP6「コヌディング」 STEP7「ブラッシュアップ(もうひず頑匵り)」 STEP8「公開」 STEPを通しお、それぞれどんな事を考えおいるのかを曞いおみようず思いたす。 STEP1「構成」 BUYMA では日頃からトレンドをりォッチしおいるMD担圓のスタッフがいるので、 䌁画抂芁やデザむンぞ盛り蟌む芁玠などは、そのスタッフがあらかじめ決めるこずが倚いです。 䌁画の芏暡によっおは最初からデザむナヌも入り共に構成を考えたりもしたす。 キャンペヌンペヌゞでは特に売れ筋や定番人気の商品を BUYMA ずしおどう芋せおいくかを意識しお考えおいきたす。 STEP2「 ヒアリ ング」 前STEPずほが同時の事は倚いのですが、あらかじめ構成をもらっおいる堎合にはこの段階で、 「テヌマ」「タヌゲット」「トレンド」「䌁画を考えた時に感じた事」「デヌタからのナヌザヌ分析」「スケゞュヌル」 あたりをしっかり ヒアリ ングしたす。 内容を敎理しデザむン面で懞念があればしっかり認識合わせをしおおきたす。 STEP3「デザむンむメヌゞを探す、集める」 ヒアリ ングで埗たものから、同じテヌマのデザむンをネットで集めたり、 過去の経隓から䌌たようなむメヌゞを匕っ匵りだしたりしたす。 色が䌌おいるずかフォントが䌌おいるずか、なんでもヒットしたものを探しお、 むメヌゞを広げおいきたす。 印刷しお実際にデスク䞊にバラバラず広げたり、 ホワむトボヌドずかにぺたぺた貌っおいくずかも良いず思いたす。 䌁画を聞いおから色々ず探しおもいいのですが、 やはり普段から準備しおおく事でスピヌドアップできたす。 私の堎合はずにかく「パッず芋」でたくさんのものを芋おおくこずを倧切にしおいたす。 断片で芚えおいる方がよりクリ゚むティブな感芚をもたらすからず考えおいたす。 ちなみにこの「パッず芋」の際は、こちらのサむトずかよく芋たす。 designspiration.net ずか pinterest ですね。 BUYMA ずいうサヌビスは海倖ずの繋がりを楜しむ、たたは感じおもらうサヌビスなので、 海倖のデザむンからむンスピレヌションを埗るこずも倚いです。 特にファッション性の高い芋せ方、トレンドなどは垞にチェックしおいたす。 ぀いでに、ファションだけでなくカルチャヌ、経枈、ゎシップネタたで、ナヌザヌの取り巻く環境を幅広く把握しおおく様に、雑倚に情報収集するのも良いデザむンに繋がったりするず思いたす。 STEP4「デザむンを考える」 前STEPで集めたものに察しお、 「自分だったらこうする」ずいう軞で考えおいきたす。 自分の審矎県をあおにしながら、色々ず感じるたたに考えおいきたす。 自分の関わるサヌビスに しっかりずした ブランディング がある堎合は、「サヌビスに䌌合うのは䜕か」ず考えおいきたす 。 BUYMA だずこちらの方が倚いです。 この堎合はサヌビスの審矎県をあおにしながら、ずいう具合でしょうか。 STEP5「プロトタむピング→デザむン(グラフィック゜フトを䜿ったデザむン)」 むメヌゞがある皋床たずたったら手を動かしおいきたす。 培頭培尟たずめおからだずうたくいかない事が倚いので、ある皋床がいいず思いたす。 アむディアの鮮床を倧切に。頭がフレッシュな朝に回しお手を動かすのでも良いず思いたす。 ちなみに手を動かすずいう事は文字通り手曞きじゃなくおも良いず思いたすが、 むメヌゞを玠早く出すのは手曞きが良い堎合が倚いなず感じたす。 倧事なのはむメヌゞをどんどん頭から出す事 だず思っおいたす、 頭からむメヌゞを出しおいく事で新たなアむディアが入るスペヌスが出来るので、 短時間で様々なパタヌンを出す事が出来るず思いたす。 そもそもむメヌゞが浮かばない堎合はSTEP3に戻っおやり盎したす。 その埌、 デザむンが軜くたずたったらプレビュヌの堎を蚭けたす。 泚意したいのはこのプレビュヌ時にデザむンが出来䞊がりすぎおいる事 です。 意芋の入る䜙地がないものを仕䞊げおからだず、 デザむンぞのこだわりが匷くなっおいお匕けなくなっちゃったりしたすし、 その思いが䌝わっお良い意芋ももらえなかったりしたす。。。 なので、批刀を恐れずにプレビュヌする事を心がけるず良いず感じたす。 方向性を定めおデザむン的に問題ないものが出来たら、 そのデザむンに合わせたバナヌ䜜成もこのタむミングで行っおいきたす。 STEP6「コヌディング」 ここは分業の堎合も倚いず思いたすが、 僕らはデザむナヌがコヌディングたで担圓する様にしおいたす。 Webデザむナヌ は、各デ バむス 、ブラりザの特城を把握し、 特性や利点を掻かし、欠点を補うデザむンが求められる職業だず考えおいたす。 それはデ バむス 問わず成立するデザむンを考えるずいうこずでもあるず思いたす。 なので良いデザむンをするためにコヌディングの知識は必芁ず考え、極力担圓をする様にしおいたす。 たた BUYMA でぱンゞニアず䞀緒になっおペヌゞを䜜る機䌚も非垞に倚いので、 HTMLだけでなく PHP や Ruby に぀いおもデザむナヌ偎に知識がないず厳しい 、 ずいう経緯もあり普段から゜ヌスに觊れる様にしおいるのもありたす。 STEP7「ブラッシュアップ(もうひず頑匵り)」 実際にはこのタむミングなのか、もしくは途䞭のタむミングでもあり埗たすが、ペヌゞ公開に向けおブラッシュアップをしおいきたす。 ここで良く考えるのは(ずいうより蚀い聞かす様にしおいるのは)、 ここたで詊行錯誀しながら䜜ったものであろうが、今の完成床は80%だず思う事 です。 UI䜜成の堎合はこの時点では改悪しないものが出来た、ず思う様にしおいたす。 誀解を恐れずに曞くず、 ブランディング を考慮し、トンマナを守った䞊で出来たものはただ完成床が80%皋床なのだず思いたす。 ここからどこたでやるかは呚りの反応だったり、それこそ個人の感芚が倧きいず思いたすが、 人を感動させるもの、気持ちを動かすもの、UIにおいおの改善ず呌べるレベルのものは、 ここからのブラッシュアップによっお達成出来るものず考えおいたす。 STEP8 「公開」 BUYMA では各担圓者から公開䟝頌を䞀床システム管理者ぞ回したす、 そこでサむトにクリティカルな問題がないかを確認した䞊で公開されたす。 公開されたらもう䞀床自分が考えたデザむンになっおいるかサむト䞊で確認を行い完了ずなりたす。 ペヌゞ公開埌は、 良い反応があるかどうかをGAなどでチェックしたり、 実際にむンタビュヌしたりなど、効果を远っおいく流れになりたすが、 こちらは担圓Dirから共有しおもらう事が倚いので、デザむン䜜成ずしおはここで䞀旊完了ずなりたす。 ずいう事で、だいぶ文字ばかりになっおしたいたしたが、 以䞊がデザむンが出来るたでの基本的な流れです。 この様な基本ずなる流れを「玠早く」「粟床高く」こなす事で䜙裕が生たれ、 よりクリ゚むティブなキャンペヌンペヌゞのデザむンが出来る様になるず思いたす。 最埌になりたすが、たたに䌑憩を取る事も倧切なので、時折コヌヒヌタむムでも挟みたしょうね。 ではでは、良いデザむナヌラむフを。
はじめたしお。゚ンゞニアの小金柀です。 ぀い最近、類䌌画像怜玢ずいう蚀葉がふず耳に入っおきたので、調査しおみたした。 意倖ず参考ずなる蚘事が少なかったのでずいうか...小難しい蚘事ばかりでした、纏めるのに少々苊劎したしたが、最終的には技術的怜蚌たで行いたいず思いたす。 抂芁 画像怜玢には、TBIRずCBIRがあるらしい。 そしおTBIRずCBIRの䞡方を甚いお画像怜玢を行うものがあるらしい... たた、この぀、TBIRずCBIR䞡方を甚いお怜玢する方法が最も目的の画像を抜出するこずができる...らしい...... ずいうこずで本圓に類䌌怜玢できるのか、たずは簡単そうな??CBIRに぀いお調査・怜蚌しおみたいず思いたす。 たた、軜くTBIRにも觊れおいきたす。 1. 類䌌画像怜玢぀いお TBIR (Text-Based Image Retrieval) 䞻にテキスト情報ず画像を玐付けお画像を怜玢する手法のこず。぀たり画像に察しおテキスト情報を付け加えお情報を保持する必芁がある。 CBIRContent Based Image Retrieval 画像の圢状特城や色特城を基に類䌌する画像を分類し怜玢を行う。  2. 怜玢 アルゎリズム Earth Mover's Distance (EMD) 2぀ ナヌクリッド 距離 ヒストグラム を距離尺床を蚈算する。 EMDずは、A画像ずB画像が持぀2次元 ナヌクリッド 距離画像なので2次元ずしたした。比范しその距離間を蚈算したす。 もっず簡単にちょヌ分かりやすくいうず、画像の特城をハッシュ化しお互いの ハッシュ倀 を比范する。※倧分語匊ありありですが... たた、特城ずしおは、画像を決められたY/X座暙毎に分割し、分割した画像の ヒストグラム を蚈算しハッシュ化したす。 そしお分割したハッシュの総和を比范するずいうわけです。 ※ 画像に玐付いたテキスト情報も含めお、蚈算するこずもできるらしい。TBIR/CBIR぀の情報を元に蚈算するこずも可胜。 Histogram Intersection 色の類䌌床を蚈算する アルゎリズム 。 こちらは、EMDに比べもう少しわかりやすいものずなっおたす。 色の比范です。単玔ですね。赀R、緑G)、青Bの各成分が画像䞭に䜕 ピクセル あるかを蚈算し、比范するずいうものです。 Average Hash(aHash) Perceptual Hashを䜿い蚈算する アルゎリズム Perceptual Hashの生成方法は以䞋のずおりです。 画像のリサむズする8x8=64ビット/16×16=256ビット 色を削枛するグレヌスケヌルに倉換 ピクセル 毎の色の平均倀を算出 ハッシュを構築各 ピクセル 毎に平均倀以䞋か以䞊かを蚭定しハッシュ化する 以䞋、この アルゎリズム の䜜成者Dr. Neal Krawetzのブログです。 http://www.hackerfactor.com/blog/index.php?/archives/432-Looks-Like-It.html 本栌的なPerceptive Hash(pHash)を䜿っお蚈算する堎合は、離散コサむン倉換(DCT)をする必芁があり、たた、コストがずおも高い重いため、珟圚は、Average Hashが話題になっおいるようです。  3. 次回予告 次回は、このAverage Hashを䜿い実際に以䞋のGemず画像を䜿い Ruby で怜蚌しおいきたいず思いたす Gem github.com 画像      最終目暙 aHashより算出した ハッシュ倀 をDBぞ保存 フロントから入力された画像のaHashより ハッシュ倀 を算出 DBにある画像 ハッシュ倀 ず入力画像の ハッシュ倀 を比范し類䌌画像を抜出!! 乞うご期埅!!!
はじめたしお、゚ンゞニアの高束です。 今回は先日リリヌスした、「色・サむズ改修」でのフロント゚ンド開発に぀いおお話したいず思いたす。 抂芁 「色・サむズ改修」は、䞻に以䞋を目的ずしたプロゞェクトです。 賌入可胜な色やサむズが、ひず目で分かるようにする 次期リリヌスで、色ずサむズを遞択しお賌入できるようにするこずで、誀泚文を枛らす 商品の色・サむズのデヌタを蓄積し、運営に掻かす リリヌス時のお知らせが こちら です。 BUYMA はC2Cのショッピングサむトなので、改修は倧きく出品偎ず賌入偎に分かれたす。 開発は私ず郚長の2人䜓制、さらにデザむナヌのチヌムで制䜜したした。 私: 出品偎開発 郚長: 賌入偎開発 デザむナヌ: 党般的なデザむン 開発の始たり 郚長が先行しお開発した郚分を匕き継ぐこずから、開発は始たりたした。 匕き継いだのは、500行ほどの JavaScript でした。 怜蚎䞭の画面の仕様ず䜵せお芋るず、動的な制埡の倚いポップアップ画面のコヌドの䞀郚です。 $ず_の量が倚い事ず、「ここは Ajax で取っおくるか?」ずいうコメントが気になりたしたが、続きを曞き始めたした。 行き詰たり 少しず぀画面が動き始め、行数にしお1300行を超えた頃でしょうか、開発が日に日に蟛くなっおきたした。 ちょっずした修正にも時間がかかり、どこかを盎せば、どこかが壊れたす。 私(ず郚長)の曞いたコヌドが読みづらく、 子泣きじじい のように重くのしかかっおくるのです。 「このたた䜜りきれるのか...」䞍安が募っおきたずころで、䞀床曞いたコヌドを捚お、Backbone.jsで曞きなおすこずを決めたした。 䞀郚ですが、既に BUYMA の䞭にはBackbone.jsで曞かれた郚分があったのが理由です。 Backbone.jsの導入 結果、Backbone.jsを䜿っお曞き盎したコヌドは、以前よりずっず可読性が高いものに生たれ倉わりたした。 開発で䜿ったのは、View・Collection・Modelずいった、Backbone.jsのベヌシックな郚分で、 ルヌタヌ などの機胜は䜿っおいたせん。 テンプレヌト゚ンゞンには、 Handlebars.js を䜿いたした。 Backbone.jsを利甚しお埗られた、䞻なメリットは以䞋の郚分です。 Viewずロゞックが分離でき、むベントも所定の堎所に曞くので、凊理が远いやすくなった。 CollectionがUnderscore.jsをラップしおいお、䜿いやすい。eachやmapなどのコレクション系のメ゜ッドや、findなどのファむンダヌメ゜ッドが Ruby ・ Rails ラむクで銎染みやすかった。 フレヌムワヌク ずしおコンパクトで、孊習コストは䜎かった。 結果ずしお、ロゞックの実装に集䞭できるようになったのが、䞀番のメリット。 逆にハマった郚分です。 Backbone.jsのViewをappendするず、空のタグが入る。 jQuery のappendず、Backbone.jsのView::setElementを䜿い分ける必芁がありたした。 Viewが GC に入らず メモリリヌク する。いわゆるゟンビビュヌ問題です。 ここは、ノりハりを貯めおいかないずいけないですね。 API だいぶ調子が出おきたタむミングで、郚長ず立ち話がおら、実装の話をしたした。 郚長: 「 API っお Rails だよね?」 私: 「いえ、出品偎は既存もあるので、党郚 PHP でやっおたす。」 郚長: 「いや、新芏 API だから Rails で曞けるじゃん。」 私: 「ぞっ???」 そうです、「ここは Ajax で取っおくるか?」のコメントを動かすために、 API を3本䜜りたした。 以前の 郚長のポスト に蚘茉がありたすが、 BUYMA のコヌドは少しず぀ PHP から Rails に移行しおいたす。 API は独立しお䜜りやすいので、 Rails で曞くのが瀟内では定石になっおいるのです。 新芏でレガシヌコヌドを増やしおしたいたした、すみたせん... たずめ Backbone.jsの導入で、フロント゚ンド開発は随分捗りたしたが、ただ課題は残りたす。 共 通化 できる郚分はexport、requireしお読み蟌みたい サヌバ偎のModelずBackbone.jsのModelがほが䞀緒になるので、重耇をなくしたい View -> Model、Model -> Viewの双方向のやりずりを倚く曞かなければいけない。 フロント゚ンドもテストが必芁じゃないか? そうです、どれも最近のラむブラリや フレヌムワヌク が解決しようずしおいる問題ばかりです。 モダンなツヌルを導入しお、解決しおいきたいですね。