Kohortenanalyse in PHP – ein Marketinginstrument zum verlieben

Wie man seine Kunden besser im Blick hat, deren Kaufverhalten analysiert und wie man eine Kohortenanalyse im eigenen Ecommerce-Shop aufsetzt (Ansatz mit Vorbereitungen), erfährst du in diesem Artikel.

Von Google Analytics kennt man bereits die Kohortenübersicht aus dem Dashboard einer Property. Um sie zu verstehen ist der Begriff Kohorte zu erklären: Er stammt von den Römern und eine Menschengruppe in  militärische Einheiten ein. Übertragen auf das Marketing teilt man Kunden in Gruppen ein. Das kann man wunderbar auf Kunden übertragen, indem man sie zum Beispiel nach der Woche der Registrierung einteilt oder dem Tag des ersten Seitenaufrufes. Die Events müssen dabei klar definiert sein, damit die Analyse sinnhaft wird.

Aufgrund der Parameter lässt sich analysieren, wie das Kaufverhalten einer Kohorte ausschaut. Da die Datensammlung von Google Analytics auf 3 Monate beschränkt ist, ist es sinnvoll eine eigene Analyse aufgrund der eigenen Zahlen anzulegen. Im Netz finden sich oft Anleitungen zu Excelmakros und Best Practices. Allerdings braucht man dazu regelmäßig Zeit. Es gab auf Github auch großartige Projekte wie Cohort Builder by Keen IO und  kirilkirkov/Cohort-Analysis, die allerdings nicht ausreichend dokumentiert sind, für einen konkreten Zweck vorgesehen sind (z.B. Kibana Plugin, Datenansicht nicht ausreichend) oder schlicht weg nicht funktioniert haben.

Um all diese Punkte zu umgehen  und ein leicht zu verstehendes Marketingtool bereit zu stellen, habe ich ein Backendwidget entwickelt, das On-The-Fly gerendert wird und dabei auch noch gut ausschaut.

Wie funktioniert die Technik im Hintergrund?

Via PHP, DB-Connector und MySQL werden die Daten in ein mehrdimensionales Array gegeben. Die Struktur ist für die Ausgabe im  Frontend vorbereitet. Dort werden alle Datensätze via foreach() ausgegeben und in eine Tabelle generiert. Zusätzlich werden je Tabellenzelle werden conversions als Data-Attribute angegeben. Dies passiert, damit im Frontend via Javascript jede Zelle priorisiert werden kann woraufhin CSS Klassen verteilt werden. Diese färben die Zellen ein und machen dieses Widget lesbar, vor allem für Marketer.

Vorbereitungen

Das benötigst du für eine Kohortenanalyse in PHP, CSS, HTML5, JS:

  • Zeitraumdefinition der Analyse in einem verschachtelten Array (arraywert wird mit “TRUE” befüllt, da sonst das die Keys des Arrays nicht erhalten bleiben)
  • SQL Statements für
    • Gesamtanzahl der Orders der Kohorte
    • Betrag der gesamten Bestellungen der Kohorte
    • Anzahl der Registrierungen der Kohorte
    • Anzahl der Bestellungen für die jeweiligen Monate
  • Achtung: Bei der Auswertung von Kalenderwochen-basierten Auswertungen habe ich mit der YEARWEEK() Funktion gearbeitet. Diese fängt in MySQL by default bei 0 an zu zählen. Das heißt, Kalenderwoche 1 wird als 0 ausgegeben. Diese kann ganz einfach mit dem 2. Parameter “Mode” auf 1 gesetzt werden.
  • 2-fache Iteration der Zeitraumdefinition
    • 1. Durchlauf: Generiert die Zeilen/Spalten für das Frontend
    • 2. Durchlauf: Befüllt die Conversions der jeweiligen Zelle
  • Eine Conversion kann nur dann berechnet werden, sofern die Bestellungen & Registrierungen > 0 sind. Diesen Fall muss man unbedingt prüfen.
  • CSS Klassen für die farbliche Unterscheidung sind eine tolle Erweiterung um wertvolle Kohorten und darauf passende Marketingaktionen sichtbar zu machen. Hier kann dir Adobe Color CC dabei helfen das passende Farbschema zu finden.
  • TIPP: Dieses Widget zu programmieren ist sehr kopflastig, besonders wenn es Tagelang später noch ein mal zur Anpassung kommt; deshalb empfiehlt es sich am Vormittag mit frischen Gedanken ans Werk zu gehen und einen möglichst ununterbrochenen Arbeitsfluss von der Umgebung einzufordern.

Ansatz in PHP-Code

public function cohortAnalysisByMonth(){


    $return = []; // must be an array

    // generate time range array like this
    $timeInterval['2017']['10'] = true;
    $timeInterval['2017']['9'] = true;
    $timeInterval['2017']['8'] = true;
    // and so on .....

    foreach ($timeInterval as $thisYear => $yearValue) {
        foreach ($yearValue as $thisMonth => $monthValue) {

            // frontend rendering
            $return[$i]['year'] = $thisYear;
            $return[$i]['month'] = $thisMonth;

            // the logical part
            $return[$i]['registrations'] = $this->getRegistrationsByMonth($thisMonth, $thisYear);
            $return[$i]['total'] = $this->getTotalOfCohortByMonth($thisMonth, $thisYear);
            $return[$i]['totalOrders'] = $this->getTotalOrdersByMonth($thisMonth, $thisYear);

            // define the calculation of week
            $orders = []; // reset array

            // expect something like: $orders['2017']['12']['amount'] => 223.23
            $orders = $this->getOrdersByRegistrationMonth($thisMonth, $thisYear);
            $return[$i]['orders'] = $orders;


            // calculate conversion
            if ($return[$i]['registrations'] == null || $return[$i]['totalOrders'] == null) {
                // prevent division with zero
                $return[$i]['conversion'] = "0%";
            } else {
                // calculate percentage of overall conversion
                $return[$i]['conversion'] = round((float)($return[$i]['totalOrders'] / $return[$i]['registrations']) * 10, 2) . '%';
            }

            // 2. loop: iterate all existing months from time interval
            // fyi: conversions, i = year, j = week
            foreach ($timeInterval as $jYear => $jYearValue) {
                foreach ($jYearValue as $jMonth => $jMonthValue) {
                    # $jYear => 2017 , 2018; $jMonth => 44,45,46,...;

                    $ordersWeekItem = !empty($orders[$jYear][$jMonth]) ? $orders[$jYear][$jMonth] : 0;
                    $return[$i]['calculation'][$jYear][$jMonth]['orders'] = $ordersWeekItem['amount'];

                    // check if there are no conversions
                    if ($return[$i]['registrations'] == null || $ordersWeekItem['amount'] == null) {
                        $conversion = "0%";
                    } else {
                        // calculate percentage of conversion this month
                        $conversion = round((float)($ordersWeekItem['amount'] / $return[$i]['registrations']) * 100, 2) . '%';
                    }

                    // duplicate but neccessary to prevent brainfuck and extend debugging
                    $return[$i]['calculation'][$jYear][$jMonth]['registrations'] = $return[$i]['registrations'];
                    $return[$i]['calculation'][$jYear][$jMonth]['conversions'] = $conversion;
                }
            }

            $i++;
        }
    }
    return $return;
}