【Python３】第３回 タイタニックを標準モジュールだけで集計してみた。　～リスト集計編①～

#概要#
**某データ分析会社による一流のデータサイエンティストを養成するのためのPython研修タイタニック編**
　
　**　<font color="LightSeaGreen">
オッス！！！！！
オラ@74kenshiro！
いやー最近ずっとぺぇそん（Python）の勉強してるんだけんどよぉ。
なかなかみんなについてけねぇんだ。
壁にはまるとエラーばっかりだしオラもう限界だぞぉ！
まっ！そんなこと言ってもどうにもなんねぇから今日もいっちょやるかっ！！**</font>

**タイタニックのトレインデータをPython３標準モジュールで読込み、加工集計、CSVに出力してみた。
の皆さんお待ちかね第３弾です。**


**目次
１．行数の出力（ヘッダー除く）
２．列数の出力
３．先頭５行の出力（ヘッダー含む） CSVファイルに出力
４．末尾５行の出力（ヘッダー含む） TSVファイルに出力
５．各列の欠損している個数と欠損率（％表記、小数点第２位まで）をCSVファイルに出力
６．id, sibsp, parch, family 列のみのリスト「families」を作成し、そのリストの10~100行をCSVファイルに出力（ヘッダー含む）**
##この記事で分かること##
**<font color="Red">pandas</font>を使わずに、<font color="Red">標準モジュール</font>での**
**・リストの要素数を知る方法
・二次元リストの要素同士を演算する方法
・リストの一部をCSVに出力する方法
・家族とタイタニック観た時の気まずい空気を圧倒的に打破する方法**

##データ概要
**SIGNATE**
【練習問題】タイタニックの生存予測
https://signate.jp/competitions/102/data
トレインデータ（TSV）
**《データ説明》**

|カラム|ヘッダ名称|データ型|説明|
|-----|----------|-------|----|
0|id|int|インデックスとして使用
1|survived|boolean|生還結果（1=生還, 0=死亡）
2|pclass|int|客室のクラス（1,2,3の順に高級クラス）
3|sex|char|性別
4|age|int|年齢
5|sibsp|int|乗船していた兄弟、配偶者の数
6|parch|int|乗船していた両親、子供の数
7|fare|float|運賃
8|embarked|char|乗船した港（S=Southampton, C=Cherbourg, Q=Queenstown）

