ลองเอา LINE chat มาวิเคราะห์

TITIPATA bio photo

By TITIPATA

ชอบฟังเพลงอินดี้และอัลเทอร์เนทีฟ เวลาว่างชอบเขียนโปรแกรมและเล่นเกม

Email Twitter Google+ Github

Reading time ~27 minutes

TITIPATA bio photo

By TITIPATA

ชอบฟังเพลงอินดี้และอัลเทอร์เนทีฟ เวลาว่างชอบเขียนโปรแกรมและเล่นเกม

Email Twitter Google+ Github

เรื่องของเรื่องมีอยู่ว่าเราชอบแชทกับสาวๆ บนแอป LINE (ไลน์) จริงๆ สำหรับเราตอนนี้ก็มีแค่คนเดียวนั่นแหละ แต่เวลาคุยกับสาวทีไรเพื่อนสนิทซึ่งก็ไม่ใช่ใครที่ไหน @bluenex นี่แหละ จะชอบถามไถ่ว่าคุยไปถึงไหนแล้ว คุยอะไรไปบ้าง ไหนเราจะโดนสาวเทแบบคนก่อนๆ รึเปล่า หรือทักเค้าไปฝ่ายเดียวรึเปล่า

ปกติคนส่วนมากก็คงจะแคปหน้าจอแชทไปให้ดู แต่แค่แคปหน้าจอไปให้ @bluenex อย่างเดียว มันก็ชอบหาว่าเราเอาแต่ส่วนที่เค้าตอบดีๆ มาให้ดู และไม่ค่อยจะยอมเชื่อซักเท่าไหร่ แต่ถ้าจะส่งแชททั้งหมดไปให้ก็ไม่โอเค เขินน่ะ สุดท้ายเลยบอกมันไปว่าเดี๋ยวส่งสรุปไปให้ดูละกัน

นั่นแหละครับ เรื่องมันก็เริ่มขึ้นประมาณนี้ เหตุเกิดในเวลาเที่ยงคืนวันจันทร์ เราเลยกดโหลด chat log จากไลน์แชทมา และเริ่มวิเคราะห์แชทโดยใช้ Python

ในบล็อกนี้เราจะมาพูดถึงกระบวนการคร่าวๆ ที่เราใช้เพื่อวิเคราะห์ไลน์แชทกัน จริงๆ แล้วเราเอาแชทมาพล็อตอะไรได้เยอะแยะเลยนะ แต่วันนี้จะมาลองพล็อตอะไรง่ายๆ กันก่อน

โค้ดทั้งหมดอยู่บน Github ที่ titipata/visualize_line_chat ไปลองติดตาม หรือโคลนมาลองใช้กับแชทตัวเองก็ได้

หน้าตาของ Line text file

2017.03.10 Friday
07:38 user1 hello
08:06 user2 hi, how are you?
08:37 user1 i'm doing great, i'm going to get Thai food tonight.
08:38 user1 and go to the gym later :)
08:40 user2 aww, have fun. send me some photos
2017.03.11 Saturday
01:39 user2 aww, i just got ramen today
01:39 user1 did you like it!?
07:54 user2 hahahahahah yupp

หน้าตาของแชทที่โหลดมาก็เป็นประมาณข้างบน จากไฟล์ที่ว่าเราสามารถใช้ library ของ Python ที่ชื่อ csv เพื่อแปลง text file ให้เป็น list ได้ โดยใช้คำสั่งด้านล่าง

lines = csv.reader(open(file_name))
chats = list(lines)
chats = [c[0] for c in chats if len(c) > 0]
...

list ท้ายสุดที่เราได้จะมีหน้าตาประมาณนี้

