Function for setting a streak of strings in a Pandas
For starter, your implementation is too tightly tied to your data, making it not reusable for other kind of dataframe where you would want to count streaks. If you provided a column (pd.Series) to the function instead, it would be much more versatile; allowing calls such as count_streak(df.Artist), count_streak(pd.Series([1, 2, 2, 1, 1, 3]) or even count_streak('abcdccbdddbbbbcaaacbddba').

Doing so, you would remove the need for itertuple and favor regular iteration. This would ease the use of enumerate to check for the previous element:

def count_streak(sequence):
    streaks = []

    for index, element in enumerate(sequence):
        if not index or sequence[index - 1] != element:
            count = 1
        else:
            count += 1
        streaks.append(count)

    return streaks


Much simpler. But this is all without taking into account the wonderful itertools module and its groupby function. It will make group of consecutive data that evaluate equals, yielding both the value, and the entire group. The other advantage being that any iterable will be accepted:

def count_streak(iterable):
    return [
        i for _, g in itertools.groupby(iterable)
        for i, _ in enumerate(g, start=1)
    ]


Since you wish to stay in pandas' world, you also have a groupby method available on DataFrames and Series. But contrary to itertools.groupby that stops at each boundaries, pandas' groupby return all occurences of similar data even if some are discontinuous. But you can make use of cumsum and cumcount to get an equivalent and vectorize these operation instead of a slow python loop. This would require a pandas.Series as parameter, though, not any iterable:

def count_streak(serie):
    return serie.groupby((serie != serie.shift()).cumsum()).cumcount() + 1


usage being

df['Streak'] = count_streak(df.Artist)




And since you commented on performances, here is a small benchmark comparing the approaches. I’ve thrown in a couple extra approaches, out of curiosity. The code to produce the results is:

import pandas as pd
import numpy as np
import timeit

def python_streaks(sequence):
  streaks = []
  for index, element in enumerate(sequence):
    if not index or sequence[index - 1] != element:
      count = 1
    else:
      count += 1
    streaks.append(count)
  return streaks

def python2_streaks(sequence):
  streaks = [1] * len(sequence)
  for index, element in enumerate(sequence):
    if index and sequence[index - 1] == element:
      streaks[index] += streaks[index - 1]
  return streaks

def numpy_streaks(sequence):
  streaks = pd.Series(np.ones(len(sequence), dtype=int))
  for index, element in enumerate(sequence):
    if index and sequence[index - 1] == element:
      streaks[index] += streaks[index - 1]
  return streaks

def itertools_streak(iterable):
  return [
    i for _, g in itertools.groupby(iterable)
    for i, _ in enumerate(g, start=1)
  ]

def pandas_streaks(serie):
  return serie.groupby((serie != serie.shift()).cumsum()).cumcount() + 1

for size in range(8):
  size = 10**size
  for name in ('python', 'python2', 'numpy', 'pandas', 'itertools'):
    setup = 'import pandas as pd;from random import choice;from __main__ import {}_streaks as streaks; df = pd.DataFrame({{"Artist": [choice("abcde") for _ in range({})]}})'.format(name, size)
    elapsed = timeit.timeit('df["Streaks"] = streaks(df.Artist)', setup=setup, number=1000)
    print(name, size, elapsed)


And the results are (I stopped pure Python loops as they were taking too much time):



or, without using log scale on the Y-axis:



So depending on the amount of data you wish to process, either itertools (up to 10000ish elements) or pandas version is better.