{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Analyzing Murdock (1962) Free Recall Data\n", "\n", "This tutorial demonstrates analyzing the classic Murdock (1962) free recall dataset, which established the serial position effect as a fundamental phenomenon in memory research.\n", "\n", "The dataset contains 90 subjects (15 per condition) across 6 experimental conditions varying in list length (10, 15, 20, 30, or 40 items) and presentation rate (1 or 2 sec/item). Each subject completed 80 lists.\n", "\n", "**Conditions:**\n", "- LL10-2s: 10 items, 2 sec/item (15 subjects, 80 lists each)\n", "- LL15-2s: 15 items, 2 sec/item (15 subjects, 80 lists each)\n", "- LL20-1s: 20 items, 1 sec/item (15 subjects, 80 lists each)\n", "- LL20-2s: 20 items, 2 sec/item (15 subjects, 80 lists each)\n", "- LL30-1s: 30 items, 1 sec/item (15 subjects, 80 lists each)\n", "- LL40-1s: 40 items, 1 sec/item (15 subjects, 80 lists each)\n", "\n", "We'll analyze recall performance using:\n", "1. Probability of First Recall (PFR) - probability of recalling each position first\n", "2. Lag-CRP - conditional recall probability by temporal lag\n", "3. Serial Position Curve (SPC) - recall probability by encoding position\n", "\n", "**Reference:**\n", "Murdock, B. B. (1962). The serial position effect of free recall. *Journal of Experimental Psychology*, 64(5), 482-488. https://doi.org/10.1037/h0045106" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import quail\n", "import matplotlib.pyplot as plt\n", "import warnings\n", "\n", "# Suppress RuntimeWarnings about empty slices\n", "warnings.filterwarnings('ignore', category=RuntimeWarning)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Load the dataset\n", "\n", "The Murdock 1962 dataset is included with quail and can be loaded using `load_example_data()`." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Load the Murdock 1962 dataset\n", "egg = quail.load_example_data('murd62')\n", "\n", "print(f\"Loaded Murdock 1962 data: {egg.n_subjects} subjects, {egg.n_lists} lists per subject\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Set up subject groupings\n", "\n", "Since each subject belongs to a single condition, we create a `subjgroup` list that maps each subject to their condition. This allows us to plot separate curves for each condition." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Build subjgroup: map each subject index to its condition name\n", "subjgroup = []\n", "for subj_idx in range(egg.n_subjects):\n", " try:\n", " sample = egg.pres.loc[(subj_idx, 0)][0]\n", " if sample and 'condition' in sample:\n", " subjgroup.append(sample['condition'])\n", " else:\n", " subjgroup.append('Unknown')\n", " except (KeyError, IndexError, TypeError):\n", " subjgroup.append('Unknown')\n", "\n", "print(f\"Subject conditions: {len(set(subjgroup))} unique conditions\")\n", "\n", "# Create listgroup for averaging across lists within each subject\n", "listgroup = ['average'] * egg.n_lists" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Analyze and plot\n", "\n", "We'll create three plots showing key memory phenomena:\n", "- **PFR**: Shows the primacy effect - items at the beginning of a list are more likely to be recalled first\n", "- **Lag-CRP**: Shows temporal contiguity - items studied close together are likely to be recalled together\n", "- **SPC**: Shows the classic serial position curve with primacy and recency effects" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Create figure with 3 subplots in order: PFR, Lag-CRP, SPC\n", "fig, axes = plt.subplots(1, 3, figsize=(15, 5))\n", "\n", "# 1. Probability of First Recall - use quail's built-in plot with error bars\n", "pfr = egg.analyze('pfr', listgroup=listgroup)\n", "pfr.plot(ax=axes[0], subjgroup=subjgroup, plot_type='subject', legend=True)\n", "\n", "# 2. Lag-CRP - use quail's built-in plot with error bars (legend=False)\n", "lagcrp = egg.analyze('lagcrp', listgroup=listgroup)\n", "lagcrp.plot(ax=axes[1], subjgroup=subjgroup, plot_type='subject', legend=False)\n", "\n", "# 3. Serial Position Curve - use quail's built-in plot with error bars (legend=False)\n", "spc = egg.analyze('spc', listgroup=listgroup)\n", "spc.plot(ax=axes[2], subjgroup=subjgroup, plot_type='subject', legend=False)\n", "\n", "# Configure PFR plot\n", "axes[0].set_title('Probability of First Recall')\n", "axes[0].set_xlabel('Serial Position')\n", "axes[0].set_ylabel('Probability')\n", "axes[0].set_ylim([0, 0.6])\n", "\n", "# Configure Lag-CRP plot\n", "axes[1].set_title('Lag-CRP')\n", "axes[1].set_xlabel('Lag')\n", "axes[1].set_ylabel('Conditional Recall Probability')\n", "axes[1].set_xlim([-10, 10])\n", "axes[1].set_ylim([0, 0.5])\n", "axes[1].axvline(x=0, color='gray', linestyle='--', alpha=0.5)\n", "\n", "# Configure SPC plot\n", "axes[2].set_title('Serial Position Curve')\n", "axes[2].set_xlabel('Serial Position')\n", "axes[2].set_ylabel('Recall Probability')\n", "axes[2].set_ylim([0, 1])\n", "\n", "plt.tight_layout()\n", "plt.suptitle('Murdock (1962) Free Recall Data', y=1.02, fontsize=14)\n", "plt.show()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Key findings\n", "\n", "The plots reveal several classic memory phenomena:\n", "\n", "1. **Primacy Effect**: Items at the beginning of the list are recalled more often (visible in SPC)\n", "2. **Recency Effect**: Items at the end of the list are recalled more often (visible in SPC)\n", "3. **Temporal Contiguity**: Items studied nearby in time tend to be recalled together (visible in Lag-CRP asymmetry toward +1 lag)\n", "4. **List Length Effects**: Longer lists show lower overall recall probability but similar curve shapes" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "name": "python", "version": "3.8.0" } }, "nbformat": 4, "nbformat_minor": 4 }