Understanding Taylor Swift with Python

Here are the complete lyrics of Taylor Swift’s “Shake it off”, in the form of a Python string

shakeItOffComplete = """
I stay out too late
Got nothing in my brain
That's what people say, mm, mm
That's what people say, mm, mm
I go on too many dates
But I can't make them stay
At least that's what people say, mm, mm
That's what people say, mm, mm

But I keep cruisin'
Can't stop, won't stop movin'/groovin'
It's like I got this music in my mind
Saying it's gonna be alright

'Cause the players gonna play, play, play, play, play, 
And the haters gonna hate, hate, hate, hate, hate, 
Baby, I'm just gonna shake, shake, shake, shake, shake, 
I shake it off, I shake it off
Heartbreakers gonna break, break, break, break, break, 
And the fakers gonna fake, fake, fake, fake, fake, 
Baby, I'm just gonna shake, shake, shake, shake, shake, 
I shake it off, I shake it off

I never miss a beat
I'm lightning on my feet
And that's what they don’t see, mm, mm
That's what they don’t see, mm, mm
I'm dancing on my own (dancing on my own)
I make the moves up as I go (moves up as I go)
And that's what they don't know, mm, mm
That’s what they don’t know, mm, mm

But I keep cruisin'
Can't stop, won't stop movin'/groovin'
It's like I got this music in my mind
Saying it's gonna be alright

'Cause the players gonna play, play, play, play, play, 
And the haters gonna hate, hate, hate, hate, hate, 
Baby, I'm just gonna shake, shake, shake, shake, shake, 
I shake it off, I shake it off
Heartbreakers gonna break, break, break, break, break, 
And the fakers gonna fake, fake, fake, fake, fake, 
Baby, I'm just gonna shake, shake, shake, shake, shake, 
I shake it off, I shake it off

Shake it off, I shake it off
I, I, I shake it off, I shake it off
I, I, I shake it off, I shake it off
I, I, I shake it off, I shake it off

Hey, hey, hey
Just think while you've been getting down and out about the liars
And the dirty, dirty cheats of the world
You could've been getting down
To this sick beat

My ex-man brought his new girlfriend
She's like, “Oh my God,” but I'm just gonna shake
And to the fella over there with the hella good hair
Won't you come on over, baby?
We can shake, shake, shake
Yeah, oh, oh, oh

'Cause the players gonna play, play, play, play, play, 
And the haters gonna hate, hate, hate, hate, hate, 
Baby, I'm just gonna shake, shake, shake, shake, shake, 
I shake it off, I shake it off
Heartbreakers gonna break, break, break, break, break, 
And the fakers gonna fake, fake, fake, fake, fake, 
Baby, I'm just gonna shake, shake, shake, shake, shake, 
I shake it off, I shake it off

Shake it off, I shake it off
I, I, I shake it off, I shake it off
I, I, I shake it off, I shake it off
I, I, I shake it off, I shake it off

Shake it off, I shake it off
I, I, I shake it off, I shake it off
I, I, I shake it off, I shake it off
I, I, I shake it off, I shake it off

Shake it off, I shake it off
I, I, I shake it off, I shake it off
I, I, I shake it off, I shake it off
I, I, I shake it off, I shake it off
"""
print( type(shakeItOffComplete))

By representing it in Python we can learn about the formulae underlying pop music. Let’s break it up into parts to see how it is structured.

verse1 = """
I stay out too late
Got nothing in my brain
That's what people say, mm, mm
That's what people say, mm, mm
I go on too many dates
But I can't make them stay
At least that's what people say, mm, mm
That's what people say, mm, mm
"""

prechorus = """
But I keep cruisin'
Can't stop, won't stop movin'/groovin'
It's like I got this music in my mind
Saying it's gonna be alright
"""

chorus = """
'Cause the players gonna play, play, play, play, play, 
And the haters gonna hate, hate, hate, hate, hate, 
Baby, I'm just gonna shake, shake, shake, shake, shake, 
I shake it off, I shake it off
Heartbreakers gonna break, break, break, break, break, 
And the fakers gonna fake, fake, fake, fake, fake, 
Baby, I'm just gonna shake, shake, shake, shake, shake, 
I shake it off, I shake it off
"""

verse2 = """
I never miss a beat
I'm lightning on my feet
And that's what they don’t see, mm, mm
That's what they don’t see, mm, mm
I'm dancing on my own (dancing on my own)
I make the moves up as I go (moves up as I go)
And that's what they don't know, mm, mm
That’s what they don’t know, mm, mm
"""

postchorus = """
Shake it off, I shake it off
I, I, I shake it off, I shake it off
I, I, I shake it off, I shake it off
I, I, I shake it off, I shake it off
"""

interlude = """
Hey, hey, hey
Just think while you've been getting down and out about the liars
And the dirty, dirty cheats of the world
You could've been getting down
To this sick beat
"""

