SPSS Modelerで装置故障分析

SPSS Modelerを使って、装置故障分析を行ってみます。

* 稼働確認環境
    * Modeler 18.6
    * Windows 11


* データ
 
https://github.com/hkwd/250401spsshandson/blob/master/250401EquipmentFailureAnalysis/250401EquipmentFailureAnalysisData.zip

* 完成ストリーム

https://github.com/hkwd/250401spsshandson/blob/master/250401EquipmentFailureAnalysis/250401%E8%A3%85%E7%BD%AE%E6%95%85%E9%9A%9C%E5%88%86%E6%9E%90.str

# A.データの入力
## A1. センサーデータを入力
`01過去装置センサーデータ.csv`というファイルをModelerのキャンバスにドラッグアンドドロップします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/c9b856b2-17c7-4b0b-a278-b3dae26b634e.png)


出力タブからテーブルノードを選択し、ドラッグアンドドロップした`01過去装置センサーデータ.csv`と接続します。
テーブルノードを選択状態にして、五角形に三角の「選択内容を実行」ボタンで実行します。


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/5b7a6913-d2d1-49f6-a532-36ce2c5489f8.png)



装置ID、稼働日数、温度、電力、油塗布のデータが入っています。装置ID毎に各稼働日のセンサーの情報が入っているイメージで、装置が変わると、稼働日はまた０から始まるデータになっています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/f8e9b7c0-9a6e-4ad8-9ad3-73da0cfa42fa.png)


確認し終わったら赤い×ボタンで閉じます。

## A2. 故障データを入力

同様に`02装置故障データ.csv`を配置します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/29bcecce-93ac-4e4c-b025-cd6c388db8c2.png)

`01過去装置センサーデータ.csv`とテーブルノードの間のリンクを右クリックで削除します。
![{0A86149E-D311-4F98-AC14-AB9C28EC89E6}.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/685f1164-46b4-457d-8d5a-bab762f49886.png)

`02装置故障データ.csv`とテーブルノードの間のリンクし、右クリックで実行します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/f23a2da3-05f7-468e-bd67-a1144692588b.png)

`02装置故障データ.csv`には、装置ID、稼働日数、そして故障したかどうかがT/Fのフラグで入っています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/01b95454-c209-4ac5-bc75-f7ae43c6b07c.png)

確認し終わったら赤い×ボタンで閉じます。

テーブルノードはここでは一旦、右クリックで削除しておきます。
![{88E3F437-E7C8-4E27-B13E-EE2F1B783A26}.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/f3330a04-d265-4cda-9742-ece923ae437e.png)


# B.データ加工
## B1. データ結合
「レコード設定」タブからレコード結合ノードを選び、キャンバスにドラッグアンドドロップします。
そして、`01過去装置センサーデータ.csv`と`02装置故障データ.csv`から接続します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/5ff196c7-b161-4258-a7c0-f687e2cd9fc8.png)

レコード結合ノードを右クリックして、「編集」を選びます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/faae79ef-3a99-48b7-a1eb-49f8f42709b5.png)

「レコード結合」タブで「レコード結合方法」で「キー」を選びます。そして、「装置ID」、「稼働日数」の順に`→`ボタンで結合キーを設定します。これで「プレビュー」ボタンをクリックしてください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/288ff28c-9e47-4d34-9718-3b154d4cb1ff.png)

二つのCSVが結合できたことがわかります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/4fa58283-f2ba-4fb5-acda-604a2bfe2acf.png)

## B2. 変数のロール設定
どの変数が説明変数でどの変数が目的変数かを設定します。

「フィールド設定」タブから「データ型」ノードを選び、キャンバスにドラッグアンドドロップします。
そして、「レコード結合」ノードから接続し、右クリックで「編集」を選びます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/a737a86e-e547-4fed-ae4b-782b9f49799d.png)

「値の読み込み」ボタンを押して、装置IDのロールを「なし」、故障のロールを「対象」に設定します。そして「OK」 で閉じます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/6d2af3b6-2c0a-4e3a-9cbb-c536babf04a0.png)

# C.データ探索
これで機械学習の準備はできましたが データの中身をあらかじめ確認して前処理やデータの探索をしておきたいと思います。

## C1. 欠損値の代入
「出力」タブから「データ検査」ノードを選び、キャンバスにドラッグアンドドロップします。
そして、「データ型」ノードから接続し、右クリックで「実行」をします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/915bcb2a-ae9d-483d-b244-16e24b1a6523.png)

「欠損値」のタブを開きます。外れ値やヌル値などが何件あるかが表示されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/9f737e10-da58-4546-bf7f-41f25cb283c2.png)

