WHAT IS TEHILLIM?

King David’s 150-chapter book of Tehillim (Psalms) is one of the Books of the Tanakh. A collection of songs of praise to Hashem, songs that arise from the soul of a person at different stages and in different situations in life.

Tehillim has an awesome power that is inherent in the words itself and one who reads the books of Tanach without understanding their contents has nevertheless fulfilled his obligation to study Torah.

— Shulchan Aruch Adhaz, Talmud Torah 2:12

One way of reading Tehillim is by a division of the monthly cycle, in which only a few chapters are read each day and the entire book of Tehillim is completed on the final day of each Jewish month. For example on the first day of the month one would read chapters 1-9 and then on the next day chapters 10-17. This is a practice I have been doing for over a year and have noticed that the start of the month takes longer than the rest of the month, so I decided to write some code to look into this.

If people only knew the power concealed in the combinations of the letters of the Torah, every single Jew would strive to become an expert in the words of Torah and Tehillim!

— Baal Shem Tov

We are going to grab the Tehillim text from Sefaria for both the Hebrew and English, and found that Sefaria-Data’s github has a psalms 30 day cycle csv that is going to be really useful in finding the break in days.

#imports

import pandas as pd
import numpy as np
import plotly.express as px
import re
import io

# Data sources

df = pd.read_csv('https://www.sefaria.org/download/version/Psalms%20-%20he%20-%20Tanach%20with%20Text%20Only.csv', skiprows=4)
engdf = pd.read_csv('https://www.sefaria.org/download/version/Psalms%20-%20en%20-%20merged.csv', skiprows=4)
cycle = pd.read_csv('https://raw.githubusercontent.com/Sefaria/Sefaria-Data/8df479a24eab50336dee30f05db86ea97edcf530/misc/psalms_30_day_cycle.csv')

After looking at the dataframe, we need to split up the “version notes” to chapter and verse by splitting on : and then using regex to just keep the numeric values, and rename the columns.

df[['chapter', 'verse']] = df['Version Notes'].str.split(':', 1, expand=True)
df['chapter'] = df['chapter'].str.replace(r'[^0-9]+', '')
df.rename(columns={'Version Notes': 'section', 'Unnamed: 1': 'text'}, inplace=True)
df['word_count'] = df['text'].str.split().str.len()

We are ready to look at the cycle data 

Exploding the cycle

In my earlier years I would have taken this to Excel and used a formula to fill in blank cells with value above, we can keep this all in python with the help of the explode function in pandas; Transform each element of a list-like to a row, replicating index values.

cycle[['start', 'end']] = cycle['Ref'].str.split('-', 1, expand=True)
cycle['start'] = cycle['start'].str.replace(r'[^0-9]+', '')

cycle.loc[cycle['Day'] == 25, 'start'] = 1
cycle.loc[cycle['Day'] == 26, 'start'] = 97
condition = cycle['Ref'].str.startswith('Psalm 119')
ch119 = cycle[condition]

cycle = cycle.loc[~condition].reset_index(drop=True)
cycle['start'] = cycle['start'].astype(int)
cycle['end'] = cycle['end'].astype(int)

new_cycle = cycle.assign(range=lambda x: x.apply(lambda row: range(row['start'], row['end']+1), axis=1)).explode('range').reset_index(drop=True)
new_cycle = new_cycle.rename(columns={'range': 'chapter'})
new_cycle.head(10)

King David asked of G-d: Please, when they recite Psalms, they should get rewarded as if they were studying the complex sections of law, those dealing with leprosy and impurity imparted through a tent.

– Midrash Tehillim 61

We now have a dataframe that has the chapters with the day and chapter columns we need for the join.

new_cycle['chapter'] = new_cycle['chapter'].astype(int)
df['chapter'] = df['chapter'].astype(int)
merged = df.merge(new_cycle, how='left', on='chapter')
merged.head(10)

Chapter 119 is a little different as one chapter is split by verse not chapter for days 25 and 26

condition = merged['section'].str.startswith('Psalms 119')
merged['chapter'] = merged['chapter'].astype(int)
merged['verse'] = merged['verse'].astype(int)
merged.loc[(merged['chapter'] == 119) & (merged['verse'] <= 96), 'Day'] = 25.0 merged.loc[(merged['chapter'] == 119) & (merged['verse'] > 97), 'Day'] = 26.0

Plotly Charts

Once that is completed we can start doing a group by to get the sums by day, and using Plotly express chart them

ndf = merged.groupby(['chapter', 'Day']).agg({'word_count': 'sum'}).reset_index()
fig = px.bar(ndf,x='chapter', y='word_count', color='Day')
fig.show()

We can now see the word count per chapter of Tehillim, with the known outlier of Chapter 119 being the longest.

We can then group by the Day of the month and color code by word_count to see the difference as the month goes on.

xdf = merged.groupby(['Day']).agg({'word_count': 'sum'}).reset_index()

xdf['Day'] = xdf['Day'].astype(int)
xdf['word_count'] = xdf['word_count'].astype(int) 

fig = px.bar(xdf,x='Day', y='word_count', color='word_count')
fig.update_yaxes(range=[0, 1000])
fig.show()

We can confirm my hunch that the first week of the month has the longest reading based on word count and then starts to get shorter with the 16th day a word count of 460 being less than half of the 3rd days 952.

If you crave to be connected to G-d, then be connected with the book of Psalms

— Shaloh, vol. 3, inyan Tefilah V’Krias Hatorah, 21d

The longer portion of Tehillim during the first days of the month reminds us of the importance of starting each new cycle with intention and reflection.

Link to Colab Notebook Py_Psalms.ipynb

Selected Quotes from Chayenu introduces Tehillim