Destroy Your Data Using Excel With This One Weird Trick!

All you pie-chart haters are wishing I used one here.

All you pie-chart haters are wishing I used one here.

I often use Twitter as a place to vent about the horribleness of Excel, from the product itself to analyses its UI and workflow influences. Admittedly, some of this is snobbish preference: if everyone use my preferred tools, then the world would be a better place! But let me back off my snobbishness a bit and just say this: please feel free to use any tool you want, up to and including pencil-and-paper…JUST.STOP.USING.EXCEL.

Excel arbitrarily destroys data for fun, as evidenced by the example below.

Who Gives A ‘F’ About Seconds? I’m 10 minutes Late Everywhere!

CSV files have many flaws, but at least they are just plain text. It doesn’t take any special software to read them and you can open and close them without loss of fidelity…except if you open them with Excel.

Suppose you have a CSV file with timestamps in ISO8601 format. Depending on which text editor you use, it might look something like this:

timestamp

Now, let’s open our file in Excel:

excel-dates

The first thing you might notice is that not only does Excel change the date formatting in the file to be more “‘Murican”, they don’t even have the courtesy to use one of their existing date or time formats! And rather than keep the date the way it was, or standardize the dates to the way the rest of the world writes them, or even keep fixed-width columns, Excel feels like it should also hide the seconds! Makes sense…seconds are for other people to see, if/when they highlight an individual cell.

So, you’ve opened this file, but can’t remember if you made any changes outside of applying auto-width to the columns. The data still looks right, so you hit ‘Save’ when prompted by Excel. But you remember that your favorite programmer asked for a CSV file, and it’s already a CSV file, so you hit save, ignore the ‘features’ Excel brags about and email it back to your co-worker. Here’s what they receive:

excel-fidelity-loss

 

Reading this back in our plain-text editor, we can now see we have a loss of fidelity of between 37 and 47 seconds on each cell of data. Whereas Excel keeps track of your timestamps while you’re in a SPREADSHEET, if you save as plain text, Excel assumes you want to keep the format it automatically applied to your data (automatically! silently!), and thus, destroys your file. In what world would you not care about seconds in your timestamps?

Remember, this mis-feature occurs even if the only thing you do is open a plain-text file in Excel and hit save. No other Excel actions are needed to destroy your data.

Excel: Only The Proper Tool If You Don’t Care

If you don’t care about using the proper tool for analytics, don’t want to learn something new, don’t want numerical accuracy, hate visually interesting graphics, don’t need reproducibility…use Excel. For everything else, there’s everything else. Don’t be a VLOOKUP guru, use SQL. Don’t store your data in Excel just because it allows for a million rows, use a database. If you need point-and-click graphics, at least spring for Tableau so the defaults look nicer.

Or, learn to code using open-source languages for a total licensing cost of $0. Every analyst would get value from knowing one open-source analytics language, even topically, so that you can write simple calculation scripts and document your thought process. A side benefit is that by coding, you can also use version control like Git or SVN. Then, you can have different versions of thought, and the next analyst down the line can see how your analysis has evolved.

And while I’m ranting, a special message for all you ‘top-tier’ analytics consultants out there: you should know SEVERAL of the common analytics languages. If you do your “analysis” in Excel, you are a hack or you are just providing reporting for $300/hr. Use better tools, your clients deserve better. I have infinitely more respect for someone who delivers a sloppy set of slides and a documented R script than someone who knows who to put drop-shadows on MS Office documents and makes fancy decks. You are being judged not just by the C-Suite, but also by snobs like me. And when contract renewal time comes around, they do ask my opinion and I do make comments on how sophisticated your toolset was that you used (or lack thereof if you’re using Excel).

It’s nearly 2015, do better. Stop Using Excel.

Code Refactoring Using Metaprogramming

It’s been nearly a year since I wrote Twitter.jl, back when I seemingly had MUCH more free time. In these past 10 months, I’ve used Julia quite a bit to develop other packages, and I try to use it at work when I know I’m not going to be collaborating with others (since my colleagues don’t know Julia, not because it’s bad for collaboration!).

One of the things that’s obvious from my earlier Julia code is that I didn’t understand how powerful metaprogramming can be, so here’s a simple example where I can replace 50 lines of Julia code with 10.

CTRL-A, CTRL-C, CTRL-P. Repeat.

