こんな人にオススメ
行の数が異なる、複数列を持ったcsvファイルをpandas
で読み込んだんだけど、データフレームに勝手にNaN
が入ってる。
特に支障はないけど、いつもNaN
があるからなんか気持ち悪い。どうにかして表示だけでも消せない?
ということで、今回は形の歪なcsvファイルを読み込んだときに発生するNaN
を削除する方法について解説する。今回は以下のような歪なデータを使用する。
列0 | 列1 | 列2 | 列3 |
date | 2021/9/14 | 1 | 1.5 |
time | 13:50:12 | 2 | 2.7 |
tool | A device | 3 | 3.8 |
11 | 11.3 | ||
10 | 10.4 | ||
9 | 10 | ||
8 | 8.5 | ||
7 | 7 | ||
6 | 6.7 | ||
5 | 5.9 | ||
4 | 4.7 |
初めの0, 1列分は取得データが存在、日付と取得データ名が書かれているが、その下は空白となっている。2, 3列目でようやくデータがある。
このデータをシンプルにpandas
で読み込むとNaN
が発生してしまって見た目が悪い。もちろんあってもなくてもそれは個人・したいことの勝手。
python環境は以下。
- Python 3.9.6
- pandas 1.3.1
作成したコード全文
csvを読み込んでデータフレームを作成
import pandas as pd print(' - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -') # データの読み込み file = 'data_file.csv' names = ['items', 'values', 'x', 'y'] # ヘッダ名 df = pd.read_csv(file, names=names) print(df) # items values x y # 0 date 2021/9/14 1 1.5 # 1 time 13:50:12 2 2.7 # 2 tool A device 3 3.8 # 3 NaN NaN 4 4.7 # 4 NaN NaN 5 5.9 # 5 NaN NaN 6 6.7 # 6 NaN NaN 7 7.0 # 7 NaN NaN 8 8.5 # 8 NaN NaN 9 10.0 # 9 NaN NaN 10 10.4 # 10 NaN NaN 11 11.3
まずはcsvファイルを読み込む。今回のデータではヘッダ名が設定されていないので、こっちで勝手にヘッダ名を決めた。ヘッダ名は引数names
で行える。
read_csv
で無事にデータを読み込むことができたが、ここで本記事の問題に直面する。それは、items, values列の3行目以降がNaN
であるということ。
今回はこれを解決する。
データフレームをcsvへ書き込み
x, y = df['x'], df['y'] df['y2'] = y * 2 print(df) # items values x y y2 # 0 date 2021/9/14 1 1.5 3.0 # 1 time 13:50:12 2 2.7 5.4 # 2 tool A device 3 3.8 7.6 # 3 NaN NaN 4 4.7 9.4 # 4 NaN NaN 5 5.9 11.8 # 5 NaN NaN 6 6.7 13.4 # 6 NaN NaN 7 7.0 14.0 # 7 NaN NaN 8 8.5 17.0 # 8 NaN NaN 9 10.0 20.0 # 9 NaN NaN 10 10.4 20.8 # 10 NaN NaN 11 11.3 22.6
とその前に、そもそも再度csvへと書き込んだ時にはどうなるのかを見ておく。別データということを確認しやすいように、データを追加しておく。
csv上ではNaNはないように見える
new_file = file.replace('.', '_new.') # ファイル名を変更 # df.to_csv(new_file, index=False)
データフレームを新しいcsvファイルへと書き込んで、実際にその出力を見てみると、NaN
の文字はなく何も入っていないということが確認できる。
ジャンプで空に行ってもない
なお、ちゃんと空になっているのかを確認するために楽な方法にはジャンプ機能という機能を使用する。これはmacの場合だと「ctrl g」で可能。多分Windousもこれ。
ジャンプで「セル選択」に進み「空白」の欄を選択して確定すると、囲った範囲で空白になっているセルのみを選択することができる。
実際に選択した時の状態が上の画像で、ちゃんと空になっていることがわかる。なお、スペースが入っている場合は空白としてみなされないので注意。
df
からNaN
を消すにはfillna
df_nonan = df.fillna('') # NaNを空と比較 print(df_nonan) # items values x y y2 # 0 date 2021/9/14 1 1.5 3.0 # 1 time 13:50:12 2 2.7 5.4 # 2 tool A device 3 3.8 7.6 # 3 4 4.7 9.4 # 4 5 5.9 11.8 # 5 6 6.7 13.4 # 6 7 7.0 14.0 # 7 8 8.5 17.0 # 8 9 10.0 20.0 # 9 10 10.4 20.8 # 10 11 11.3 22.6
csvファイル上ではNaN
は出てこないということはわかった。でも肝心のpythonの出力上でのNaN
は解決していない。
どうやれば表示から消せるかというと、一番簡単な方法は上のようにfillna
を使用するという方法。今回で言えば空にしたいから''
を選択すればいい。
これでデータのない部分がNaN
から空に変換される。イメージは置き換わる。
空白ではなく空(から)
# 削除した部分は空白ではなく空っぽ for i in df_nonan['items']: val = f"{i:4s}" # 中身を取り出し tf1 = f"{i == ''}" # 空と比較 tf2 = f"{i == ' '}" # 空白と比較 print(val, tf1, tf2) # date False False # time False False # tool False False # True False # True False # True False # True False # True False # True False # True False # True False
filllna('')
で空に置き換えたが、実際に空かどうかを確かめたい。確かめ方として今回は1要素ずつ比較してみた。結果は''
と等しいにTrue
なのでから出ることが確認できる。
csvで確認してもやっぱり空
new_file = file.replace('.', '_new2.') df_nonan.to_csv(new_file, index=False)
csvファイルとして出力して中身をExcelのジャンプで空白セルチェックをすると、ちゃんと空白=pythonでいう空になっていることが確認できる。
空白にするともちろん空白に
# 空白にするともちろん空白が入る df_space = df.fillna(' ') # NaNを空と比較 # 削除した部分は空白ではなく空っぽ for i in df_space['items']: val = f"{i:4s}" # 中身を取り出し tf1 = f"{i == ''}" # 空と比較 tf2 = f"{i == ' '}" # 空白と比較 print(val, tf1, tf2) # date False False # time False False # tool False False # False True # False True # False True # False True # False True # False True # False True # False True
当たり前だが、fillna
に空白(スペース)を指定すると、NaN
の代わりに入るのが空から半角スペースになる。
したがって、for
で中身を書くにする際には空ではなく空白と等しいかの判定時にTrue
で返される。
csvで確認しても空白
new_file = file.replace('.', '_new3.') df_space.to_csv(new_file, index=False)
今回は半角スペースを入れたのでジャンプでの空白せるには引っかからない。ということで、ここでは条件付き書式で半角スペースと等しいセルに赤色を付加した。
結果は半角スペースを入れたセルは赤くなった。予想通り。
そもそも読み込むときにNaNを使用しない
file = 'data_file.csv' names = ['items', 'values', 'x', 'y'] # ヘッダ名 df_ini = pd.read_csv(file, names=names, na_filter=False) print(df_ini) # items values x y # 0 date 2021/9/14 1 1.5 # 1 time 13:50:12 2 2.7 # 2 tool A device 3 3.8 # 3 4 4.7 # 4 5 5.9 # 5 6 6.7 # 6 7 7.0 # 7 8 8.5 # 8 9 10.0 # 9 10 10.4 # 10 11 11.3
最後に大どんでん返し。これまではNaN
になってしまった→NaN
を空に置き換えようという流れだったが、そもそもデータを読み込む際にNaN
を表示しなければいい。
初めから表示しない方法にはread_csv
の引数na_filter
をFalse
にしてあげればいい。False
にすることで、データがない部分はそのまま出力される。
要するにデフォルトではデータがない部分はNaN
にするという処理をスキップということ。これば一番楽。
ちょっとしたことだけど疑問に持てる
ということで、今回はpandas
のデータフレームで表示されるNaN
を如何にして表示しなくするかについて解説した。
正直、表示使用がしまいが割とどうでもいいことだが、こんな小さなことでも気にしてしまうのが初心者たること。慣れるとどうでもよくなる。
初心を忘れずにという言葉にはこのような、慣れると気にしなかったことも気にすると言う意味も含まれているのかもしれない。
関連記事
-
-
【pd&MultiIndex】pandasで複数インデックスの設定と書き読み
続きを見る
-
-
【辞書&pandas】dict{name: , val: {a: [~], b:[~]}}のpandas化
続きを見る
-
-
【辞書の結合】dictのマージ
続きを見る