bridge = """
My ex-man brought his new girlfriend
She's like, “Oh my God,” but I'm just gonna shake
And to the fella over there with the hella good hair
Won't you come on over, baby?
We can shake, shake, shake
Yeah, oh, oh, oh
"""

With those parts, the variables verse1, verse2, prechorus, chorus, postchorus, interlude, and bridge we can see how “Shake it off” is structured (and also represent it with a lot less typing).

shakeItOffReconstructed = (verse1 +   # (it's ok to stretch expressions over several lines. It can help readabiilty)
                          prechorus + 
                          chorus + 
                          verse2 + 
                          prechorus + 
                          chorus + 
                          postchorus + 
                          interlude + 
                          bridge + 
                          chorus + 
                          postchorus * 3 )  # repeats three times
#print( shakeItOffReconstructed )

Is it really that simple? Let’s test and see if these strings are the same.

shakeItOffComplete == shakeItOffReconstructed

Verse-level representation

That’s some nice compression, but we can do better. There is a lot of repetition all over the song that we can capture in variables and chunk down. For example, the “mm, mm”s and “That’s what people say”‘s in the verses could be chunked down. But the most redundancy in any pop song is going to be the in the chorus and, in this song, especially the post-chorus. Let’s see if we can rewrite them into a more compact form.

### Original
chorus = """
'Cause the players gonna play, play, play, play, play, 
And the haters gonna hate, hate, hate, hate, hate, 
Baby, I'm just gonna shake, shake, shake, shake, shake, 
I shake it off, I shake it off
Heartbreakers gonna break, break, break, break, break, 
And the fakers gonna fake, fake, fake, fake, fake, 
Baby, I'm just gonna shake, shake, shake, shake, shake, 
I shake it off, I shake it off
"""

### Refrain
shk = 'I shake it off'   # this gets used a lot, so it gets a variable 

### Replacement
chorusReconstructed = """
'Cause the players gonna {}
And the haters gonna {}
Baby, I'm just gonna {}
{}, {}
Heartbreakers gonna {}
And the fakers gonna {}
Baby, I'm just gonna {}
{}, {}
""".format('play, ' * 5, 
           'hate, ' * 5, 
           'shake, ' * 5, 
           shk, shk, 
           'break, ' * 5, 
           'fake, ' * 5, 
           'shake, ' * 5, 
           shk, shk)

#print( chorusReconstructed)

### Test for success
chorus == chorusReconstructed

The new chorus is identical content, typed in about half as many characters. That means that, in some sense, about half the chorus of “Shake it off” is redundant.

How about the post-chorus? We’ve already defined placeholder variable shk, which it looks like we’ll keep using.

### Original
postchorus = """
Shake it off, I shake it off
I, I, I shake it off, I shake it off
I, I, I shake it off, I shake it off
I, I, I shake it off, I shake it off
"""

### Replacement
postchorusReconstructed = """
Shake it off, {}
I, I, {}, {}
I, I, {}, {}
I, I, {}, {}
""".format( shk, shk, shk, shk, shk, shk, shk )

### Better replacement
###    (observe above that most shk's are repeated twice.
###     We can use that to get a bit more compression)
shk2 = shk + ', ' + shk
postchorusReconstructed2 = """
Shake it off, {}
I, I, {}
I, I, {}
I, I, {}
""".format( shk, shk2, shk2, shk2 )

### Even better replacement
###    (observe above that most shk's are preceded by a comma and a space.
###     We can use that too)
cshk = ', ' + shk   
shk2 = cshk + cshk
postchorusReconstructed3 = """
Shake it off{}
I, I{}
I, I{}
I, I{}
""".format( cshk, shk2, shk2, shk2 )


### Too far?
i = 'I, I'
shk2 = i + cshk + cshk
postchorusReconstructed3 = """
Shake it off{}
{}
{}
{}
""".format( cshk, shk2, shk2, shk2 )

### Test for success
postchorus == postchorusReconstructed3

We’ve reduced postchorus to almost a third of the size. Add to that that the final post-chorus of the song repeats postchorus three times, and that’s a total reduction of about nine times. In other words, from an informational standpoint, the last 20% of the song is 90% redundant.

### The last 20% (40 seconds) of "Shake it off" in one line
###  "\n" is the character representation of the line break/return key
print( ( ('Shake it off' + cshk + ('\n' + shk2) * 3 ) + '\n' ) * 3 )

Of course, it’s really not fair to evaluate music from an informational standpoint. There are other standpoints that make sense for music. Nevertheless this exercise does do something useful for us. Breaking a thing down into parts—”ana-lysis”—teaches us about a thing by showing us its natural faultlines, and revealing the formula behind it. And it’s just that kind of breaking-things-down that programming makes you good at.

If you end up analyzing another song this way, let me know!

FYI, this is an excerpt from a lesson out of my Python course at UC Davis and on Coursera.