LoginSignup
2
0

More than 3 years have passed since last update.

【初心者】LINEのトーク履歴をデータセットに加工する

Last updated at Posted at 2020-07-30

LINEのトーク履歴を加工する

Pythonを使って、LINEのトーク履歴をいじります。

そもそもLINEって?

LINE(ライン)は、24時間、いつでも、どこでも、無料で好きなだけ通話やメールが楽しめる新しいコミュニケーションアプリです。

この記事を読んでいる方は全員LINEを知っている、という前提で話を進めます。

今回の目標

送信した日時、送信した人の名前、送信した内容を上手いことPandasのDateFrameにまとめます。
理想はこんな感じ↓

Datetime Name Content
2020/7/30 12:00 わたし こんにちは
2020/7/30 12:01 わたし [スタンプ]
... ... ...

フォーマット

テキストファイルのフォーマット

LINEのトーク履歴はtxt形式でダウンロードできます。開くと大体これに近い形になっているはず。
最近頻繁にアップデートされているので、また形式が変わってるかも。

2019.12.23 月曜日
15:16 --がグループに参加しました。
15:16 --がグループに参加しました。
15:16 -- こんにちは
15:16 -- [スタンプ]
15:16 -- よろしくお願いします
15:16 -- [スタンプ]

\nは改行です。

  • 日付
yyyy.mm.dd -曜日\n
  • 普通のトーク
hh:mm 名前 内容\n
  • 改行が含まれるトーク
hh:mm 名前 内容1\n
内容2....\n

これ以外は割愛します。自分で試してみてね。

実装する

txtファイルを読み込む
→改行を含むトーク内容を1つにまとめ直す
→時刻 名前 内容を抽出する
→日付をトークにアペンドする
→DataFrameに加工する

全体のスクリプト

スクリプトはこんな感じ。

import pandas as pd

# txtファイルの読み込み
f = open("line_--.txt", encoding="UTF-8")
line_data = f.readlines()
f.close()

# 連結を定義
def appending(list, row):
    row = list[-1] + row
    del list[-1]
    list.append(row)

data = []
for row in line_data:
    # 10文字未満の行
    if len(row) < 10:
        row = row[:-1]
        appending(data, row)
    # 15文字未満の行
    elif len(row) < 15:
        # 時刻+名前+内容
        if row[2] == ":" and row[5] == " ":
            row = row[:-1]
            data.append(row)
        # 改行後のトーク内容
        else:
            row = row[:-1]
            appending(data, row)
    # 15文字以上の行   
    else:
        # 日付
        if row[4] == "." and row[7] == "." and row[-3:-1] == "曜日":
            row = row[:10]
            data.append(row)
        # 時刻+名前+内容
        elif row[2] == ":" and row[5] == " ":
            row = row[:-1]
            data.append(row)
        # 改行後のトーク内容
        else:
            row = row[:-1]
            appending(data, row)

data2 = []
for row in data:
    # 日付を変数dateに代入
    if row[4] == ".":
        date = row
    # 時刻+名前+内容に日付を連結
    else:
        row = date + "." + row
        row = row.split(" ")
        if len(row) == 3:
            data2.append(row)

# リストのデータフレーム化
df = pd.DataFrame(data2, columns=["Datetime", "Name", "Content"])
# 時刻をDatetime型に直す
df["Datetime"] = pd.to_datetime(df["Datetime"], format="%Y.%m.%d.%H:%M")

txtファイルの読み込み

先頭から1行ずつ読み込みます。

f = open("line_--.txt", encoding="UTF-8")
line_data = f.readlines()
f.close()

どうやらline_dataはリストのようです。

print(type(line_data))
# <class 'list'>

連結を定義

listの一番最後の要素に、現在の行を連結させます。

def appending(list, row):
    row = list[-1] + row
    del list[-1]
    list.append(row)

遊んでみましょう。

thanks = ["いつも", "ありがとう"]
appending(thanks, "ございます")
# thanks = ['いつも', 'ありがとうございます']

10行未満の行

hh:mm 名前 内容\n

文字数が最小になるのは、名前が1文字、内容が1文字のときです。
つまり、10文字を下回る行はすべて「改行を含むトークの、改行後の部分」になります。

row = row[:-1] # 最後の一文字は改行\nなので削除
appending(data, row)

この処理で、これを↓

01:10 わたし あけましておめでとう!\n
ことしもよろしく!\n

↓こうします。

01:10 わたし あけましておめでとう!ことしもよろしく!\n

もっといい例はなかったのか。