ここでは「温度」に2件のヌル値がありますので、欠損値の代入を行ってみます。
「温度」の欠損値の代入から「指定…」を選びます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/404d6f0d-af25-47ef-985d-12181065d29c.png)

「代入時」に「ヌル値」を選び、「代入方法」は「固定」のままにして、「固定」値として「平均値」を選びます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/3b40cd34-dcb6-451c-8225-1d3d01c0a35d.png)

「生成」メニューから「欠損値スーパーノード」を選びます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/2a0f83bb-1e39-436f-9280-6d09c4565c1e.png)

「OK]で進みます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/d446ffa4-a2f4-4437-8174-7c8143bfa1e9.png)

データ検査ノードを赤い×ボタンで閉じます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/f89b86f7-9168-4fed-ad73-597fb9ef7896.png)

欠損値の代入というスーパーノードができているのでこれを「レコード結合」ノードと「データ型」ノードの間にいれてつなぎなおします。
そして、右クリックで「ズームイン」を選びます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/152b1aa2-be46-4f68-99b9-15ec90e8c8e8.png)

「温度　個の置換」というノードができています。スーパーノードとは複数のノードをまとめるノードです。今回は「温度」のみの欠損値処理を行いましたが、他の変数も処理していれば、このスーパーノードの中に一緒に格納されます。
右クリックで「編集」を選びます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/b80fc4e5-9b5c-4ef2-9870-420fc4a958bb.png)


「温度」を平均値で置換する処理が自動的に作られているのがわかります。
「OK」で閉じます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/bdf74d3d-b927-432f-a78c-8d1329c1368f.png)

ちなみに欠損値の代入には「無作為」や「アルゴリズム」による予測補完メニューもありますし、[時系列データの線形補間](https://qiita.com/416nishimaki/items/196b0ebacbf93ac62984)も可能です。

キャンパスで右クリックして「ズームアウト」を選び、メインのストリームに戻ります。
![{DCBAB14B-D625-4126-8178-03EFB4FAEDC3}.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/32a28919-cf54-47e9-a969-84661bb0ddef.png)

再度、「データ検査」ノードを右クリックで「実行」をします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/41197972-7542-4065-932a-6902558d59f7.png)
「欠損値」のタブを開くと、「温度」のヌル値が0になったことがわかります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/1d66b3e1-befa-4091-a4ff-4d8b4f875949.png)



## C2. データの概要の把握
検査タブでは、平均値や最大値などの基本的な統計情報を確認することができます。
またサンプル グラフでは目的変数の「故障」で色分けをしてグラフを作成しています。「故障」のグラフをダブルクリックをしてください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/b7580de4-79b2-4158-b7bc-6db22557f7b1.png)

「故障」のグラフが拡大されます。
全体としては22.37％が故障だとわかります。
赤い×ボタンでグラフを閉じます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/b34e49d2-195b-492b-a384-0f977d20b6bf.png)
以下は「いいえ」で閉じます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/f71ad6a7-7322-4149-b6bf-0f5534ecf47a.png)


次に「稼働日数」のグラフをダブルクリックして拡大します。
稼働日数が進むと故障の割合が増えていくことがわかります。
赤い×ボタンでグラフを閉じます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/c1d3a288-ba39-441d-9456-e5fa242a11bb.png)
以下は「いいえ」で閉じます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/8756ef47-2a1b-49a7-9bf6-2fe28c5415e1.png)

「温度」のグラフをダブルクリックしてみます。温度が高いと故障が多いように見えます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/5fc288c1-6bce-4fe0-b365-47079508ba08.png)

詳しく調べてみます。
表示メニューからインタラクティブをチェックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/49139596-89fa-4f6d-815c-37e0a7c49ffd.png)

赤い縦棒のアイコンをクリックして、260度よりちょっと下の位置でクリックをします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/c7f8dba0-c7b7-433d-a70a-6f3457266980.png)

以下のように赤い区切り線がひかれました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/957a9acd-1f89-497d-88eb-db1f3f2dde45.png)

ここで、「生成」メニューから「バンドのフィールド作成ノード」を選びます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/1696d2f7-2077-4d8a-9e3a-6e80ec5a530e.png)

赤い×ボタンでグラフを閉じます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/9453add3-e768-4622-9810-07eda55fe16a.png)
以下は「いいえ」で閉じます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/218e4d88-4628-48a7-923e-44b6e09b4df0.png)
データ検査ノードを赤い×ボタンで閉じます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/e84df3e6-71c0-40c1-b674-3ff93418737e.png)

「バンド」というフィールド作成ノードができています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/dd147d09-6452-4938-abc9-c3326766cc43.png)

