#16/25: Web Site Measurement Hacks

Funny how a major economic downturn and the enforcement of fiscal responsibility will motivate people to make decisions based on available data, not just their gut instinct.

Customer intent

  • Explicitly
    • Landing page survey: What are you trying achieve today?
    • On exit survey: Did you successfully achieve what you wanted to do?
  • Implicity
    • Obvious intent: ordering something, etc.
    • Otherwise Keywords

Data Integration

  • Marketing cost => campaign ROI
  • Customer Satisfaction data
  • Email campaigns

Try to apply analytics to your intranet

  • How much do you save using this?
  • Adaption
  • Most frequent pages

Look at

  • Broken links
  • 404s
  • Failures to respond

Start with your business objective (macroconversion) and try to generate micro-conversions

Email Marketing

  • Hard Bounces – message not delivered
  • Opening rate
  • CTR
  • Unsubscribes
  • Landing page stickiness – do they keep moving or do the CTA?

Email Testing

  • Layout
  • Format – HTML, text, rich text
  • Length
  • Tone
  • Date
  • Return email address
  • Subject line
  • CTA

When you segment by traffic, you can do something

Scent trails

  • create persona
  • Use the right language
  • build rapport by relevant copy and addressing issues
  • present relevant solutions

Measuring the internal search engine

  • Percentage of exits from the search page
  • Usage for conversions
  • Percentage with no results
  • Top search terms

Measure Recency and Latency

  • Recency – When was the last time the visitor/customer visited your site
  • Latency – Time between different visits
  • Segment into above and below average
  • Helps you to estimate future earnings

Test offline campaign – geographic segmentation

  • Control group
  • Treatment group

KPIs for Online Retail

  • AOV
  • Order Conversion Rate
  • Funnel analysis
  • Visits under 90 seconds

KPIs for Content sites

  • Average pages per visit
  • Average visits per visitor
  • Average time on site
  • Visits with over 5-10 page views

KPIs for Lead Generation Sites

  • Average hours to response

Okay book. It’s a rather outdated but may be interesting if you want to know more about the development of web tracking systems.

#90/111: The C Programming Language

Basics, basics, basics. You could call K&R’s book one basic book which every programmer should read. Nowadays lots of new programmers think that Ruby on Rails is all you need. If you just build basic CRUD web apps this is probably true. However, if you want to understand what’s really going on in your web server, operation system or music player, you should know C. K&R isn’t a introduction course into C programming but it will help you to get better at it, if you have some experience in C / programming.

I really love this book, mostly for its cool exercises (implementing tail, memory management, etc.). Always a recommendation!

Concrete Abstractions: Chapter 12

Exercise 12.4: Draw a tree, analogous to Figure 4.4 on page 92, showing how the value of C(4, 2) is computed by choose. Your tree should have C(4, 2) at the root and six 1s as its leaves.
Solution:

Exercise 12.6: Using these procedures, write
a. A procedure called table-fill! that takes a table and an element and sets every entry in the table to the given element. For example, (table-fill! table 0) would have a similar effect to that of zero-out-vector! in Section 11.6.
b. A procedure called display-table that nicely displays its table parameter.

Solution:

(define table-fill!
  (lambda (table value)
    (define loop-row
      (lambda (row column)
        (if (= column (table-width table))
            'done
            (begin
              (table-set! table row column value)
              (loop-row row (+ column 1))))))
    (define loop
      (lambda (row)
        (if (= row (table-height table))
            'done
            (begin
              (loop-row row 0)
              (loop (+ row 1))))))
    (loop 0)))

b.

(define display-table
  (lambda (table)
    (define show-row
      (lambda (row column)
        (if (= column (table-width table))
            (newline)
            (begin
              (display (table-ref table row column))
              (display " ")
              (show-row row (+ column 1))))))
    (define show
      (lambda (row)
        (if (= row (table-height table))
            (newline)
            (begin
              (show-row row 0)
              (show (+ row 1))))))
    (show 0)))

