เรื่องของเรื่องมีอยู่ว่าเราชอบแชทกับสาวๆ บนแอป 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 เล่นดู :)