データ型ノードに、この「バンド」というノードをつなぎ、右クリックで「編集」を選びます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/3211248a-6916-42c1-87f1-170bea9d1988.png)

先ほどヒストグラムで引いた赤い区切り線の位置で「バンド１」と「バンド２」を分けるフラグが作られています。このようにグラフをみながらコーディングなしに、処理を作る事ができます。
ここではこの後の動きを合わせるために値の設定条件を`温度 < 255`に書き換えて、「OK」で閉じてください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/0875dc01-2f96-4c7f-bc2a-578a2c53ef21.png)

さらに「テーブル」ノードを接続し、右クリックで「実行」します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/c8610d50-3f8d-448c-95a3-1e70b61d3dc0.png)

温度が高い状態に絞り込みたいので、209行目の「バンド２」クリックして選択します。またここでは、分析上は意味がないのですが、複数の条件を指定できることを体験いただくために、別の行である200行目の油塗布の「F」をCTRLを押しながら選択します。そして、「生成」メニューから「条件抽出ノード(AND)」を選びます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/c494dee7-4cd3-4eb2-a4f3-4b424e388c33.png)

「（生成）」という条件抽出ノードがキャンバスにできていますので、「バンド」ノードに接続して、「編集」を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/318d5055-bc84-49e3-a6a4-b9a1ea73bb76.png)

テーブルノードで選んだ項目が`バンド = "バンド2" and 油塗布 = "F"`という条件式になって自動的に設定されています。
このようにデータの中から抽出したい項目を選べば、処理を作る事ができます。異なるレコードからも組合せを選べるので、画面に表示されていないレコードのパターンの条件式も作れます。
「OK」で閉じてください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/ddca34fa-e705-4db4-95c4-4d925c8a0e9f.png)

「グラフ作成」タブの中から 「棒グラフ」を選び、 「（生成）」のノードに接続をします。そして右クリックで「編集」をします
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/624b810a-6cb0-4b4a-b951-90ec8b797abd.png)

「フィールド」に「故障」を選び、「実行」します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/4612a45f-2c48-4ff7-a6af-71f2a638d2f0.png)

温度が255度以上で、かつ油塗布 = "F"という条件では故障の割合が「79.79%」となっています。全体では2割程度が故障でしたので、温度が255度以上で、かつ油塗布 = "F"という条件だと、かなり故障率が高まることがわかります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/9f71cbd7-473d-4f1e-a5c7-a9794d6d0382.png)


# D.決定木モデル作成
ここまでで、データの前準備や探索を行ってきました。次に機械学習のモデルを作っていきたいと思います。人間にも理解しやすく、予測だけではなく原因分析にも便利な決定木のモデルを作っていきます。

## D1. データの分割
データを学習データとテストデータに分けていきます。過学習を避けるために、モデルの作成には学習データのみを使い、テストデータは評価のために使います。

「フィールド設定」タブから「データ区分」ノードを選び、キャンバスにドラッグアンドドロップします。
そして、「データ型」ノードから接続し、右クリックで「編集」を選びます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/59b29731-ae4e-4958-8249-10584e694d13.png)

学習データとテストデータのサイズを80：20で入力して、「OK」で閉じます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/86a155a0-2dc1-4745-92bd-f08b7e4e12c6.png)

## D2. 決定木モデル作成

「モデル作成」タブから「CHAID」ノードを選び（右の方にスクロールすると見つかります）、キャンバスにドラッグアンドドロップします。
そして、「データ区分」ノードから接続し、右クリックで「実行」します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/3d255f43-d994-4098-afbb-9c5dac32d577.png)

CHAIDの黄色のアイコンのモデルナゲットが自動的に生成されます。右クリックで「編集」を選びます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/60454b25-c7dc-499c-ba12-942e59b920b1.png)

ビューアータブを開き、「度数情報を表とグラフで表示」のアイコンをクリックして決定木を表示します。
全体では故障は③22.019%です。それを④稼働日数で分けています。稼働日数が進むごとに赤いグラフが大きくなって、故障の割合が大きくなっていることがわかります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/983d5865-0d88-4be8-aee6-3af349af907f.png)

「稼働日数」が①58日から69日の間の故障率は②24.145％ですが、「温度」が③248度以下の場合と④252度より大きい場合、故障率が高いことがわかります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/67fe3302-74fa-422d-a5c6-52b06db1dbce.png)

このように複数要因の条件で、問題のルールが見えてくるので、要因分析には決定木が便利です。
また、CHAIDは多分岐の決定木です。同じ説明変数が条件を変えて何度も出てくるCARTのような2分岐の決定木アルゴリズム（例：稼働日数＞49　AND 稼働日数>58のように何度も「稼働日数」の条件がでてくる）よりも理解しやすい特徴があります。