Exercise 12.31: Imagine the following game: You are given a path that consists of white and black squares. The exact configuration of white and black squares varies with the game. You start on the leftmost square (which we’ll call square 0), and your goal is to move off the right end of the path in the least number of moves. However, the rules stipulate that:
If you are on a white square, you can move either 1 or 2 squares to the right.
If you are on a black square, you can move either 1 or 4 squares to the right. […]
Write a memoized version of fewest-moves.
Solution:

(define fewest-moves-mem
  (lambda (path)
    (let ((table (make-vector (vector-length path))))
      (define fewest-moves-f
        (lambda (path i)
          (cond ((>= i (vector-length path))
                 0)
                ((equal? (vector-ref path i) 'white)
                 (+ 1 (min (fewest-moves-sub path (+ i 1))
                           (fewest-moves-sub path (+ i 2)))))
                (else
                 (+ 1 (min (fewest-moves-sub path (+ i 1))
                           (fewest-moves-sub path (+ i 4))))))))

      (define fewest-moves-sub
        (lambda (path i)
          (ensure-in-table! path i)
          (vector-ref table i)))

      (define ensure-in-table!
        (lambda (path i)
          (if (vector-ref table i)
              'done
              (store-in-table! table i))))

      (define store-in-table!
        (lambda (table i)
          (vector-set! table i (fewest-moves path i))))

      (vector-fill! table #f)

      (fewest-moves-f path 0))))

Exercise 12.33: The function h(n) is defined for nonnegative integers n as follows:
h(n) = \begin{cases} 1 & \text{ if } n<2\\ h(n-1) + h(n-2) & \text{ if n } < \text{2 and n is odd}\\ h(n-1) + h(n/2) & \text{ if n } \geq \text{2 and n is even}\\ \end{cases}
a. Write a dynamic programming procedure for efficiently calculating h(n).
b. Is it possible to modify the procedure so that it stores all the values it needs in a vector of fixed size, as walk-count can be modified to store the values it needs in a two-element vector? (A vector of “fixed size” is one with a size that does not depend on the parameter, n.) Justify your answer.
Solution: a & b. I implemented b directly into the code.

(define h
  (lambda (n)
    (let ((vector (make-vector (+ n 1))))
      (define calc-h
        (lambda (n)
          (cond ((< n 2) 1)
                ((odd? n) (+
                           (calc-h-sub (- n 1))
                           (calc-h-sub (- n 2))))
                (else (+
                       (calc-h-sub (- n 1))
                       (calc-h-sub (/ n 2)))))))

      (define calc-h-sub
        (lambda (n)
          (vector-ref vector n)))

      (from-to-do 0 n
                  (lambda (i)
                    (vector-set! vector i (calc-h i))))

      (calc-h n))))

SPOJ: 8132. Street Trees

A group of trees is planted along a straight line.

KOI is planning to plant more trees so that the distance between two adjacent trees is equal for all trees.

For simplicity, each tree can only be planted on an integer coordinate.

Problem: Sphere Online Judge (SPOJ) – Problem STREETR

Solution:
To illustrate this problem I drew this small graphic:

The large trees are given and we have to find the small ones. You can see pretty fast that the maximum difference between trees is the minimum difference between already planted trees. But we’re not only looking for one arbitrary solution (which would be zero difference), we’re looking for the greatest difference or more generally the Greatest common divisor.

def gcd(a, b):
    if b == 0:
        return a
    else:
        return gcd(b, a % b)


def gcdList(lst):
    myGcd = gcd(lst[0], lst[1])
    for c in lst[1:]:
        myGcd = gcd(myGcd, c)

    return myGcd

N = int(raw_input())
diff = []
lastTree = int(raw_input())
for i in xrange(1, N):
    newTree = int(raw_input())
    diff.append(newTree - lastTree)
    lastTree = newTree

myGcd = gcdList(diff)

trees = map(lambda x: (x / myGcd) - 1, diff)
print sum(trees)