{"id":869,"date":"2017-08-01T23:07:08","date_gmt":"2017-08-01T21:07:08","guid":{"rendered":"https:\/\/www.bartbarnard.nl\/blog\/?p=869"},"modified":"2017-08-01T23:07:08","modified_gmt":"2017-08-01T21:07:08","slug":"statistieken-uit-een-whatsapp-groep","status":"publish","type":"post","link":"https:\/\/www.bartbarnard.nl\/blog\/statistieken-uit-een-whatsapp-groep\/","title":{"rendered":"Statistieken uit een whatsapp-groep"},"content":{"rendered":"<p>Voor een project met een aantal studenten maakten we in het tweede semester van 2016\/2017 gebruik van whatsapp voor de onderlinge communicatie. Gedurende dat semester werd er behoorlijk wat heen en weer gewhatsappt, maar toen het project eenmaal voltooid was (het had een behoorlijk strakke deadline in het weekend van 22 juli) droogde die stroom snel op. Omdat ik het jammer zou vinden als al die data verloren zou gaan, besloot ik de hele conversatie naar mezelf te mailen en eens aan een eenvoudige statistische analyse te onderwerpen.<\/p>\n<p>Om de data aan jezelf te mailen kun je gebruik maken van de optie &#8216;Exporteer chat&#8217; van whatsapp, die je te zien krijgt wanneer je op de gegevens van de whatsapp-groep zelf klikt. Helemaal onderaan, onder de lijst van de deelnemers, zie je deze optie (zie figuur).<\/p>\n<p><img loading=\"lazy\" class=\"aligncenter size-medium wp-image-877\" src=\"https:\/\/www.bartbarnard.nl\/blog\/wp-content\/uploads\/2017\/08\/exporteer_chat-169x300.png\" alt=\"\" width=\"169\" height=\"300\" srcset=\"https:\/\/www.bartbarnard.nl\/blog\/wp-content\/uploads\/2017\/08\/exporteer_chat-169x300.png 169w, https:\/\/www.bartbarnard.nl\/blog\/wp-content\/uploads\/2017\/08\/exporteer_chat-577x1024.png 577w, https:\/\/www.bartbarnard.nl\/blog\/wp-content\/uploads\/2017\/08\/exporteer_chat.png 640w\" sizes=\"(max-width: 169px) 100vw, 169px\" \/><\/p>\n<p>De data die je dan opgestuurd krijgt, heeft een eenvoudig formaat: datum en tijd, afzender, en tekst \u2013 allemaal gescheiden door een dubbele punt gevolgd door een spate <tt>': '<\/tt>. Op zich zou dit dus eenvoudig in mysql te laden moeten zijn. Hiervoor maakte ik even een tabel chat met drie corresponderende kolommen (genaamd <tt>wanneer<\/tt>, <tt>wie<\/tt> en <tt>wat<\/tt>) en probeerde de data in te laden:<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\nload data local infile \r\n'\/Users\/bart\/Desktop\/wttv\/wttv_chat.txt' \r\ninto table chat fields terminated by ': ';\r\n<\/pre>\n<p>Dit gaf nog wel een zooi errors en warnings, maar belangrijker was dat bij inspectie bleek dat er in het datum-veld dingen als <tt>'2024-07-17 17:47:52'<\/tt> terecht waren gekomen. Op de corresponderende regel in de data zelf stond <tt>'24-07-17 17:47:52'<\/tt> en uit de context kon ik achterhalen dat dit een bericht betrof dat op 24 juli verstuurd was. Blijkbaar is het datum-formaat dus <tt>DD-MM-YY HH:MM:SS<\/tt>.<\/p>\n<p>Het zou natuurlijk een optie zijn geweest om deze data in Excel op te ruimen, maar via <a href=\"https:\/\/dba.stackexchange.com\/questions\/21948\/how-to-import-timestamp-from-a-csv-file\">deze link op stackoverflow<\/a> kwam ik er achter dat het ook (eenvoudiger) via mysql zelf kon.<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\nselect str_to_date('24-07-17 17:47:52', '%d-%m-%Y %k:%i:%s');\r\n+-------------------------------------------------------+\r\n| str_to_date('24-07-17 17:47:52', '%d-%m-%Y %k:%i:%s') |\r\n+-------------------------------------------------------+\r\n| 2017-07-24 17:47:52\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 |\r\n+-------------------------------------------------------+\r\n1 row in set (0,00 sec)\r\n<\/pre>\n<p>Dus<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\nload data local infile \r\n'\/Users\/bart\/Desktop\/wttv\/wttv_chat.txt' \r\ninto table chat fields terminated by ': ' \r\n(@var1, wie, wat) set wanneer=str_to_date(@var1, '%d-%m-%Y %k:%i:%s');\r\n\r\nQuery OK, 1619 rows affected, 271 warnings (0,03 sec)\r\nRecords: 1619\u00a0 Deleted: 0\u00a0 Skipped: 0\u00a0 Warnings: 271\r\n<\/pre>\n<p>Een laatste probleem, wat ook al die foutmeldingen en warnings aan het begin had veroorzaakt, was dat er berichten in de data stonden waar een nieuwe regel in voorkwam; berichten zoals de onderstaande (ik heb de namen van de studenten in deze blog verzonnen):<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\n11-07-17 11:52:34: Henk de Boer: I think it\u2019s really important to see you all this Wednesday at 15:30\r\nWe\u2019ll discuss the following:\r\n- Decoration, fencing (Jan)\r\n- Tents! Who has a tent, who needs one?\r\n- What kind of tools does each group needs, how are we going to get them?\r\n- Transportation\r\n- Schedule at WTTV\r\n<\/pre>\n<p>Het mooiste is om even een scriptje te maken dat over alle regels van het bestand heengaat en dit soort regels tot \u00e9\u00e9n bericht samenvoegt: op die manier voorkom je vuile data en hou je de statistieken het meest accuraat. Om dit te bewerkstelligen kunnen eenvoudig kijken of de regel begint met twee cijfers (die van de datum namelijk); als dat niet het geval is, betreft het hoogstwaarschijnlijk een stuk tekst die over de regel is gelopen. Het onderstaande python-scriptje doet precies dat:<\/p>\n<pre class=\"brush: python; title: ; notranslate\" title=\"\">\r\nbuffer = [];\r\nprevious_line = '';\r\n\r\nwith open('wttv_chat.txt') as f:\r\n  for line in f:\r\n    line = line.rstrip()\r\n    if (line[:2].isdigit()):\r\n      print(previous_line + ' '.join(c for c in buffer))\r\n      previous_line = line\r\n      buffer = []\r\n\r\n    else:\r\n      buffer.append(line) #buffering lines that belong to the same message\r\n\r\nprint(line) #otherwise the last line won't be printed.\r\n<\/pre>\n<p>Het enige probleem is dat er tijdens het festival op een gegeven moment een rooster werd verspreid waarin tijden staan waarop mensen aanwezig moesten zijn. Deze begonnen natuurlijk weer wel met twee cijfers aan het begin van de regel:<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\n20-07-17 12:03:22: Karel de Graaf: VRIJDAG AANWEZIG\u00a0 14.00 - 1.00\r\n14.00 - 17.00 die-en-die studenten\r\n17.00 - 20.00 andere studenten\r\n20.00 - 22.00 nog een groepje\r\n11.00 - 14.00 enzovoort\r\n<\/pre>\n<p>Dit gebeurde twee of drie keer, dus ik had het met de hand aan kunnen passen, maar programmatisch is natuurlijk altijd beter. Eenvoudig de check op regel 7 in het python-scriptje uitbreiden met het streepje dat na de timestamp komt:<\/p>\n<pre class=\"brush: python; title: ; notranslate\" title=\"\">\r\nif (line[:2].isdigit() and line[2]=='-'):\r\n<\/pre>\n<p>Er kwamen nu bij het laden nog wel een paar waarschuwingen, maar dat bleken opmerkingen te zijn van mensen die aan de groep waren toegevoegd \u2013 die konden we dus eenvoudig negeren. Voor de goede orde halen we die (en vergelijkbare) zooi er even uit:<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\ndelete from chat where wat is null;\r\n<\/pre>\n<p>Nu was de data alleszins acceptabel om de statistieken eruit te halen.<\/p>\n<p><strong>STATISTIEKEN<\/strong><br \/>\nDe meest eenvoudige query is natuurlijk om te kijken hoeveel appjes er in totaal zijn verstuurd<br \/>\nHoeveel appjes zijn er in totaal verstuurd?<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\nmysql&gt; select count(*) from chat;\r\n+----------+\r\n| count(*) |\r\n+----------+\r\n|\u00a0\u00a0\u00a0\u00a0 3032 |\r\n+----------+\r\n1 row in set (0,00 sec)\r\n<\/pre>\n<p>Een ander interessant gegeven, dat eveneens makkelijk te achterhalen is, is wie er het meeste appt:<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\nmysql&gt; select count(*) as tot, wie from chat group by wie order by tot desc;\r\n<\/pre>\n<p>Wie heeft er hoeveel afbeeldingen en hoeveel video&#8217;s aan de groep toegevoegd?<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\nmysql&gt; select wie, count(*) from chat where wat like '%afbeelding%' group by wie order by wie;\r\nmysql&gt; select wie, count(*) from chat where wat like '%video%' group by wie order by wie;\r\n<\/pre>\n<p>Omdat dit een groep zeer gemotiveerde studenten betrof, was ik ook wel nieuwsgierig of je iets van die motivatie terug kon zien in de momenten waarop zoal berichten werden verstuurd. Omdat deze chat maar een half jaar heeft bestaan (ok, hij bestaat nog steeds, maar de analyse gaat over het voorbije half jaar), kon ik eenvoudig een check doen op de weeknummers:<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\nmysql&gt; select week(wanneer) as w, count(*) as total from chat group by w;\r\n+------+-------+\r\n| w\u00a0\u00a0\u00a0 | total |\r\n+------+-------+\r\n|\u00a0\u00a0 11 |\u00a0\u00a0\u00a0 12 |\r\n|\u00a0\u00a0 13 |\u00a0\u00a0\u00a0 32 |\r\n|\u00a0\u00a0 14 |\u00a0\u00a0\u00a0\u00a0 6 |\r\n|\u00a0\u00a0 15 |\u00a0\u00a0\u00a0 24 |\r\n|\u00a0\u00a0 16 |\u00a0\u00a0\u00a0 32 |\r\n|\u00a0\u00a0 18 |\u00a0\u00a0\u00a0 58 |\r\n|\u00a0\u00a0 19 |\u00a0\u00a0\u00a0\u00a0 4 |\r\n|\u00a0\u00a0 20 |\u00a0\u00a0\u00a0 28 |\r\n|\u00a0\u00a0 21 |\u00a0\u00a0\u00a0 52 |\r\n|\u00a0\u00a0 22 |\u00a0\u00a0\u00a0 12 |\r\n|\u00a0\u00a0 23 |\u00a0\u00a0 182 |\r\n|\u00a0\u00a0 24 |\u00a0\u00a0 236 |\r\n|\u00a0\u00a0 25 |\u00a0\u00a0\u00a0 16 |\r\n|\u00a0\u00a0 26 |\u00a0\u00a0\u00a0 76 |\r\n|\u00a0\u00a0 27 |\u00a0\u00a0\u00a0 52 |\r\n|\u00a0\u00a0 28 |\u00a0\u00a0 776 |\r\n|\u00a0\u00a0 29 |\u00a0 1304 |\r\n|\u00a0\u00a0 30 |\u00a0\u00a0 130 |\r\n+------+-------+\r\n18 rows in set (0,09 sec)\r\n\r\nmysql&gt;\r\n<\/pre>\n<p>Hier komt wel heel duidelijk naar voren dat week 29 de week is voorafgaand aan de strakke deadline van 22 juli: in deze week zijn verreweg de meeste berichten verstuurd, gevolgd door de week daarvoor. Het is nog interessant om te kijken wat er gebeurde in weken 23 en 24, want daar zijn ook veel meer berichten verstuurd dan gemiddeld (het gemiddelde is 3032\/20 = 151 berichten per week, maar als we de uitbijters van week 28 en 29 negeren daalt dat naar zo&#8217;n vijftig berichten per week).<\/p>\n<p>Minstens zo interessant is om te kijken naar de dagen waarop berichten worden verstuurd. Hier heb ik even een trucje moeten toepassen om de dagen op een normale (niet-lexicografische) manier gesorteerd te krijgen:<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\nmysql&gt; select dayofweek(wanneer) as d_nr, dayname(wanneer) as dag, count(*) as total from chat group by dag order by d_nr;\r\n<\/pre>\n<p>En de drukste uren:<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\nmysql&gt; select hour(wanneer) as h, count(*) from chat group by h;\r\n<\/pre>\n<p>Uit deze data bleek dat er geen enkel uur in het etmaal is waarin er geen bericht is verstuurd: de studenten werkten blijkbaar altijd door.<\/p>\n<p>Maar interessanter is natuurlijk om te zien wie wanneer een berichtje stuurt; daarvoor maakte ik gebruik van de optie om een if-statement in een sum-clause te stoppen, zoals <a href=\"https:\/\/stackoverflow.com\/questions\/9798937\/count-with-if-condition-in-mysql-query#9798978\">hier beschreven wordt<\/a>:<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\nmysql&gt;\r\nselect hour(wanneer) as h\r\n, sum(if(wie like '%Henk%', 1, 0)) as Henk\r\n, sum(if(wie like '%Karel%', 1, 0)) as Karel\r\n, sum(if(wie like '%Sjaak%', 1, 0)) as Sjaak\r\n, sum(if(wie like '%Margriet%', 1, 0)) as Margriet\r\nfrom chat\r\ngroup by h;\r\n<\/pre>\n<p>Via deze query (althans, de echte versie ervan natuurlijk) konden we mooi achterhalen wie van de groep de nachtbrakers waren en wie de vroege vogels.<\/p>\n<p><strong>Conclusie<\/strong><br \/>\nHet gebruiken van whatsapp voor onderlinge communicatie werkt heel goed. Het is snel, vertrouwd en makkelijk te gebruiken. Statistieken zoals deze zijn natuurlijk in eerste instantie alleen bedoeld voor de grap, maar wie weet kunnen we het ook eens gaan gebruiken om de inzet van bepaalde studenten te monitoren.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Voor een project met een aantal studenten maakten we in het tweede semester van 2016\/2017 gebruik van whatsapp voor de onderlinge communicatie. Gedurende dat semester werd er behoorlijk wat heen en weer gewhatsappt, maar toen het project eenmaal voltooid was (het had een behoorlijk strakke deadline in het weekend van 22 juli) droogde die stroom<\/p>\n<p class=\"more-link\"><a href=\"https:\/\/www.bartbarnard.nl\/blog\/statistieken-uit-een-whatsapp-groep\/\" class=\"themebutton2\">Read More<\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[19],"tags":[],"_links":{"self":[{"href":"https:\/\/www.bartbarnard.nl\/blog\/wp-json\/wp\/v2\/posts\/869"}],"collection":[{"href":"https:\/\/www.bartbarnard.nl\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.bartbarnard.nl\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.bartbarnard.nl\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.bartbarnard.nl\/blog\/wp-json\/wp\/v2\/comments?post=869"}],"version-history":[{"count":8,"href":"https:\/\/www.bartbarnard.nl\/blog\/wp-json\/wp\/v2\/posts\/869\/revisions"}],"predecessor-version":[{"id":878,"href":"https:\/\/www.bartbarnard.nl\/blog\/wp-json\/wp\/v2\/posts\/869\/revisions\/878"}],"wp:attachment":[{"href":"https:\/\/www.bartbarnard.nl\/blog\/wp-json\/wp\/v2\/media?parent=869"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.bartbarnard.nl\/blog\/wp-json\/wp\/v2\/categories?post=869"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.bartbarnard.nl\/blog\/wp-json\/wp\/v2\/tags?post=869"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}