## D2. モデルの精度確認

「出力」タブから「データ検査」ノードを選び、キャンバスにドラッグアンドドロップします。
そして、「CHAID」のモデルナゲットから接続し、右クリックで「編集」を選びます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/495dab36-2e00-4bf3-b677-b7aa666858ed.png)

「一致行列」にチェックをつけて、「実行」します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/1aad6d69-e990-45a0-a00d-3013dca5092e.png)

テストデータに対して94.85％の精度だったことがわかります。
赤い×ボタンで閉じます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/455e6bf8-8844-484f-8782-1bf4d2114d6f.png)

# E. スコアリング

良いモデルができたので、新しいセンサーデータをこのモデルでスコアリングを実行して、将来のエラーを判定してみます。


## E1. 装置ID1000のスコアリング
新しいセンサーデータの入っている`03新規装置センサーデータ1000.csv`をファイルから選び、キャンバスに置きます。
そして右クリックしプレビューで中身を確認します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/3652e9cd-92b5-47a8-bae1-cea78e3f20cc.png)

このファイルには装置ID1000のセンサーのデータだけがあります。「故障」の列はありません。
赤い×ボタンで閉じます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/b2f8dfa0-352d-46b2-a6f4-b8dc44c1d619.png)

このデータから「故障」を予測してみます。

モデルナゲットを右クリックしてコピーします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/3c83dded-d91a-4420-a0cb-76f66e3e890f.png)


キャンバスの何もないところで右クリックして、貼り付けします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/7bc36b4f-e04f-47ee-8a94-0307a05c2314.png)


貼り付けたモデルナゲットに`03新規装置センサーデータ1000.csv`から接続します。
さらに出力タブからテーブルノードを選び、キャンバスにドラッグアンドドロップします。
そして、モデルナゲットノードと接続します。
それからテーブルノードを右クリックして、「実行」します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/54a73bc3-d22a-437b-9af8-558d5434bc6e.png)

 

新たに`$R-故障`と`$RC-故障`の列が追加されています。
`$R-故障`が予測結果です。`$RC-故障`がその確度を示しています。`$R-故障`が`F`なので、この装置ID1000は故障しないと予測し、その確度は9割以上であると予測をしています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/b3bff6ed-5745-47a2-8490-7b091b96c3f3.png)

## E2. 装置ID111のスコアリング
別の装置のセンサーデータの入っている`03新規装置センサーデータ111.csv`をファイルから選び、キャンバスに置きます。そして右クリックしプレビューで中身を確認します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/056318c1-6ac3-4518-ad7f-0efa611d7fa7.png)

このファイルには装置ID111のセンサーのデータだけがあります。
赤い×ボタンで閉じます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/0a821f9f-41c2-40f2-be24-a445b24f9135.png)

`03新規装置センサーデータ1000.csv`からのモデルナゲットへのリンクをはずし、`03新規装置センサーデータ111.csv`からモデルナゲットに接続しなおします。
それからテーブルノードを右クリックして、「実行」します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/86e076f4-fc71-4544-8e1d-f0aabc512438.png)

この装置ID111は故障すると予測し、その確度は8割以上であると予測をしています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/90ef958d-7691-4c5c-8376-3bd37f618eff.png)

どういうルールで故障すると予測したのかを調べてみます。
モデルナゲットを右クリックして「編集」を選びます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/1910e5bb-aea4-4d76-be1d-9c294acc7d8a.png)


設定タブで「ルール識別子」にチェックをいれ、「プレビュー」します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/6b3089cc-f44f-4d71-9f6f-8ac953c70c8f.png)

新たに`$RI-故障`の列が追加されています。この「18」が決定木内のリーフIDを示しています。
赤い×ボタンで閉じます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/24c0860b-d828-4809-be4c-4e3140d47d8b.png)

ビューアータブを開き、「度数情報を表とグラフで表示」のアイコンをクリックして決定木を表示します。
③がノード18です。このリーフをルートからたどると、④「稼働日数」が58日から69日の間で、⑤「温度」が④252度より大きいので、⑥故障率8割以上と判定したことがわかります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/e738b374-4f94-4746-b8c1-f359d01bc9ae.png)

このように判別の根拠を調べることができます。

# 参考
#### SPSS Modelerによる製造系データの分析ハンズオン・コンテンツへのリンク #SPSS_Modeler - Qiita 

https://qiita.com/spssfun2017/items/383a8d1059d008ccfad0