---
# System prepended metadata

title: macro_analysis

---

# macro_analysis
## 試験種別の添削時間、1h辺りの添削工数 <br>（担当：藤井、王）
### 試験種別の添削時間、1h当りの添削工数(評価なし)，<br>試験種別の添削時間、1h辺り添削工数、換算時給(評価あり)

* 試験種別の添削時間、換算時給を算出、添削者別
	* ops,tgt等も利用
	* 添削者評価のデータの利用
		* こちら側でスキーマ定義を行い、汎用性を高める
		
    
> LibreOfficeマクロとwebマクロのデータ形式を揃える
> 
> 入力：それぞれのファイル
> 
> 出力のデータ構造
> 
> | カラム |  データ型 | 説明 |
> | -------- | -------- | -------- |
> | examiner_id     | string    | 添削者id |
> | exam_id     |  string  | 試験種id |
> | correction_time    | int | 添削時間（秒） |
> | correction_date | date | 添削日|
> | man_hour | float | 工数 |
        
* 必要な入力は↑のファイルと,スキーマ定義した添削者評価ファイル,工数対応表
出力はこれから考える

* 阿部さんとのやり取り


入力のデータ型は何か（dataframe or ファイル名(str) or list or others）
> 一番外側のインタフェースとしてはコマンドライン引数でファイルパスを指定する認識です。また、同時に科目、算出する粒度(大学単位, 試験種単位etc)といった必要なパラメータも入力としてコマンドライン引数に入れる必要があるかと思います。作成していく中で外部から入力として受け取っていたものに関してはパラメータとして適宜追加していくとよさそうです。

"1h当たりの添削工数" は試験種ごとに出すという認識で合っているか
> 基本は試験種別で出せると良いですが、さらに拡張して大学別、大学×年度別、科目別といった粒度でも出せる形にしていただきたいです。(外部からの入力で粒度を選択)

スキーマ定義した添削者評価ファイルのサンプルはあるか（なければ、データ構造のざっくりとした感じを知りたいです）
> 前回のmtgの議事録の総添削量試算の部分の添削者評価ファイルのスキーマ定義、添削者評価マスタと同様のものになるかと思います。

添削者評価スキーマ定義
| カラム |  データ型 | 説明 |
| -------- | -------- | -------- |
| examiner_id     | string    |　添削者id |
| evaluation_month |  int  | 添削者評価月 |
| examiner_evaluation_id |  int  | 添削者評価id |

添削者評価マスタ

| カラム |  データ型 | 説明 |
| -------- | -------- | -------- |
| examiner_evaluation_id |  int  | 添削者評価id |
| examiner_evaluation_name |  int  | 添削者評価 |
| basic_correction_fee |  int  | 基本添削料 |
> 内部的にデータをpandasで読み込んで処理をするか、csvモジュールでcsv.DcitReaderで読み込んでdataclass等を作成し処理をしていくかはお任せしますが、出来る限りソフトコーディングを行って汎用性を高めていただきたいです。特にmacro_analysis部分は今後分析の幅を広げる際に拡張していく余地があるので。
> また、それぞれの関数、classのインタフェースの設計が出来た段階で一度自分の方で確認しようと思うのでPRを出していただけると助かります。

* 松田さんとのやりとり

試験種id と試験種名の対応を *`macro_analysis`* フォルダでやろうと思っているのですが．．． 
> preprocessの段階でexam_nameを出力のデータに入れるようにします。(macro_analysisはあくまで整形後のデータの「分析」だけを行うのが望ましいと思うので) 

- input
    - preproccessed_path
    - examiner_evaluation_path

- output


| 返り値 | 想定される粒度 | Column 3 |
| -------- | -------- | -------- |
| 添削時間 | 大学, 試験種 ||
| (粒度)ごと添削工数| |
| (粒度)ごと時給 | |


- 粒度の定義
    - 科目>大学>年度>試験種(大問ごと) → preprocessに提案
    - 添削者
```
commandにて
$ (試験種) (添削者)
> 
(試験種)--添削者１
       --添削者2
       --...

$ (添削者) (試験種)
>
（添削者）-- 試験種1
        -- 試験種2
        -- ...
```

---

- コマンドライン引数の例
    `python analysis.py (arg1) (arg2) (arg3) (arg4) ...`
    `python analysis.py -in (arg1) (arg2) -o (arg3) (arg4)...`


```
python a.py arg1 arg2 arg3

import sys

arg1 = sys.argv[1]
arg2 = sys.argv[2]
arg3 = sys.argv[3]

print(type(arg1))
> str
```

## TODO
●mainの関数で コマンドライン引数を受け取るように対応
●受け取った順に例の構造を出力するような関数を用意
●Liveshare
●preprocessで粒度定義するか提案する

---

### 3/10 18:00~

##### TODO確認
- ~~mainの関数で コマンドライン引数を受け取るように対応~~
- ~~受け取った順に例の構造を出力するような関数を用意~~
- ~~Liveshare~~
- ~~preprocessで粒度定義するか提案する~~