Admittedly, when I started on the Twitter package, I fully meant to go back and clean up the codebase, but moved onto something more fun instead. The Twitter package started out as a means of learning how to use the Requests.jl library to make API calls, figured out the OAuth syntax I needed (which itself should be factored out of Twitter.jl), then copied-and-pasted the same basic function structure over and over. While fast, what I was left with was this (currently, the help.jl file in the Twitter package):It’s pretty clear that this is the same exact code pattern, right down to the spacing! The way to interpret this code is that for these five Twitter API methods, there are no required inputs. Optionally, there is the ‘options’ keyword that allows for specifying a Dict() of options. For these five functions, there are no options you can pass to the Twitter API, so even this keyword is redundant. These are simple functions so I don’t gain a lot by way of maintainability by using metaprogramming, but at the same time, one of the core tenets of programming is ‘Dont Repeat Yourself’, so let’s clean this up.

For :symbol in symbolslist…

In order to clean this up, we need to take out the unique parts of the function, then pass them as arguments to the @eval macro as follows:
What’s happening in this code is that I define two tuples: one of function names (as symbols, denoted by ‘:’ ) and one of the API endpoints. We can then iterate over the two tuples, substituting the function names and endpoints into the code. When the package is loaded, this code evaluates, defining the five functions for use in the Twitter package.

Wha?

Yeah, so metaprogramming can be simple, can it can also be mind-bending. It’s one thing to not repeat yourself, it’s another to write something so complex that even YOU can’t remember how the code works. But somewhere in between lies a sweet spot where you can re-factor whole swaths of code and streamline your codebase.

Metaprogramming is used throughout the Julia codebase, so if you’re interested in seeing more examples of metaprogramming, check out the Julia source code, the Requests.jl package (where I first saw this) or really anyone who actually knows what they are doing. I’m just a metaprogramming pretender at this point :)

 

To read additional discussion around this specific example, see the Julia-Users discussion at:

https://groups.google.com/forum/#!topic/julia-users/zvJmqB2N0GQ

RSiteCatalyst Version 1.4.1 Release Notes

Changes

Version 1.4.1 of RSiteCatalyst is now available on CRAN. There were a handful of bug fixes and new features added, including:

  • Fixed bug in QueueRanked function where only 10 results were returned when requesting multiple element reports. Function now returns up to 50,000 per breakdown (API limit)
  • Created better error message to inform user to login with credentials instead of making function call without proper API credentials
  • Added support for using SAINT classifications in QueueRanked/QueueTrended functions
  • Added more error checking to make functions fail more elegantly
  • Added remaining GET methods from Reporting/Administration API

Additional GET methods

This version of RSiteCatalyst has roughly 20 new GET methods, mostly providing additional report suite information for those who might desire to generate their documentation programmatically rather than manually. New API methods include (but are not limited to):

  • GetMarketingChannelRules: Get a list of all criteria used to build the Marketing Channels report
  • GetReportDescription: For a given bookmark_id, get the report definition
  • GetListVariables: Get a list of the List Variables defined for a report suite
  • GetLogins: Get all logins for a given Company

If you were the type of person who enjoyed this blog post showing how to auto-generate Adobe Analytics documentation, I encourage you to take a look at these newly incorporated functions and use them to improve your documentation even further.

Feature Requests/Bugs

If you come across any bugs, or have any feature requests, please continue to use the RSiteCatalyst GitHub Issues page to make tickets. While I’ve responded to many of you via the maintainer email provided in the R package itself, it’s much more efficient (and you’re much more likely to get a response) if you use the GitHub Issues page. Don’t worry about cluttering up the page with tickets, please fill out a new issue for anything you encounter, unless you are SURE that it is the same problem someone else is facing.

And finally, like I end every blog post about RSiteCatalyst, please note that I’m not an Adobe employee. Please don’t send me your API credentials, expect immediate replies or ask to set up phone calls to troubleshoot your problems. This is open-source software…Willem Paling and I did the hard part writing it, you’re expected to support yourself as best as possible unless you believe you’re encountering a bug. Then use GitHub :)

Declaring Twitter Bankruptcy

Maybe I don’t have enough to do today, or a long day of vendor calls has made me re-evaluate what I’m doing with my life, but I had a thought:

I started on Twitter in December 2009. Quite ironically from where I sit now, I think I joined Twitter because I was an Omniture/Adobe Analytics newcomer, and probably searched Google for some term I didn’t understand. I eventually realized that people were talking about digital analytics on Twitter, so I created an account. Now, of course, I would imagine many would consider me an Adobe Analytics expert, at least in the case of the API and data feeds. And I now use Twitter way differently than I used to.

Since 2009, I’ve gone from banking and a beginner at digital analytics, to a working at an agency on helping them with Omniture, to being a digital analytics consultant at a specialty firm, to a start-up that didn’t work out, to a gigantic media company. I also pretty much never think about ‘web’ analytics, except for the fact that I created and maintain a very specialized R package that maybe a few hundred people in the world use (if I’m lucky).