[[2017.03.10, 07:38 user1 hello],
 [2017.03.10, 08:06 user2 hi, how are you?],
 [2017.03.10, 08:37 user1 i'm doing great, i'm going to get Thai food tonight.],
  ...
 [2017.03.11, 01:39 user2 aww, i just got ramen today],
 [2017.03.11, 01:39 user1 did you like it!?],
 [2017.03.11, 07:54 user2 hahahahahah yupp],
  ...

สิ่งแรกที่เราต้องทำคือแค่ loop ไปในแต่ละบรรทัด แล้วเอาวันที่มาใส่ข้างหน้าแชทแต่ละอัน ที่เราทำนี้ก็เพื่อว่าในตอนท้ายเราจะสามารถใช้ฟังก์ชันชื่อ groupby จาก library ที่ชื่อ itertools เพื่อจัดกลุ่มข้อมูลของเราที่มีวันที่เดียวกันเข้าด้วยกันได้ตาม key ซึ่งในที่นี้ ก็คือวันที่นั่นเอง

หน้าตาของโค้ด groupby เป็นประมาณด้านล่าง

from itertools import groupby

group_chats = []
for key, group in groupby(chats, lambda x: x[0]):
    group_chats.append({'date': key, 'chats': [g[1] for g in group]})

หลังจากนั้น เราจะนับจำนวนและพล็อตจำนวนของแชทในแต่ละวัน โดยใช้เพียงคำสั่งที่ชื่อว่า len

chats_per_day = []
for group_chat in group_chats:
    dt = parser.parse(group_chat['date'])
    chats_per_day.append([dt, len(group_chat['chats'])])

สำหรับใครที่โหลดสคริปต์มาจาก titipata/visualize_line_chat เราเขียนฟังก์ชัน plot_chat_per_day ไว้ใน line_utils.py ทำให้สามารถใช้ฟังก์ชันตามตัวอย่างด้านล่างได้เลย

import line_utils
chats = line_utils.read_line_chat('path/to/chat_history.txt')
line_utils.plot_chat_per_day(chats_dict)

พอพล็อตออกมา จำนวนแชทที่เราแชทกันในแต่ละวันจะมีหน้าตาประมาณนี้

เรากับเธอใครแชทเยอะกว่ากัน?

เวลาเราแชทกับคนคนนึง บางทีเราอาจจะคิดว่าเค้าแชทมาเยอะกว่า หรือบางทีเราแชทไปเยอะกว่า แต่เราไม่รู้หรอกว่าจำนวนที่เราแชทไปหรือเค้าแชทมามันต่างกันมากขนาดไหน ถ้าสมมติเราแชทกับใครซักคนและปริมาณของแชทมีเท่าๆ กันก็น่าจะดี ต่อไปเรามาลองดูกันว่าปริมาณแชทของเราสองคนเป็นยังไงบ้าง

เทคนิคที่ใช้ก็คล้ายๆ เดิม เพียงแต่ตอนนี้เราต้องจัดกลุ่มทั้งวันที่และชื่อผู้ใช้งาน จากนั้นก็นับจำนวนของแชทในแต่ละกลุ่ม

ก่อนอื่นเราจะต้องแยกส่วนประกอบของแต่ละแชทให้เป็น dictionary ดังตัวอย่างด้านล่าง

# chat string
'01:39 user2 aww, i just got ramen today'

# dictionary
{'time': "01:39", 'user': "user2", 'text': "aww, i just got ramen today"}

พอเราได้ dictionary มาแล้วก็ใช้เทคนิคเดิมเพื่อจัดกลุ่มวันที่และชื่อผู้ใช้งานเข้าด้วยกัน เราสามารถใช้คำสั่งเดิมคือ groupby แต่ว่าใส่ key เข้าไปเป็น date และ user แทน

grouper = itemgetter("date", "user")
chats_per_day = []
for key, group in groupby(sorted(chat_users, key=grouper), grouper):
    temp_dict = dict(zip(["date", "user"], key))
    temp_dict["n_chat"] = len([item for item in group])
    chats_per_day.append(temp_dict)

สำหรับใครที่โหลดสคริปต์มาก็แค่พิมพ์ตามนี้เลย

import line_utils
chats = line_utils.read_line_chat('path/to/chat_history.txt')
line_utils.plot_chat_users_per_day(chats)

สีฟ้าคือจำนวนแชทของผม ส่วนสีชมพูคือจำนวนแชทของเธอ เรากับเธอแชทไปมาพอๆ กันเลยนะ ไม่รู้ว่าดีหรือไม่ดี สำหรับเราคิดว่าดีนะเพราะเราไม่ได้คุยอยู่ฝ่ายเดียว :)