##### examiner_idに対応する単価(unit)を`examiner_evaluation`のDataFrameから抜き出す
df=
|examiner_id| evaluation | unit |
| ---|---|---|
|N0......| A |3000|

~~##### for ループで回すなら.~~

##### DataFrameにめそっどがあるかも
- examiner_id列に一致する行インデックスを返すメソッド
--> queryメソッドが使えそうでした。TODO下部にメモを記します。

##### 換算時給の計算アルゴリズム
1. 添削者ごとに、1hごとの工数を出力するコマンドに, `-e`オプションを付けたら換算時給を出す
    `python analysis.py processed_web_macro_log.csv -g examiner_id -v "man_hour/(cor
rection_time/3600)" -e (examiner_evaluation file path)`

```
# ret_dict = {examiner_id: 工数/h, ...}
for key in ret_dict.keys():
    if (keyがexaminer_evaluationのexaminer_idと一致したら):
        ret_dict[key] *= (単価)
```

2. 複雑な場合,例えば(試験種id×添削者id)で換算時給を出す場合
-> 再帰処理を利用


- fujii/macro_analysisブランチからanalysis.pyをコピーする
`git pull`
`git checkout fujii/macro_analysis -- analysis.py`

## TODO
- 関数2つ(換算時給計算、~~添削者評価ファイル(dataframe)から単価を抽出作成~~ → dictに変換すればこの関数は不要では?
- コードレビュー(出来れば)

---
(3/12追記)

### 設計思想
- "添削者評価ファイル"に捉われない
- 本質は、structuralize関数で生成した辞書(ret_dictという変数名にしたやつ)に、追加の計算(四則演算任意指定可)をほどこす事
- "**追加の計算をほどこす**"こと(大事なことなので二回)
- 追加計算のもとになるファイル名、keywordの列名、値の列名を指定してもらい、追加計算をほどこす(**ファイルに2列しかない場合は指定なし**でいこう)
- よって、**以後は「添削者評価ファイル」→「追加ファイル」と言い換える**

### 実現するための方法2つ
1. (method-1) 現在のstructuralize関数で生成した辞書に対し、後から計算をほどこす(**前回のmtgで話した内容はこちらです**)
2. (method-2) macro preprocessed dataから読み込んだdataframeと、追加ファイルから読み込んだデータを結合する(結合することで、`-v`の後に計算式を書くだけでよくなるので、より抽象的で良いです)

---

#### method-1
**手順1,2のコーディングをお願いします！！**
0. stracturalize関数(返り値`ret_dict`)の**後**にコーディング
1. `--add (added file path) [(keyword column name) (value column name)] []内は任意`で与えられた引数1つないし3つを利用してデータを読み取る
    ```
    df_added = pd.read_csv(cmd_args.additional_calculation[0])
    if cmd_args.additional_calculation is None:
        dict_added = dict(df_added.values)
    else:
        keyword_colname = cmd_args.additional_calculation[1]
        value_colname   = cmd_args.additional_calculation[2]
        dict_added = dict(df_added[[(keyword column name), (value column name)]].values)
    ```
2. 計算用関数を作る
    - 入力：ret_dic, dict_added, value=0
    - 出力：dict
    
    ```
    def additional_calculation(dic, dict_added, value=0) -> dict:
        for key in ret_dict.keys():
            if key in dict_added:
                value = dict_added[key]
            if type(dic[key]) == dict:
                additional_calculation(dic[key], dict_added, value=value)
            else:
                dic[key] *= value # 四則演算子をハードコーディングするのがmethod-1の弱点
        return dic
    ```
    前回画面共有しながら適当に書いたやつとほぼ同じです。
    - `if key in dict_added`が一生trueにならなかったら?
    - `else`でdic[key]がstringとか文字列だったら?

    など想定出来る例外がいくつかあると思うので、いくつか動作テストまでお願いします。プログラムの使い方は別途ドキュメントにまとめるので、必ずしも全てのエラーをキャッチする必要はありません。

以上

---

#### method-2
**こんな感じのアルゴリズムも思いつきました。**
**こちらの場合も手順1,2のみ。stracturalize関数を呼ぶ前に処理することに注意です**

0. stracturalize関数を**呼ぶ前**に処理しちゃいます
1. method-1の手順1.と同じことをする(dict_added)
2. macro preprocessed data(以降data)のdataframeと統合
    - 以下の手順でdataに追加
        ```
        ds = []
        keyword = (df_addedの1列目の列名) or (cmd_args.additional_calculation[1])
        for key in data[keyword]: # ここがmethod-2の弱み. dataとdf_addedが全く同じkeywordを持っていないとだめ.
            ds.append(dict_added[key])
        data["added"] = pd.Series(ds) # addedって名前の列名で固定してるの、ほんとは嫌です
        ```
以上


ざっくり考えたので、動くかどうか分かりません。
特にmethod-2は抽象化を考えてさっき思いついたので、よく分からないと思います。ので、まずはmethod-1から取り掛かってください！method-1で多分十分です。

---
