Butterfly System TANTO CUSTOM L350 リモコンハーネスキット(H3用) ハイパーシルバーIII/SCマシニング (ウェッズスポーツ スベラーヌ黒

【送料無料】 215/70R16 16インチ BRANDLE ブランドル 562B 6.5J 6.50-16 DUNLOP ダンロップ グラントレック PT3 サマータイヤ ホイール4本セット,Butterfly System TANTO CUSTOM L350 リモコンハーネスキット(H3用) ハイパーシルバーIII/SCマシニング (ウェッズスポーツ スベラーヌ黒,【送料無料】 215/70R16 16インチ KOSEI コーセイ エアベルグ レバンナ 6.5J 6.50-16 DUNLOP ダンロップ グラントレック PT3 サマータイヤ ホイール4本セット

15インチ サマータイヤ セット【適応車種:ステラ(LA100系)】WEDS レオニス グレイラ アルファ ハイパーシルバー/ミラーカット 4.5Jx15ディレッツァ Z3 165/55R15,【SSR】 GTV03 (GTV03) 17インチ 7.0J PCD:100 穴数:5 inset:50 フラットブラック [ホイール1本単位] [H],トヨタ エスティマ 30,40系 18インチ アルミホイール 一台分(4本) LEONIS VT (レオニス ブイティー) BMCミラーカット アルミ,[ホイールのみ単品4本セット] ENKEI / all eight (BKC) 18インチ×7.5J PCD:100 穴数:5 インセット:48,エテルナ・エテルナサヴァ(87.8~89.9)E32AR/34AR■プロジェクトμ ブレーキパッド COMP-B for GYMKHANA フロント用左右セット,[ホイール1本(単品)] RAYS / BLACK FLEET V205C (KM) 20インチ×8.5J PCD:114.3 穴数:5 インセット:38,ハイエース 200系 リアアンダースポイラー/リアハーフスポイラー 1型/2型/3型前期/3型後期/4型 標準ボディ 素材色/ブラック,グレンツェン リアバンパー(フォグ有)[未塗装]BMW E89 Z4 [代引不可],ULTRA パワープラグコード インプレッサスポーツワゴン ターボ GF8 ブルーポイント 品番:2338-40,データシステム テレビ&ナビキット 切替タイプ TTN-43 JAN:4986651170131 トヨタ RUSH J200・210 2006年01月~2010年06月,アコード CB5 ディストリビューター リビルト 30100-PV0-016 キャップ&ローター付,右側(ホワイト) の リヤビュー の ミラー[一式] ■ 『写真No1のみ』 スズキ純正部品 スペーシア 4V MK32S適合年式[平成25年01月~]【品番】 84701-81M41-Z7T ^~38^,ミラー[一式] リヤビュー ライト(クローム) ■ 『写真No1のみ』 スズキ純正部品 キャリィ/エブリィ エブリイランデイ DA32W適合年式[平成13年05月~]【品番】 84701-66H00-0PG ^73^,◆◆【ハイクオリティー】Y51系フーガ ステンレスピラーヘアラインゴールド☆送料無料☆/ピラー/鏡面/ヘアライン/ニッサン/日産/車/車パーツ/ピラーパネル/ステンレス/高品質,Butterfly System TANTO CUSTOM L350 リモコンハーネスキット(H3用) ハイパーシルバーIII/SCマシニング (ウェッズスポーツ スベラーヌ黒,アウトバーン 広角ドレスアップサイドミラー(ドアミラー) BMW 7シリーズ E66 ロングボディ 01/10~09/02 ゴールド,KLC ルクラ L455F グレード:カスタム LXピラー 8ピース カラー:鏡面ブルー,エブリィバン DA62V LXピラー 8ピース カラー:鏡面ゴールド,セルボ HG21S LXピラー 8ピース カラー:鏡面ブラック,【USエヌファブ 直輸入正規品】 n-Fab シボレー 2500/3500 2015-2017年式 ライトマウント ツヤありブラック,パイプ エキゾースト ■ 『写真No2のみ』 スズキ純正部品 アルト(セダン、バン、ハッスル) バン HA25V適合年式[平成25年01月~]【品番】 14190-64L00 ^8^,245/35R20 ヨコハマ DNA エコス ES300 レオニスFY 20-8.5J 新品 サマータイヤ アルミホイール 4本セット YOKOHAMA DNA ECOS 【代引不可】【RCP】,235/60R18 BRIDGESTONE ブリヂストン REGNO GRV2 レグノ GRV-2 VENERDi MADELENA ヴェネルディ マデリーナ サマータイヤホイール4本セット,バッテリー デルタ N-V99 用 AYBXR-15D26-01×2 ストロングXシリーズ ピットワーク PITWORK ダイハツ DAIHATSU,【M's】ベンツ W140 Sクラス S600 600SEL R129 SLクラス 600SL SL600 V12 M120 ボッシュ製 BOSCH製 デスビキャップ ディスビキャップ(2個) デスビローター ディスローター(2個)セット新品,【受注生産】【アドミレイション/Admiration】 ワゴンR 等にお勧め アルタモーダ シートカバー LUXURY ラグジュアリー・ストライプ (ラムース×SSPU) 型式等:MC 品番:GSKS 112 F,【YZF-R1(1KB)】【グリップヒーター2 スポーツ120】【モーターサイクル用電源サブハーネスキット】セット【Q5KYSK063Y02+Q5KYSK063U01】【YAMAHA】【ワイズギア】,SAMCO サムコ ターボホースキット&ホースバンドキット インプレッサ GC8(STI Ver5~6) ブルー 青,☆Radiator・ラヂエーター・社外新品・代表車種名N BOX☆適合純正品番:19010-R9H-J01,ブレーキ パッド Projectμ(プロジェクトμ) TYPE HC-CS ブレーキパッド フロント MJ1 ジェミニ (リヤドラム MT車 93.9~),DIXCEL ディクセル Zタイプ 1台分前後セット トヨタ ビスタ SV21 88/8~90/7 [ブレーキパッド] Z311130 / Z315106,SUBARU レガシー 2000 93.10~96.6 BD5(RS-TURBO/GT-TURBO) プロジェクトミュー(Projectμ) ブレーキパッド TYPE HC-CS 前後セット [品番:F911/R910],プロジェクトμ ブレーキパッド HC-CS 1台分 カルディナ AZT241W 02/9~ プロジェクトミュー

プロジェクトμ ブレーキパッド HC-CS 1台分 レガシィ BEE(BLITZEN6含む) 02/1~03/9 プロジェクトミュー,ランドクルーザー プラド(90.4~)LJ71G/78G■プロジェクトμ ブレーキパッド B SPEC 前後セット【送料無料】

■DIXCEL(ディクセル) プレリュード インクス BA8 BA9 PRELUDE INX 91/9~96/10 フロント ブレーキパッド X タイプ,[ENDLESS] エンドレス Super Street M-sports (SSM) ブレーキパッド 前後セット 1台分 【ソアラ UZZ30 UZZ31 H4.4~H8.8 4000cc】 本州・北海道は送料無料 沖縄・離島は送料1000円(税別),[1450586] DIXCEL ES ブレーキパッド リヤ用 オペル ASTRA (XD系) XD180/XD180W/XD180K 1.8 16V 96~98,Dimotiv ディモーティヴ アジャスタブルショートレバー クラッチ タイプ3 エクステンションカラー:ダークグリーン ボディーカラー:チタン(アジャスターカラー:レッド) 3D 350 15-16,タナベ サステックプロ CRキット コンフォートR 車高調 クラウン GRS202 排気量:2994cc 08/02~ 12/12 FR NA 送料無料 代引無料,zoom/ズーム 230kgf/mm^2 ダウンフォースHG 1台分 日産/ニッサン/NISSAN ウイングロード NY12 HR15DE H17/11~ 4WD,Enjoy Mfg シートカバー Kawasaki カラー:すべて:グリーン/リブ:黒 KX65,Motor Rock 69シート カラー:Yellow & Green レザー:No.67 ステッチ:Type3 汎用,エントリーでポイント10倍 9/01 09:59まで 【送料無料】 155/55R14 14インチ BRIDGESTONE ブリヂストン レイナー BW25S 4.5J 4.50-14 FALKEN ファルケン ジークス ZE912 サマータイヤ ホイール4本セット フジコーポレーション,エントリーでポイント10倍 9/01 09:59まで 【送料無料】 235/45R18 18インチ TECHNOPIA テクノピア カシーナ XV-5 7.5J 7.50-18 GOODYEAR グッドイヤー EAGLE LS2(限定) サマータイヤ ホイール4本セット フジコーポレーション,カロ/KARO フロアマット SISAL 品番:2361 フォルクスワーゲン パサート 3C# ハンドル:右 FF・4WD フットレスト:有 2006年03月~2011年02月,KARO(カロ)KRONE(クローネ) ニッサン エクストレイル T30 H12/11~H19/08 フロアマット リアゲートのみ,WINMAX(ウインマックス)ブレーキパッド ARMA ストリート AT2 トヨタ クラウン LS130 フロント用,送料無料 アウトランダーPHEV GG2W PHILIPS製 2016正規品 車検対応 8000LM LEDヘッドライト Lo H7+180Wより明るい 12枚チップ搭載 60W LEDフォグランプ H11 高輝度 LEDセット 4P+L,Butterfly System TANTO CUSTOM L350 リモコンハーネスキット(H3用) ハイパーシルバーIII/SCマシニング (ウェッズスポーツ スベラーヌ黒,KARO(カロ)SISAL(シザル) トヨタ カローラ AE11# H09/04~H12/08 FF フロアマット,RS-R ローダウンサスペンション T083THD トヨタ ZVW30 プリウス(G ツーリングセレクション)用 ダウン量 F 15~10mm R 15~10mm 【3年間/5万キロのヘタリ保証付き】,Voomeran VW GOLF Touran 5Dr ALL 右ハンドル用 AT/DSG 11~ voomeran ドレスマット スポーツシリーズ センターフルセット 5枚 カラー:グリーン×ブラック,【1500円以上購入で300円OFFクーポン 8/18 10:00~8/23 9:59】 【送料無料(沖縄・離島を除く)】 ハイラックスサーフ 年式:H14~ フロアマット一式 プレミアム [カラー:レッド] 【天野: カー用品 内装パーツ フロアマット】【AMANO】,ベルサス ストラテジーア ヴォウジェ(VERSUS STRATAGIA VOUGE)ホイール4本の価格です。クロモイブリード(DR)【18inch×7.0 5H-114 INSET42】【送料無料】※別途納期有 【代引支払不可商品】,ZERO1000 オールインワンタイプHIDキット 固定タイプ,【USA在庫あり】 49-2012 300021 クロームワークス(Khrome Werks) 1インチハンドルバー 18インチ エイプ クローム

[ホイール1本(単品)] CRIMSON / CLUB LINEA L747D KING LABEL (BRC) 24インチ×10.5J PCD:130 穴数:5 インセット:11,Butterfly System TANTO CUSTOM L350 リモコンハーネスキット(H3用) ハイパーシルバーIII/SCマシニング (ウェッズスポーツ スベラーヌ黒,【メーカー直送品】無限 LEDフォグライト アタッチメント ステップワゴン SPADA RK6 _08V31-XLSB-K0S0

RIDEA アジャストクラッチレバー 本体:グリーン アジャスト:レッド YZF-R25 YZF-R25ABS,YZF-R1 イージーフィットバーセパレートハンドル EFFEX(エフェックス),NSR250(MC16) アルミ溶接ハンドル φ39垂れ角 5度 BATTLE FACTORY(バトルファクトリー),ターボチャージャー リビルト ワゴンR MH21S 13900-58JC0 交換キット付 送料無料,ターボチャージャー リビルト AZワゴン MJ21S 13900-58JA0 交換キット付 送料無料,ミシュラン パイロット スポーツ PS2 295/25ZR22 (97Y) XL,S-class W221 SPORTS LINE Black Bison Edition D.T.M SPORTS MUFFLER (OVAL120×2.)(~2009y),245/45R19 98Q DUNLOP ダンロップ WINTER MAXX 02 WM02 ウインターマックス 02 冬スタッドレスタイヤ単品1本価格《2本以上ご購入で送料無料》,Z750FX-1 79-80年 トリプルクランプ付フォークASSY KYB38&Type-2 フォークカラーシルバー×クランプカラーブラック PMC(ピーエムシー),09-07-2071 SP武川 ソリッドオイルクーラ?キット スリムラインホース ブラック フレームマウント モンキー/ゴリラ,【1500円以上購入で300円OFFクーポン 8/18 10:00~8/23 9:59】 【送料無料(沖縄・離島を除く)】 セルシオ 年式:H12~H18 型式:UCF30 フロアマット一式 チェック [カラー:ブラック×ピンク] 【天野: カー用品 内装パーツ フロアマット】【AMANO】,【送料無料】 Weds(ウェッズ) REVSPEC PRIMES(レブスペック プライム) 品番:PR-T038 フロント用 トヨタ セリカ ST202 SSIIノーマルサス '93/10~'97/12 Weds [ブレーキパッド 自動車]【RCP】,スバル インプレッサ スポーツワゴン 2000 00.08-02.10 GGA ADVICS(アドヴィックス) STREET SPEC ブレーキパッド リア用 [SS866-s],GS750 83/84年 COMPLETE GASKET SET(コンプリートガスケットセット) ATHENA(アテナ),K&H ケイアンドエイチ シート本体 スリムショートA ステッチ <セミオーダー> カラー:アイボリー2 カラー:ダークブラウン,【メーカー在庫あり】 30720 229-6250 トラスコ中山(株) TRUSCO アクメスクリューピッチゲージ 測定範囲2-20mm 12枚組,【メーカー在庫あり】 SMARK 361-3470 (株)ミツギロン ミツギロン スパークマーカー 203φ×100,【メーカー在庫あり】 WW840 767-3540 トラスコ中山(株) TRUSCO 手動ウインチ用ワイヤーΦ8×40M用(切りっ放し),SW-MOTECH: SUZUKI V-Strom 1000 ('01-'07) アルラック ブラック

2017-10-18

AD-TECH
Lab BLOG
RCO アドテクLab ブログ

Luigiでデータ処理をきれいに書こう

2017/14akiba

エンジニアの秋庭です。

本記事では、Pythonのバッチ処理フレームワークLuigiの紹介をしつつ、読みやすいデータ処理の実装について書いていきます。 さて 、本記事を書くに至った理由ですが、分析コードのリファクタリングに苦労した経験からです。具体的には、、

  • データ処理に必要なファイルや処理の依存関係がわからない
  • 分析用の自作クラスや関数の使い方がわかりづらい

などなどです。 上記のようなちょっと管理が難しいコードが生まれてしまうのは、「試験的な運用だから…」とか「2週間しか動かさないコードだから…」 とか大人の事情があったりする場合もありますが、とにかくコードがきれいなことに越したことはありません。

また、さまざまな開発ツールやフレームワークが提案されているWeb開発と比べて、分析コードの開発手法はまだまだ議論の余地があるように感じます。

今回ブログに載せるコードは、技術的に高度なものではありませんが、データ分析を始めたばかりの方、きれいなデータ処理を書きたいと思っている方に一読いただければ幸いです。

Butterfly System TANTO CUSTOM L350 リモコンハーネスキット(H3用)の本物を購入する

Butterfly System TANTO CUSTOM L350 リモコンハーネスキット(H3用)アウトレット店舗Luigiの紹介

Luigiは、Pythonのバッチ処理フレームワークです。 データ処理をTaskという単位で定義していき 今季新作!Butterfly System TANTO CUSTOM L350 リモコンハーネスキット(H3用)、依存関係の記述やワークフローの可視化などを行うことができます。 基本的に、Taskは以下のメソッドを実装します。

  • requires -> 依存Taskを記述
  • output -> 出力を記述
  • run -> 出力を作成するロジックを記述

outputメソッドがTrueを返すときは、runメソッドを実行しません。 outputメソッドがFalseを返すときは、runメソッドを実行して、出力を作成します。 このとき、requiresメソッドで依存TaskのoutputがFalseを返すときは、先に依存Taskのrunを実行します。

以降は、サンプルコードを見ながら、luigiによるデータ処理について説明していきます。 データ処理の流れとしては、

  • Step.1 S3から元データ取得
  • Step.2 ローカルで元データを加工
  • Step.3 加工したデータをS3へアップロード

というものです。

もちろん、これらのデータ処理はluigiなしでも実装できます。 例えば、以下のように個々の処理を書き下して、一個ずつ実行していきます。 このような方法だと、コードが複雑になるにつれ 最初のButterfly System TANTO CUSTOM L350 リモコンハーネスキット(H3用)、「process.pyを動かすまえに、get_s3.pyが必要だっけ?」とか、 「このファイルを実行すると、どこが変更されるのか…??」といった管理、運用上の問題が色々と発生しそうです。

$ python get_s3.py
$ python process.py
$ python upload_s3.py

次節以降では 、簡単な例からluigiを導入し、徐々にコードを改良していきます。

品質が保証!Butterfly System TANTO CUSTOM L350 リモコンハーネスキット(H3用)

まずは、Step.1 ~ Step.3をひとつのTaskに記述してしまいます。 プロジェクトのディレクトリ構造は以下です。

├─ luigi.cfg
├─ data
└─ tasks
   └─ run_luigi.py

各Taskに必要なパラメータはluigi.cfgに書きます。 YourFirstTaskで使用するファイルのロケーションなどをluigi.cfgの[YourFisrtTask]に記述しておきます。 また、luigi.s3.S3Client()を呼び出したときに、[s3]のパラメータを読み込んでくれます。

luigi.cfg

[YourFirstTask]
s3_source_path=s3://luigi.tutorial/path/data/user_scores.tsv
local_input_path=data/user_scores.tsv
local_processed_path=data/processed.tsv
s3_destination_path=s3://luigi.tutorial/path/results/processed.tsv
[s3]
host=s3-xx-xxxxx-1.amazonaws.com
calling_format=boto.s3.connection.OrdinaryCallingFormat
aws_access_key_id=XXXXXXXXXXXXXXX
aws_secret_access_key=XXXXXXXXXXXXXXXXX

tasks/run_luigi.py

import luigi
import luigi.s3
import lib
class YourFirstTask(luigi.Task):
 # 各パラメータはluigi.cfgで定義
 s3_client = luigi.s3.S3Client()
 s3_source_path = luigi.Parameter()
 local_input_path = luigi.Parameter()
 local_processed_path = luigi.Parameter()
 s3_destination_path = luigi.Parameter()
 def requires(self):
 return None
 def output(self):
 # このTaskの生成物を定義
 return luigi.s3.S3Target(path=self.s3_destination_path)
 def run(self):
 # 入力ファイルをS3からget
 self.s3_client.get(s3_path=self.s3_source_path,
 destination_local_path=self.local_input_path)
 # getしたファイルをローカルで加工
 with open(self.local_input_path, 'r') as fin, open(self.local_processed_path, 'w') as fout:
 for line in fin:
 user_id, x, y = line.rstrip('\n').split('\t')
 value = int(x) + int(y)
 fout.write('{user}{sep}{value}\n'.format(user=user_id,
 sep='\t',
 value=value))
 # 加工後のファイルをS3へupload
 self.s3_client.put(local_path=self.local_processed_path,
 destination_s3_path=self.s3_destination_path)
if __name__ == '__main__':
 luigi.run()

以下のように実行します。

python -m tasks.run_luigi YourFirstTask

このExampleでは、luigiのモジュールに従って、S3ファイルの操作を行っています。 ファイル操作などをluigiモジュールに統一することで、チームでの開発・運用の効率化に繋がりそうです。

一方で、run内に複数のロジックが記述されており、各Stepが分離されていません。 次節では、ひとつのStepにひとつのTaskを割り当てます。

Exampleその2

Exampleその2では、設定ファイルを以下のように変更します。

luigi.cfg

[GetFileFromS3]
s3_source_path=s3://luigi.tutorial/path/data/user_scores.tsv
local_input_path=data/user_scores.tsv
[ProcessLocalFile]
local_processed_path=data/processed.tsv
sep='\t'
[UploadFileToS3]
s3_destination_path=s3://luigi.tutorial/path/results/processed.tsv
[s3]
host=s3-xx-xxxxx-1.amazonaws.com
calling_format=boto.s3.connection.OrdinaryCallingFormat
aws_access_key_id=XXXXXXXXXXXXXXX
aws_secret_access_key=XXXXXXXXXXXXXXXXX

各Taskを実行するPythonファイルは以下です。 各Taskのrequiresとoutputによって、依存しているTaskと生成ファイルが明確になっています。

tasks/run_luigi.py

import luigi
import luigi.s3
import lib
class GetFileFromS3(luigi.Task):
 """
 s3 -> local
 """
 s3_client = luigi.s3.S3Client()
 s3_source_path = luigi.Parameter()
 local_input_path = luigi.Parameter()
 def requires(self):
 return None
 def output(self):
 return luigi.LocalTarget(path=self.local_input_path)
 def run(self):
 self.output().makedirs()
 # s3からファイルをget.
 self.s3_client.get(s3_path=self.s3_source_path,
 destination_local_path=self.local_input_path)
class ProcessLocalFile(luigi.Task):
 """
 local -> processed local
 """
 sep = luigi.Parameter(default='\t')
 local_processed_path = luigi.Parameter()
 def requires(self):
 return GetFileFromS3()
 def output(self):
 return luigi.LocalTarget(path=self.local_processed_path)
 def run(self):
 self.output().makedirs()
 # ファイル加工のロジックを記述.
 with self.input().open('r') as fin, self.output().open('w') as fout:
 for line in fin:
 user_id, x, y = line.rstrip('\n').split('\t')
 value = int(x) + int(y)
 fout.write('{user}{sep}{value}\n'.format(user=user_id,
 sep=self.sep,
 value=value))
class UploadFileToS3(luigi.Task):
 """
 processed local -> s3
 """
 s3_client = luigi.s3.S3Client()
 s3_destination_path = luigi.Parameter()
 def requires(self):
 return ProcessLocalFile()
 def output(self):
 return luigi.s3.S3Target(path=self.s3_destination_path)
 def run(self):
 # s3にファイルをupload.
 self.s3_client.put(local_path=self.input().path,
 destination_s3_path=self.s3_destination_path)
if __name__ == '__main__':
 luigi.run()

実行コマンドは以下です。

python -m tasks.run_luigi UploadFileToS3

Exampleその2では、ファイル操作と依存関係をフレームワークのお作法に従って記述することで 【大量揃っています】Butterfly System TANTO CUSTOM L350 リモコンハーネスキット(H3用)、データ処理の流れを明確にすることができました。 最後に、独自に実装したファイル加工の部分にテストコードを書いていきます。

Exampleその3

ProcessLocalFile内の、ロジック部分をメソッドで切り出し、テストを書きます。

├─ luigi.cfg
├─ lib
│   └─ __init__.py
├─ tasks
│   └─ run_luigi.py
└─ tests
  └─ test_sum_value.py

tasks/run_luigi.py

import luigi
import luigi.s3
import lib
...
 def run(self):
 self.output().makedirs()
 with self.input().open('r') as fin, self.output().open('w') as fout:
 for line in fin:
 user_id, x, y = line.rstrip('\n').split('\t')
 value = lib.add_values(x, y)
 fout.write('{user}{sep}{value}\n'.format(user=user_id,
 sep=self.sep,
 value=value)
...

lib/__init__.py

def add_values(x, y):
 return int(x) + int(y)

tests/test_sum_value.py

from unittest import TestCase
import lib
class TestSumValue(TestCase):
 def test_sum_value(self):
 expected = 5
 actual = lib.add_values(2, 3)
 self.assertEqual(expected, actual)

メソッドとして切り出して、メンテンスしやすいコードになりました。 今回書いたコードは、ロジックが簡単なものでしたが、”run内のロジックは単体テストを書く”というルールを共有できていれば、、 難解な実装を避けることができるはずです。 (単体テストがうまく書けなければ、ロジックの切り分けを考え直す)

まとめ

本記事では、サンプルコードを作成しながら、luigiを利用したデータ処理について見てきました。

記載したコードは簡単なものでしたが、より複雑な処理を行いたい場合は、 luigiで用意されているモジュールをカスタマイズすることも可能です。(自作したらテスト書く)

フレームワークを導入するというのは、一つの手段でしかありませんが、luigiを使って最初に記載した課題を解決することができました。

  • データ処理に必要なファイルや処理の依存関係がわからない

  → フレームワークに従って、、

、ファイル操作や依存関係を実装する

  • 分析用の自作クラスや関数の使い方がわかりづらい

  → 自前のロジックやカスタマイズしたモジュールにテストを書く

本記事はここまでです。お読みいただきありがとうございました。

{yahoojp}nc02-yyp01-gui-987