เราแชทกันเวลาไหนมั่ง

นอกจากแต่ละวันที่แชทแล้ว เราก็อยากจะรู้บ้างว่าส่วนมากที่เราแชทกันมันช่วงเวลาไหนนะ ส่วนมากเราแชทกันวันธรรมดาหรือว่าวันหยุด วันศุกร์เราแชทกันเยอะมั้ย?​

เราเริ่มด้วยการสร้าง dictionary ของแชทเหมือนที่ทำไปเมื่อกี้

# chat string
'01:39 user2 aww, i just got ramen today'

# dictionary
{'time': "01:39", 'user': "user2", 'text': "aww, i just got ramen today"}

เมื่อเราได้ dictionary มาแล้ว สิ่งที่ต้องทำต่อก็คือแบ่งช่วงเวลาเป็นหลายๆ ช่วงเช่น เก้าโมงถึงเที่ยงวัน เป็นหนึ่งช่วง เที่ยงวันถึงบ่ายสามโมงเป็นอีกช่วงนึง จริงๆ แล้วเราก็ตั้งเป็นแค่ตัวเลข 0, 1, …, 7 ถ้าเราแบ่ง 24 ชั่วโมงเป็น 8 ช่วง

ส่วนวันนั้น ใน Python เราสามารถใช้ library ที่ชื่อ datetime และ dateutil ในการแปลงวันเป็นวันอาทิตย์ถึงวันเสาร์ได้ โค้ดสำหรับการแปลงวันที่เป็นวันในสัปดาห์หน้าตาก็เป็นตามด้านล่าง

from dateutil import parser
def day_of_week(day, n_bin=8):
    return parser.parse(day).weekday()

จากนั้นเราสามารถจัดกลุ่มวันและช่วงเวลาของวันเข้าด้วยกันแล้วนับจำนวนแชทได้เลย เราเขียนฟังก์ชันใน line_utils.py ไว้ชื่อว่า plot_punch_card_activities

import line_utils
chats = line_utils.read_line_chat('path/to/chat_history.txt')
line_utils.plot_punch_card_activities(chats)

พอพล็อตออกมาจะได้หน้าตาประมาณนี้

ส่วนมากเราคุยกันประมาณช่วงเช้ากับช่วงเย็นของวันที่อเมริกา (เวลาของเราเอง) ก็ประมาณช่วงค่ำๆ กับช่วงเช้าๆ ไทย ที่เหลือก็ปล่อยให้เวลากับตัวเองมั่งเนอะ อิอิ

เธอหรือเรา ใครตอบเร็วกว่ากัน?

เวลาแชทกันเนี่ย ปัจจัยสำคัญอย่างนึงคือความเร็วในการตอบของแต่ละฝ่าย ถึงแม้ว่าความเร็วในการตอบแชทอาจไม่ได้บ่งบอกถึงระดับความสัมพันธ์ แต่มันก็อาจจะเป็นตัวบ่งชี้ถึงความราบรื่นของบทสนทนานั้นๆ

การตอบแชทกลับไปมาที่ไม่นานจนเกินไปอาจจะแสดงว่าเราสองคนคุยกันถูกคอหรือจะเรียกว่าเคมีตรงกันก็เป็นได้

เราใช้ข้อมูลแบบเดิมกับหัวข้อที่แล้วเลย คือในแต่ละแชทเราจะจัดข้อมูลให้อยู่ในรูปแบบดังต่อไปนี้

...
['2017.03.10 18:40', 'user2'],
['2017.03.10 18:41', 'user2'],
['2017.03.10 18:41', 'user1'],
['2017.03.10 18:42', 'user2'],
['2017.03.10 18:42', 'user2'],
['2017.03.10 18:42', 'user1'],
['2017.03.10 18:42', 'user2'],
...

