はじめに
Twitter API で取得したデータをCSVファイルに保存したときに、改行コードが原因で苦労したのでメモ。
環境
Ubuntu 18.04.2
Anaconda 3 5.3.1
Python 3.7
Jupyter Notebook
問題
Twitter API で取得できるデータのうち、text
・full_text
・user->description
といった要素は、ユーザーが自分で文章を入力したデータになるので、改行コードが含まれる場合があります。
改行コードには\n
・\r
・\r\n
の3種類があるのですが、Twitterユーザーが使用している環境によって、その種類が変わってきてしまいます(参考:改行コード一覧)。
例えばツイートのtextデータには
メッセージ\nメッセージ\nメッセージ
メッセージ\rメッセージ\rメッセージ
メッセージ\r\nメッセージ\r\nメッセージ
の3種類が含まれるのです。
さて本題。
Twitter APIで取得したデータをpandasのDataFrame型にした後、CSV形式でファイルとして保存したのですが、保存したファイルを読み込むと、データの行数が増えていたり、カラムにズレが生じていて、保存時の形を全く保っていなかったのです。
どういうことかというと、例えば以下のようなコードを実行すると、
# 改行コードが\rのとき
import pandas as pd
from IPython.display import display
df = pd.DataFrame([{ 'created_at': '12:00',
'text': 'メッセージ\rメッセージ\rメッセージ',
'tweet_id': 12345,
'user_id': 67890,
}])
display(df) # DataFrameを出力
df.to_csv('test.csv', encoding="utf-8") # CSV形式で保存
df = pd.read_csv('test.csv', index_col=0)
display(df) # 読み込んだCSVデータを出力
結果は以下のようになります。DataFrame(上)は正常ですが、一度CSV形式に変換すると崩れていますよね(下)。
\r
を境に行が一段下がり、カラムと値がミスマッチしています(インデックスに値が入ってるしめちゃくちゃ...)。空いているデータはすべてNaN
になっていますね。
どうやら、問題児は改行コードの\r
のみのようです。
\n
や\r\n
の場合は、データが崩れることなく保存できます↓
# 改行コードが\nのとき
df = pd.DataFrame([{ 'created_at': '12:00',
'text': 'メッセージ\nメッセージ\nメッセージ',
'tweet_id': 12345,
'user_id': 67890,
}])
display(df) # DataFrameを出力
df.to_csv('test.csv', encoding="utf-8") # CSV形式で保存
df = pd.read_csv('test.csv', index_col=0)
display(df) # 読み込んだCSVデータを出力
# 改行コードが\r\nのとき
df = pd.DataFrame([{ 'created_at': '12:00',
'text': 'メッセージ\r\nメッセージ\r\nメッセージ',
'tweet_id': 12345,
'user_id': 67890,
}])
display(df) # DataFrameを出力
df.to_csv('test.csv', encoding="utf-8") # CSV形式で保存
df = pd.read_csv('test.csv', index_col=0)
display(df) # 読み込んだCSVデータを出力
解決方法
その1
\r
を\n
に置換する。
\r\n
に含まれる\r
は、置換してしまうと改行が1つ増えてしまうので、注意する必要があります。
df = pd.DataFrame([{ 'created_at': '12:00',
'text': 'メッセージ\rメッセージ\rメッセージ',
'tweet_id': 12345,
'user_id': 67890,
}])
display(df) # DataFrameを出力
# \r\nの場合は除いて、\rを\nに置換する
if ('\r' in df['text'][0]) and not ('\r\n' in df['text'][0]):
df['text'][0] = df['text'][0].replace('\r', '\n')
df.to_csv('test.csv', encoding="utf-8") # CSV形式で保存
df = pd.read_csv('test.csv', index_col=0)
display(df) # 読み込んだCSVデータを出力
追記
改行コードを全部\n
に統一した方が良さそうですね。以下のコードで\r\n
と\r
の両方を置換できます。
置換する順序を間違えると、\r\n
が\n\n
になってしまうので気をつけましょう。
df['text'][0] = df['text'][0].replace('\r\n', '\n').replace('\r', '\n')
df.to_csv('test.csv', encoding="utf-8") # CSV形式で保存
df = pd.read_csv('test.csv', index_col=0)
display(df) # 読み込んだCSVデータを出力
その2
pickleを使用する。
df = pd.DataFrame([{ 'created_at': '12:00',
'text': 'メッセージ\nメッセージ\nメッセージ',
'tweet_id': 12345,
'user_id': 67890,
}])
display(df) # DataFrameを出力
df.to_pickle('test.pickle') # pickle形式で保存
df = pd.read_pickle('test.pickle')
display(df) # 読み込んだpickleデータを出力
pickleファイルはコードで読み込まない限り中身を確認することができない(Excel等で開くことができない)ので、簡単にデータを確認できるようにしたいようなら、\r
を\n
置換してCSV形式で保存する方法が良いと思います。
以上