15文字未満の行

yyyy.mm.dd -曜日\n

日時を表す行は文字数が15です。
15文字を下回る行は「普通のトーク」か「改行を含むトークの、改行後の部分」になります。

普通のトーク

01:10 わたし あけましておめでとう!\n

3文字目が「:」かつ6文字目が「 」になるので、その部分を抽出します。

if row[2] == ":" and row[5] == " ":
    row = row[:-1]
    data.append(row)

改行を含むトークに対しては、先ほどと同じ処理を施します。

15文字以上の行

日付

yyyy.mm.dd -曜日

5文字目と8文字目が「.」で、最後の2文字が「曜日」です。
上手いこと日付の行をピックアップします。

if row[4] == "." and row[7] == "." and row[-3:-1] == "曜日":
    row = row[:10]
    data.append(row)

「曜日」の部分はなんとなく削除しました。
もちろん残してもいいです。

日付以外

さっきと同じです。

ここまでの作業で、リストdata内に「日付」と「時刻 名前 内容」の要素が入りました。
リストdataが空の人、エラーを吐かれている人はLINEのアップデートを恨んでください。

日付をアペンドする

data内の要素のうち、5文字目が「.」なら日付、そうでなければトーク内容です。
日付を変数dateに代入します。

if row[4] == ".":
    date = row

その後「.」で区切り、「時刻 名前 内容」とアペンドすると、

else:
    row = date + "." + row

行(要素)rowは↓になります。

yyyy.mm.dd.hh:mm 名前 内容

最後に「 」で区切り、リストを更新します。

データフレーム化

リストdata2は二重リスト構造です。
Pandasでデータフレームに直し、カラム名をつけてあげます。
せっかくなので、日付と時刻をDatetime型に直しました。

これでおしまいです。お疲れさまでした。
to_csvを使って書き出すこともできます。

最後に

LINEのトーク履歴は自然言語のデータセットとして活用できるのでは?と思ったのがきっかけです。
人間の会話を学習したり、会話から感情を読み取ったり…活用方法はたくさんあると思います。

今回は行の抽出に正規表現を用いませんでした。
このコードでは抽出が上手く行かない場合(抽出したくない行まで取り出してしまう等)、Pythonのreパッケージをお試しください。

自分がとりかかったのは3ヶ月以上前だったのですが、それからこの記事を上げるまでの間にフォーマットが変わっていました。
少しずつ書いていた記事が全部パーに。泣きながらコードを新しく書き直しています。
供養のために、以前のコードも書いておきます。

import pandas as pd

# txtファイルを1行ずつ読み込み
f = open("line_--.txt", encoding="UTF-8")
line_data = f.readlines()
f.close()

# 改行データを前の行に連結
def appending(list, row):
    row = list[-1] + row
    del list[-1]
    list.append(row)

data = []
# 4行目から読み込み
for row in line_data[3:]:
    # 9文字未満の行は連結
    if len(row) < 9:
        row = row[:-1]
        appending(data, row)
    # 13文字未満のとき
    elif len(row) < 13:
        # 時刻+名前+内容
        if row[2] == ":" and row[5] == "\t":
            row = row[:-1]
            data.append(row)
        # 時刻が一桁の場合
        elif row[1] == ":" and row[4] == "\t":
            row = row[:-1]
            data.append(row)
        # 連結
        else:
            row = row[:-1]
            appending(data, row)
    # 13文字以上のとき
    else:
        # 日付
        if row[4] == "/" and row[-4] == "(" and row[-2] == ")":
            row = row[:-4]
            data.append(row)
        # 時刻+名前+内容
        elif row[2] == ":" and row[5] == "\t":
            row = row[:-1]
            data.append(row)
        # 時刻が一桁の場合
        elif row[1] == ":" and row[4] == "\t":
            row = row[:-1]
            data.append(row)
        # 連結
        else:
            row = row[:-1]
            appending(data, row)

data2 = []
for row in data:
    # 日付をdateに代入
    if row[4] == "/":
        date = row
    # 時刻+名前+内容に日付を連結
    else:
        row = date + " " + row
        row = row.split("\t")
        if len(row) == 3:
            # 内容に""が付く場合は削除
            if row[2][0] == '"' and row[2][-1] == '"':
                row[2] = row[2][1:-1]
            data2.append(row)

df = pd.DataFrame(data2, columns=["Datetime", "Name", "Content"])
df["Datetime"] = pd.to_datetime(df["Datetime"], format="%Y/%m/%d %H:%M")
2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0