ต่อไปเราก็จะ loop ไปในแต่ละแชทเพื่อหาแชทที่ผู้ตอบไม่ซ้ำกันกับแชทที่แล้ว จากนั้นเราจะหาช่วงต่างของเวลาในการตอบนั้นๆ จริงๆ แล้ววิธีที่เราใช้นี้อาจจะไม่ถูกต้องที่สุดเพราะว่าบางทีอีกฝั่งอาจจะอ่านแชทแล้วยังไม่ตอบในทันทีไม่ว่าจะด้วยเหตุผลอะไร แต่สำหรับข้อมูลที่เรามีนี้ก็ใช้ประมาณได้พอโอเคเลยแหละ

เมื่อเรารู้ว่า user1 และ user2 ใช้เวลาตอบแชทแต่ละแชทห่างกันเท่าไหร่บ้าง เราก็จะเก็บความต่างของช่วงเวลาเหล่านั้นเข้าไปในลิสต์ดังตัวอย่างต่อไปนี้

user1_responses = [0, 1, 0, 0, 3, 0, 1, 0, ...]
user2_responses = [0, 0, 0, 1, 2, 0, 0, 1, ...]

ลิสต์นี้คือช่วงเวลาที่ทั้งสองฝ่ายใช้ในการตอบแชทอีกฝ่าย

จากนั้นเราก็สามารถพล็อตจำนวนของแชทกับช่วงเวลาที่ใช้ในการตอบได้แล้ว ซึ่งใน Python เราเพียงแค่ใช้คำสั่ง hist ซึ่งย่อมาจาก histogram เหมือนที่เห็นในตัวอย่างข้างล่าง

plt.hist(resp, bins=range(0, 30), alpha=0.6, color=colors[i])

นอกจากนั้นเรายังสามารถหาค่าเฉลี่ยความเร็วในการตอบแชทของแต่ละคนได้อีกด้วย

ความเรวในการตอบ = 1 / ผลรวมของ (จำนวนแชท * วงเวลาทีใชในการตอบของแตละคน)

คำนวณออกมาแล้วความเร็วที่ผมและเธอจะตอบแชทได้ค่าประมาณนี้ ผม = 0.636 นาที, เธอ = 0.655 นาที โดยรวมแล้วถือว่าก็ดีนะ

สองคนไม่ต้องรอนานเกินกว่านาทีก่อนที่อีกฝ่ายจะตอบ กำลังดีมั้งเนอะ :)

เราสามารถใช้ฟังก์ชัน plot_response_rate ใน line_utils.py เพื่อลองพล็อตกราฟออกมาได้เลย

import line_utils
chats = line_utils.read_line_chat('path/to/chat_history.txt')
line_utils.plot_response_rate(chats)

สรุป

ในโพสต์นี้ เราได้ดาวน์โหลดแชทจากไลน์มา และใช้ Python ลองสรุปข้อมูลที่เราได้จากแชทดังต่อไปนี้

  • จำนวนแชทที่แชทกันไปต่อวัน
  • จำนวนแชทของแต่ละคนต่อวัน
  • จำนวนแชทในแต่ละช่วงเวลาของวัน
  • เวลาที่ทั้งคู่ใช้ในการต่อบทสนทนากัน

ใครที่สนใจดูโค้ดเต็มๆ ก็ไปอ่านกันต่อได้ที่ titipata/visualize_line_chat ส่วนถ้าใครมีคำถามหรือไอเดียอยากจะพล็อตอะไรอย่างอื่น ก็ส่งข้อความมาบอกกันหรือพิมพ์ไว้ด้านล่างได้ ไว้ว่างๆ เราจะมาลองนั่งเขียน Python เล่นดู :)

จาก Reinforcement Learning จนมาเป็น Deep Reinforcement Learning (ฉบับพกพา)

ทำความรู้จักการเรียนรู้แบบเสริมกำลัง (reinforcement learning) ตั้งแต่เบื้องต้น จนมาเป็น Deep Reinforcement Learning ได้ในงานวิจัยปัจจุบัน

[Python] profiler ด้วย line_profiler

Published on February 09, 2019

[รีวิว] เน็ตบ้าน AIS

Published on February 05, 2019