When we graduate from high school, then college, get married, the natural progression is that people come into your life and some fall out. But Twitter has a sort of hoarder quality to it. Some people cull their follower list, because they don’t like what the person tweets about or they get in stupid Twitter feuds, but for the most part the list just builds and builds. Others stop using Twitter and you never hear from them again, but you still follow them (their silence?). But it occurs to me, this seems at least tangentially like the Abilene Paradox: at some point, you arrive at a place and you don’t know how you got there. What have I done over the past five years that has lead me to this place where I’m reading about what I do on Twitter?

So I’m going to conduct an experiment. I’m unfollowing all of you without prejudice. Just as if I had a hard drive crash. And I’m going to re-follow all the people I can remember, then re-discover what I’m really interested in getting from Twitter as a platform by re-following friends of friends, people saying interesting things on hashtags, etc. Hope none of you are hurt by my unfollows, but then again, if you are then maybe that says something about what kind of relationship we currently have.

Evaluating BreakoutDetection

A couple of weeks ago, Twitter open-sourced their BreakoutDetection package for R, a package designed to determine shifts in time-series data. The Twitter announcement does a great job of explaining the main technique for detection (E-Divisive with Medians), so I won’t rehash that material here. Rather, I wanted to see how this package works relative to the anomaly detection feature in the Adobe Analytics API, which I’ve written about previously.

Getting Time-Series Data Using RSiteCatalyst

To use a real-world dataset to evaluate this package, I’m going to use roughly ten months of daily pageviews generated from my blog. The hypothesis here is that if the BreakoutDetection package works well, it should be able to detect the boundaries around when I publish a blog post (of which the dates I know with certainty) and when articles of mine get shared on sites such as Reddit. From past experience, I get about a 3-day lift in pageviews post-publishing, as the article gets tweeted out, published on R-Bloggers or JuliaBloggers and shared accordingly.

Here’s the code to get daily pageviews using RSiteCatalyst (Adobe Analytics):One thing to notice here is that BreakoutDetection requires either a single R vector or a specifically formatted data frame. In this case, because I have a timestamp, I use lines 17-18 to get the data into the required format.

BreakoutDetection – Default Example

In the Twitter announcement, they provide an example, so let’s evaluate those defaults first:

breakoutdetection-defaults

In order to validate my hypothesis, the package would need to detect 12 ‘breakouts’ or so, as I’ve published 12 blog posts during the sample time period. Mentally drawing lines between the red boundaries, we can see three definitive upward mean shifts, but far fewer than the 12 I expected.

BreakoutDetection – Modifying The Parameters

Given that the chart above doesn’t fit how I think my data are generated, we can modify two main parameters: beta and min.size. From the documentation:

  • beta: A real numbered constant used to further control the amount of penalization. This is the default form of penalization, if neither (or both) beta or (and) percent are supplied this argument will be used. The default value is beta=0.008.
  • min.size:  The minimum number of observations between change points

The first parameter I’m going to experiment with is min.size, because it requires no in-depth knowledge of the EDM technique! The value used in the first example was 24 (days) between intervals, which seems extreme in my case. It’s reasonable that I might publish a blog post per week, so let’s back that number down to 5 and see how the result changes:breakout-5

With 17 predicted intervals, we’ve somewhat overshot the number of blog posts mark. Not that the package is wrong per se; the boundaries are surrounding many of the spikes in the data, but perhaps having this many breakpoints isn’t useful from a monitoring standpoint. So setting the min.size parameter somewhere between 5 and 24 points would give us more than 3 breakouts, but less than 17. There is also the beta parameter that can be played with, but I’ll leave that as an exercise for another day.

Anomaly Detection – Adobe Analytics

From my prior post about Anomaly Detection with the Adobe Analytics API, Adobe has chosen to use Holt-Winters/Exponential Smoothing as their technique. Here’s what that looks like for the same time-period (code as GitHub Gist):

adobe_analytics

Even though the idea of both techniques are similar, it’s clear that the two methods don’t quite represent the same thing. In the case of the Adobe Analytics Anomaly Detection, it’s looking datapoint-by-datapoint, with a smoothing model built from the prior 35 points. If a point exceeds the upper- or lower-control limits, then it’s an anomaly, but not necessarily indicative of a true level shift like the BreakoutDetection package is measuring.

Conclusion

The BreakoutDetection package is definitely cool, but it is a bit raw, especially the default graphics. But the package definitely does work, as evidenced by how well it put boundaries around the traffic spikes when I set the min.size parameter equal to five.

Additionally, I tried to read more about the underlying methodology, but the only references that come up in Google seem to be references to the R package itself! I wish I had a better feeling for how the beta parameter influences the graph, but I guess that will come over time as I use the package more.  But I’m definitely glad that Twitter open-sourced this package, as I’ve often wondered about how to detect level shifts in a more operational setting, and now I have a method to do so.