**《データ一部抜粋》**
各要素に一部欠損値有り
（下記一部抜粋）
![image.png](https://qiita-image-store.s3.amazonaws.com/0/340189/0b286d7c-84d9-04d2-90ff-94972d05b922.png)


**前回作成した二次元リスト「list01new」を元にする。
中身は列名（ヘッダー）も含めた各行のリストとなっている。**

**前回作成した「list01new」**

```python:list01new：TSVデータを読込み、欠損値をNoneに置換したリスト
list01 = []
list01new = []
# 1.データの読み込み
# 改行\nとタブ区切り\tを削除する
with open("train.tsv", mode="r") as f:
    for line in f:
        list01.append(line.rstrip('\n').split('\t'))
# 2．欠損値をNoneに置換する
# 「''」の場合は「None」、それ以外はそのままとし、list01newにappendする。
for line in list01:
    new_line = []
    for value in line:
        if value == '':
            value_after = None
        else:
            value_after = value
        new_line.append(value_after)
    list01new.append(new_line)

pprint.pprint(list01new[0:3])

print('--------' * 10)
none_list = [row for row in list01none if None in row]
pprint.pprint(none_list[7:9])
```

**OUTPUT：「list01new」の中身** 

```
[['id','survived','pclass','sex','age','sibsp','parch','fare','embarked'],
 ['3', '1', '1', 'female', '35', '1', '0', '53.1', 'S'],
 ['4', '0', '3', 'male', '35', '0', '0', '8.05', 'S']]
 --------------------------------------------------------------------------------
[['47', '1', '3', 'female', None, '0', '0', '7.75', 'Q'],
['61', '1', '1', 'female', '38', '0', '0', '80', None]]
```

##１．行数の出力（ヘッダー除く）
###１．リストの要素数を出力する場合は　<font color="Blue">len()</font>関数を使う。

**print(<font color="Blue">len(リスト)</font>)   ➡　リストの要素数**

**今回の場合、１行目のヘッダーを除くので、インデックスを１番目以降と指定する。**

```python:ヘッダーを除いた行数の出力
#　ヘッダーを除いた行数の出力
print(len(list01new[1:]))
=> 445
```
```python:インデックス指定の例
data = ['A','B','C','D']
print(data[:2])
  => ['A','B']
print(data[2:])
  => ['C','D']
print(data[1:2])
  => ['B']

```



##２．列数の出力
###１．これも同様に<font color="Blue">len()</font>関数だが、列数なので、ヘッダーの要素の数となる。

**<font color="Blue">len()</font>関数に「list01new」のインデックスにヘッダーをを指定する。**

```python:列数の出力

print(len(list01new[0]))
  => 9
```
##３．先頭５行の出力（ヘッダー含む） CSVファイルに出力

**CSV出力でも同じように、インデックスの指定で事足りる。
先頭５行　➡　リスト[:5]**

```python
with open(r"list01new_head5.csv", "w") as f:
    for row in list01new[:5]:
        print(*row, sep=',', file=f)
```
**OUTPUT Excelで確認。無事出力出来た。** 
![image.png](https://qiita-image-store.s3.amazonaws.com/0/340189/84330d4b-3dc9-3e30-e729-7ef0861b1e72.png)

##４．末尾５行の出力（ヘッダー含む） TSVファイルに出力
**ヘッダーの出力と、末尾４行の出力を分ける。
TSVファイルへの出力はタブ区切りなので、「sep='\t'」となる。**

```:区切りによるコードの違い
CSV出力　→「sep=','」
TSV出力　→「sep='\t'」
```

```python:末尾５行の出力（ヘッダー）含むtsvファイルに出力
with open(r"list01new_end5.tsv", "w") as f:
    # 0行目のヘッダーのみ書き込み。
    print(*list01new[0], sep='\t', file=f)
    # 末尾から4行を指定して書き込み。
    for row in list01new[-4:]:
        print(*row, sep='\t', file=f)
```
**OUTPUT サクラエディタで確認。　無事出力出来た。**　
![image.png](https://qiita-image-store.s3.amazonaws.com/0/340189/62f5409c-9ec1-c5f4-b47b-13773573908b.png)


##５．各列の欠損している個数と欠損率（％表記、小数点第２位まで）をCSVファイルに出力
###１．列ごとに計算する必要があるので、前回作成した辞書「dict01B」を使用する。

**《前回作成した「dict01B」のおさらい》
各列ごとの値のリストを作成し、<font color="Blue">dict(zip())</font>で辞書にする。**

```python:１.各列の値のリストを作成
#　値のリスト
list01value = []
for i,key in enumerate(list01new[0]):
    line_list = []
    for j,value in enumerate(list01new[1:]):
        a = list01new[1:][j][i]
        line_list.append(a)
    list01value.append(line_list)
pprint.pprint(list01value)
=>
[
['3','4','7','9',,,,
['1','0','0','1',,,,
['1','3','3','2',,,,
['female','male','male','female',,,,
['35','35','2','14',,,,
['1','0','3','1',,,,
['0','0','1','0',,,,
['53.1','8.05','21.075','30.0708',,,,
['S','S','S','C',,,,
]
```
```python:２．dict(zip()で辞書「dict01B」を作成
dict01B = dict(zip(list01[0],list01value))
print(dict01B)
=>
{'age':['35','35','2','14',,,,],
 'embarked': ['S','S','S','C',,,,],
 'fare': ['53.1','8.05','21.075','30.0708',,,,],
 'id': ['3','4','7','9',,,,],
 'parch': ['0','0','1','0',,,,],
 'pclass': ['1','3','3','2',,,,],
 'sex': ['female','male','male','female',,,,],
 'sibsp': ['1','0','3','1',,,,],
 'survived': ['1','0','0','1',,,,]}
```
**ーおさらい以上ー**
###２．辞書「dict01B」を使い欠損率を計算したリストを作成 ➡「list01deficit」


```python:各列の欠損している個数と欠損率（％表記、小数点第２位まで）のリスト「list01deficit」を作成
list01deficit = []
for i,line in dict01B.items():
    # kazu = 各列ごとのNoneの数をカウント
    kazu = line.count(None)
    # ritu = Noneの総数を要素数で割り、100を掛け、roundで小数点第３位を四捨五入
    ritu = round((kazu/len(line)*100),2)
    line2 = [i,kazu,str(ritu)+'%']
    list01deficit.append(line2)
list01deficit.insert(0,['列名','欠損数','欠損率'])
pprint.pprint(list01deficit)
=>
[['列名', '欠損数', '欠損率'],
 ['id', 0, '0.0%'],
 ['survived', 0, '0.0%'],
 ['pclass', 0, '0.0%'],
 ['sex', 0, '0.0%'],
 ['age', 85, '19.1%'],
 ['sibsp', 0, '0.0%'],
 ['parch', 0, '0.0%'],
 ['fare', 0, '0.0%'],
 ['embarked', 2, '0.45%']]
```
###３．作成した「list01deficit」をCSVに出力
```python:作成した「list01deficit」をCSVに出力
with open(r"list01deficit.csv", "w") as f:
    for row in list01deficit:
        print(*row, sep=',', file=f)
```
**OUTPUT　Excelで確認。無事出力出来た。**
![image.png](https://qiita-image-store.s3.amazonaws.com/0/340189/b0797a12-6a28-4882-2b55-79e9631b1247.png)

##６．id, sibsp, parch, family 列のみのリスト「families」を作成し、そのリストの10~100行をCSVファイルに出力（ヘッダー含む）
**※familyはSibSp, Parchの和である。**
**今回は、各列の個別のリストを作成し、<font color="Blue">for</font>文と<font color="Blue">zip() </font>関数で新たなリスト「families」を作成する**
###１．id, sibsp, parch,の各個別のリストを作成
**《二次元リストから、列ごとにリストを作成するコードの例》**

```python:例：二次元ループで2番目（C）の列のみリスト化する
>>> data = [
... ['A','B','C','D'],
... ['1','2','3','4'],
... ['5','6','7','8']]

retsu = []
for line in data:
    a=[]
    for line2 in line:
        a.append(line2)
    retsu.append(a[2]) # このインデックスで指定する。
print(retsu)

=> ['C', '3', '7']
```
**「list01new」の0番目の列「id」をリスト化してみる。**

```python:二次元ループで0番目のidのみリスト化する
id = []
for line in list01new:
    a = []
    for line2 in line:
        a.append(line2)
    id.append(a[0])
print(id)
=>
['id', '3', '4', '7', '9', '11',,,,]

```
**インデックスを変更してsibsp, parchも同様に作成する。**

```python:結果こういう形となる

id = ['id', '3', '4', '7', '9', '11',,,,]
sibsp = ['sibsp', '1', '0', '3', '1', '0',,,,]
parch = ['parch', '0', '0', '1', '0', '0',,,,]
```
###２．家族人数のリスト「family」を作成
**「family ＝ sibsp + parch」
要素同士の足し算となる。
今回は一つの二次元リストから作成するやり方と、二つのリストから作成するやり方を紹介します。**

```python:二次元リストの要素同士の足し算の例（各1番目(b)と2番目(c)の和）
data = [['a','b','c'],[0,1,2],[3,4,5],[6,7,8],[9,10,11]]
data_sum = []
for line in data[1:]:
    data_sum.append((line[1])+int(line[2]))
data_sum.insert(0,'bc_sum')
print(data_sum)
=>
['bc_sum', 3, 9, 15, 21]

```
**上記のやり方を元にリスト「list01new」から作るコード**

```python:家族人数のリストを作成（元のリスト「list01new」から作るコード）
family = []
for line in list01new[1:]:
    family.append(int(line[5])+int(line[6]))
family.insert(0,'family')
print(family)
=>
['family', 1, 0, 4, 1, 0,,,,,,]
```
**二つのリスト「sibsp」と「parch」から作る場合**
**①enumerateでインデックスを引きだし、同じインデックスの要素を足していくコード**

```python:①enumerateでインデックスを引きだし、同じインデックスの要素を足していくコード
dataA = ['a',0,1,2]
dataB = ['b',3,4,5]
AB_sum = []
for i,line in enumerate(dataA[1:]):
    AB_sum.append(int(line)+int(dataB[i+1]))
AB_sum.insert(0,'sum')
print(AB_sum)
=>
['sum', 3, 5, 7]
```
**上記のやり方を元に二つのリスト「sibsp」と「parch」から作る場合**

```python:家族人数のリストを作成（二つのリスト「sibsp」と「parch」）から作るコード）
family = []
for i,line in enumerate(sibsp[1:]):
    family.append(int(line)+int(parch[i+1]))
family.insert(0,'family')
print(family)
=>
['family', 1, 0, 4, 1, 0,,,,,,]
```
**②<font color="Blue">zip()</font>で一行ずつ抽出して作成しても可**

```python:②zip()</font>で一行ずつ抽出して作成する例
dataA = ['a',0,1,2]
dataB = ['b',3,4,5]
AB_sum = []
for a,b in zip(dataA[1:],dataB[1:]):
    AB_sum.append(int(a)+int(b))
AB_sum.insert(0,'sum')
print(AB_sum)
=>
['sum', 3, 5, 7]
```


###３．４つのリストを合体させる。➡「families」
**id, sibsp, parch, familyのリストが完成したので、0番目を列名、１番目以降を値のリストとなるようにする。**

```python:zip()でそれぞれ一行ずつappendする
families = []
for a,b,c,d in zip(id,sibsp,parch,family):
    families.append([a,b,c,d])
print(families)
=>
[
['id', 'sibsp', 'parch', 'family'],
 ['3', '1', '0', 1], 
['4', '0', '0', 0], 
['7', '3', '1', 4],
['9', '1', '0', 1],
,,,,,,
]
```
###４．10~100行をCSVファイルに出力（ヘッダー含む）
**最初に「families」のヘッダー（列名）のみ書き込み、以降10～100行目を書き込む。**

```python
with open(r"families.csv", "w") as f:
    print(*families[0],sep=',',file = f)
    for row in families[10:100]:
            print(*row,sep=',',file = f)
```
**OUTPUT　Excelで確認。無事出力出来た。**
![image.png](https://qiita-image-store.s3.amazonaws.com/0/340189/0edde1ff-9594-4760-c612-3c6aa8226f6b.png)


##最後に
**　<font color="LightSeaGreen">この記事がイイと思ったら、イイね、フォロー頼むぞ！！！
コメントもじゃんじゃんくれよな！
この調子でぺぇそん（<font color="DarkCyan">Python</font>）完全マスターすっぞ！！
これからもオラに知識とモチベを分けてくれ！！**

**<font color="LightSeaGreen">次回「ついに現れた初見殺し<font color="Red">関数の定義</font>！」
なんだか難しそうなやつでオラわくわくすっぞぉ！！
来週もぜってー読んでくれよな！！！！！**



**【お詫び】
今回、スペースの都合でお伝え出来なかった
・家族とタイタニック観た時の気まずい空気を圧倒的に打破する方法
は次回に繰り越しとさせて頂きます。
誠に申し訳ありませんが、皆様のご理解、ご協力のほど宜しくお願い致します。**