Edited at

Twitter APIで取得したデータをCSV形式で保存するときは、改行コードに気を付けよう


はじめに

Twitter API で取得したデータをCSVファイルに保存したときに、改行コードが原因で苦労したのでメモ。


環境

Ubuntu 18.04.2

Anaconda 3 5.3.1

Python 3.7

Jupyter Notebook


問題

Twitter API で取得できるデータのうち、textfull_textuser->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になっていますね。

スクリーンショット 2019-08-09 21.05.32.png

どうやら、問題児は改行コードの\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データを出力

スクリーンショット 2019-08-09 21.10.36.png

# 改行コードが\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データを出力

スクリーンショット 2019-08-09 21.10.57.png


解決方法


その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データを出力

スクリーンショット 2019-08-09 23.05.08.png


追記

改行コードを全部\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データを出力

スクリーンショット 2019-08-09 21.56.31.png

pickleファイルはコードで読み込まない限り中身を確認することができない(Excel等で開くことができない)ので、簡単にデータを確認できるようにしたいようなら、\r\n置換してCSV形式で保存する方法が良いと思います。

以上