Skip to main content

What you’ll learn

In this tutorial, you’ll learn how to use the crosswalk data in Knowledge Graph to compare standards between the Common Core State Standards (CCSSM) and state frameworks. These crosswalks can help you determine which state standards are most similar to a given CCSSM standard and understand the similarities and differences between the standards. Crosswalks are evidence-based relationships between state standards and CCSSM standards, derived from overlapping sets of Learning Components (LCs). Each crosswalk includes similarity metrics, such as the Jaccard score and relative LC counts, to help you interpret how closely two standards align. You can read more about how crosswalks are calculated here. This tutorial walks through how to:
  • Load and explore crosswalk data in therelationships.csv file.
  • Identify the closest state standards for a given CCSSM standard (focusing on Texas).
  • Interpret alignment strength using Jaccard and LC counts.
  • Join crosswalk data with standards metadata to view results.
  • Join crosswalk pairs to Learning Components to inspect the shared skills that support each alignment

What you’ll need

  • This tutorial assumes you’ve downloaded Knowledge Graph already. If you haven’t please see download instructions.
  • This tutorial utilizes crosswalks, specifically the Jaccard index. For more information, please read here.
  • You can use either Node or Python to go through this tutorial
  • If using Node
    • node 14+
    • arquero
    • csv-parse
  • If using Python
    • python 3.9+
    • pandas

Step 1: Load the Crosswalk Data

Crosswalk data lives in the relationships.csv. The standards that have crosswalk data will include the four new crosswalk-specific columns.
PropertyDescription
jaccardProportion of shared LCs between state and CCSS standards (0 < jaccard ≤ 1).
stateLCCountNumber of Learning Components supporting the state standard.
ccssLCCountNumber of Learning Components supporting the CCSS standard.
sharedLCCountNumber of Learning Components shared by both standards.
// Load CSV files
const relationshipsData = aq.from(loadCSV('Relationships.csv'));
const standardsFrameworkItemsData = aq.from(loadCSV('StandardsFrameworkItem.csv'));
const learningComponentsData = aq.from(loadCSV('LearningComponent.csv'));

console.log('✅ Data loaded from KG CSV files');
console.log(`  Total Relationships: ${relationshipsData.numRows()}`);
console.log(`  Standards Framework Items: ${standardsFrameworkItemsData.numRows()}`);
console.log(`  Learning Components: ${learningComponentsData.numRows()}`);

// Filter for crosswalk relationships (hasStandardAlignment)
const crosswalkData = relationshipsData
  .filter(d => d.relationshipType === 'hasStandardAlignment');

console.log(`\n✅ Crosswalk data filtered:`);
console.log(`  Total crosswalk relationships (state → CCSSM): ${crosswalkData.numRows()}`);

// Show preview of crosswalk data
if (crosswalkData.numRows() > 0) {
  console.log(`\n📊 Preview of crosswalk data (first 3 rows):`);
  const preview = crosswalkData
    .select('sourceEntityValue', 'targetEntityValue', 'jaccard',
            'stateLCCount', 'ccssLCCount', 'sharedLCCount')
    .slice(0, 3)
    .objects();

  preview.forEach((row, idx) => {
    console.log(`  ${idx + 1}. Source: ${row.sourceEntityValue} → Target: ${row.targetEntityValue}`);
    console.log(`     Jaccard: ${row.jaccard}, State LCs: ${row.stateLCCount}, CCSS LCs: ${row.ccssLCCount}, Shared: ${row.sharedLCCount}`);
  });
}
Each row shows one state → CCSSM crosswalk.

Step 2: Find the Best-Matching State Standards for a CCSSM Standard

To find the best state standard matches (focusing on Texas) for a CCSSM standard, filter rows by the CCSSM standard ID and then filter for Texas jurisdiction.
// Pick a CCSSM standard to find its best state standard matches (focusing on Texas)
const TARGET_CCSSM_STANDARD_CODE = '6.EE.B.5';  // Common Core 6th grade math standard on solving equations and inequalities
const TARGET_CCSSM_JURISDICTION = 'Multi-State';

// First, find the CCSSM standard by its statement code and jurisdiction
const ccssmStandard = standardsFrameworkItemsData
  .params({ code: TARGET_CCSSM_STANDARD_CODE, juris: TARGET_CCSSM_JURISDICTION })
  .filter(d => d.statementCode === code && d.jurisdiction === juris)
  .object();

if (!ccssmStandard || !ccssmStandard.statementCode) {
  console.log(`❌ CCSSM standard not found: ${TARGET_CCSSM_STANDARD_CODE}`);
  return null;
}

const ccssmStandardUuid = ccssmStandard.caseIdentifierUUID; // Use 'caseIdentifierUUID' for crosswalk matching

console.log(`✅ Found CCSSM standard: ${TARGET_CCSSM_STANDARD_CODE}`);
console.log(`  Case UUID: ${ccssmStandardUuid}`);
console.log(`  Description: ${ccssmStandard.description}`);
console.log(`  Jurisdiction: ${ccssmStandard.jurisdiction}`);

// Filter crosswalk data for this CCSSM standard (it's the target in relationships)
const matches = crosswalkData
  .params({ ccssmId: ccssmStandardUuid })
  .filter(d => d.targetEntityValue === ccssmId);

if (matches.numRows() === 0) {
  console.log(`\n❌ No state standard matches found for ${TARGET_CCSSM_STANDARD_CODE}`);
  return null;
}

// Join with standards data to get jurisdiction and filter for Texas
const matchesWithJurisdiction = matches
  .join(
    standardsFrameworkItemsData.select('caseIdentifierUUID', 'jurisdiction'),
    ['sourceEntityValue', 'caseIdentifierUUID']
  );

// Filter for Texas only
const texasMatches = matchesWithJurisdiction
  .params({ state: 'Texas' })
  .filter(d => d.jurisdiction === state);

if (texasMatches.numRows() === 0) {
  console.log(`\n❌ No Texas standard matches found for ${TARGET_CCSSM_STANDARD_CODE}`);
  return null;
}

// Drop temporary columns and sort by Jaccard score
const texasMatchesClean = texasMatches.select(aq.not('caseIdentifierUUID', 'jurisdiction'));
const sortedMatches = texasMatchesClean.orderby(aq.desc('jaccard'));

console.log(`\n✅ Found ${sortedMatches.numRows()} Texas standard matches for ${TARGET_CCSSM_STANDARD_CODE}`);
console.log(`\n📊 Top Texas match (highest Jaccard score):`);

const topMatch = sortedMatches.object();
console.log(`  State Standard UUID: ${topMatch.sourceEntityValue}`);
console.log(`  Jaccard Score: ${parseFloat(topMatch.jaccard).toFixed(4)}`);
console.log(`  Shared LC Count: ${topMatch.sharedLCCount}`);
console.log(`  State LC Count: ${topMatch.stateLCCount}`);
console.log(`  CCSS LC Count: ${topMatch.ccssLCCount}`);
This identifies the Texas state standards that contain the most similar skills and concept targets for student mastery (not necessarily the most similar semantically) to the given CCSSM standard. Because the Jaccard value represents the proportion of shared Learning Components, a score of 1.0 means the standards are supported by identical LCs (a perfect match). Scores closer to 0.0 indicate weaker or partial overlap.
A Jaccard threshold of 0.6 is a good starting point for identifying strong matches, but you can adjust it based on your use case.

Step 3: Interpret the Relationship Metrics

Each crosswalk relationship carries additional context about the degree of overlap:
  • sharedLCCount shows how many deconstructed skills are shared.
  • stateLCCount and ccssLCCount show how many total skills support each standard.
  • Together with the Jaccard score, these counts help you interpret the strength and balance of the overlap. For example, whether one standard covers more ground than the other, or whether their scopes are roughly comparable.
This example shows how to read these values in context. Actual interpretation will vary depending on your use case.
stateLCCountccssLCCountsharedLCCountjaccardExample Interpretation
5640.57Substantial overlap between standards; many shared skills
4930.30Partial overlap; the CCSSM standard covers more content
3331.0Complete overlap; same set of underlying skills
Here’s how to programmatically interpret these metrics for your top matches:
// Show top 5 matches with interpretation
const topMatches = sortedMatches.slice(0, 5).objects();

console.log(`\n📊 INTERPRETATION OF TOP MATCHES:\n`);

topMatches.forEach((match, idx) => {
  const jaccard = parseFloat(match.jaccard);
  const stateLc = parseFloat(match.stateLCCount);
  const ccssLc = parseFloat(match.ccssLCCount);
  const sharedLc = parseFloat(match.sharedLCCount);

  console.log(`Match #${idx + 1}:`);
  console.log(`  Jaccard Score: ${jaccard.toFixed(4)}`);
  console.log(`  State LC Count: ${stateLc}`);
  console.log(`  CCSS LC Count: ${ccssLc}`);
  console.log(`  Shared LC Count: ${sharedLc}`);

  // Interpret the metrics
  let interpretation;
  if (jaccard >= 0.9) {
    interpretation = "Very strong overlap; standards share nearly all skills";
  } else if (jaccard >= 0.7) {
    interpretation = "Strong overlap; substantial shared skills";
  } else if (jaccard >= 0.5) {
    interpretation = "Moderate overlap; many shared skills";
  } else if (jaccard >= 0.3) {
    interpretation = "Partial overlap; some shared skills";
  } else {
    interpretation = "Weak overlap; few shared skills";
  }

  // Check scope balance
  let scopeNote;
  if (Math.abs(stateLc - ccssLc) <= 2) {
    scopeNote = "Both standards have similar scope";
  } else if (stateLc > ccssLc) {
    scopeNote = "State standard covers more content";
  } else {
    scopeNote = "CCSS standard covers more content";
  }

  console.log(`  Interpretation: ${interpretation}`);
  console.log(`  Scope: ${scopeNote}`);
  console.log();
});

Step 4: Join Crosswalks with Standards Metadata

You can enrich the crosswalk data by joining it with StandardsFrameworkItems.csv, which contains metadata such as grade level and description.
// Rename columns to avoid conflicts when merging state and CCSS metadata
// We'll merge the same standards dataset twice (once for state, once for CCSS)

// Join with state standard metadata (source)
const enriched = matches
  .join(
    standardsFrameworkItemsData.select('caseIdentifierUUID', 'statementCode', 'description',
                                       'gradeLevel', 'academicSubject', 'jurisdiction')
      .rename({
        caseIdentifierUUID: 'state_uuid',
        statementCode: 'statementCode_state',
        description: 'description_state',
        gradeLevel: 'gradeLevel_state',
        academicSubject: 'academicSubject_state'
      }),
    ['sourceEntityValue', 'state_uuid']
  )
  // Join with CCSS standard metadata (target)
  .join(
    standardsFrameworkItemsData.select('caseIdentifierUUID', 'statementCode', 'description',
                                       'gradeLevel', 'academicSubject')
      .rename({
        caseIdentifierUUID: 'ccss_uuid',
        statementCode: 'statementCode_ccss',
        description: 'description_ccss',
        gradeLevel: 'gradeLevel_ccss',
        academicSubject: 'academicSubject_ccss'
      }),
    ['targetEntityValue', 'ccss_uuid']
  );

console.log(`\n✅ Enriched crosswalk data with standards metadata\n`);
console.log(`📊 DETAILED COMPARISON (Top 3 matches):\n`);

const top3 = enriched.slice(0, 3).objects();

top3.forEach((row, idx) => {
  console.log(`Match #${idx + 1} (Jaccard: ${parseFloat(row.jaccard).toFixed(4)}):`);
  console.log(`  STATE STANDARD:`);
  console.log(`    Code: ${row.statementCode_state}`);
  console.log(`    Jurisdiction: ${row.jurisdiction}`);
  console.log(`    Grade Level: ${row.gradeLevel_state}`);
  console.log(`    Description: ${row.description_state}`);
  console.log(`  `);
  console.log(`  CCSS STANDARD:`);
  console.log(`    Code: ${row.statementCode_ccss}`);
  console.log(`    Grade Level: ${row.gradeLevel_ccss}`);
  console.log(`    Description: ${row.description_ccss}`);
  console.log(`  `);
  console.log(`  ALIGNMENT METRICS:`);
  console.log(`    Shared LCs: ${row.sharedLCCount} / State LCs: ${row.stateLCCount} / CCSS LCs: ${row.ccssLCCount}`);
  console.log();
});
This join provides a clear view of which state standards most closely align to their CCSSM counterparts, along with the strength of each connection.

You can adapt this pattern to explore crosswalks for any state framework by changing the filter conditions or threshold.

Step 5: Join Crosswalks to Learning Components (LCs)

Now that you have crosswalk pairs (state → CCSSM), you can see the actual skills behind each match by joining to the Learning Components dataset. We’ll use the supports relationships to fetch the LCs that support each standard and then intersect them to list the shared LCs (the evidence behind the crosswalk).
// Example: use the top match from Step 4
const STATE_STANDARD_CODE = topMatch.statementCode_state;
const CCSS_STANDARD_CODE = topMatch.statementCode_ccss;
const STATE_JURISDICTION = topMatch.jurisdiction;

// Find the standard identifiers
// Note: For LC relationships, we need to use caseIdentifierUUID, not identifier
const stateStandard = standardsFrameworkItemsData
  .params({ code: STATE_STANDARD_CODE, juris: STATE_JURISDICTION })
  .filter(d => d.statementCode === code && d.jurisdiction === juris)
  .object();

const ccssStandard = standardsFrameworkItemsData
  .params({ code: CCSS_STANDARD_CODE })
  .filter(d => d.statementCode === code && d.jurisdiction === 'Multi-State')
  .object();

if (!stateStandard || !ccssStandard) {
  console.log('❌ Could not find one or both standards');
  return;
}

const stateUuid = stateStandard.caseIdentifierUUID;
const ccssUuid = ccssStandard.caseIdentifierUUID;

// Get LCs that support the state standard
// LC relationships use caseIdentifierUUID for targetEntityValue
const stateLcIds = relationshipsData
  .params({ uuid: stateUuid })
  .filter(d => d.relationshipType === 'supports' && d.targetEntityValue === uuid)
  .array('sourceEntityValue');

const stateLcs = learningComponentsData
  .filter(aq.escape(d => stateLcIds.includes(d.identifier)))
  .select('identifier', 'description')
  .dedupe('identifier');

// Get LCs that support the CCSS standard
const ccssLcIds = relationshipsData
  .params({ uuid: ccssUuid })
  .filter(d => d.relationshipType === 'supports' && d.targetEntityValue === uuid)
  .array('sourceEntityValue');

const ccssLcs = learningComponentsData
  .filter(aq.escape(d => ccssLcIds.includes(d.identifier)))
  .select('identifier', 'description')
  .dedupe('identifier');

// Find shared LCs (intersection) using join
const sharedLcs = stateLcs.semijoin(ccssLcs, 'identifier');

// Find state-only LCs (in state but not in CCSS)
const stateOnlyLcs = stateLcs.antijoin(ccssLcs, 'identifier');

// Find CCSS-only LCs (in CCSS but not in state)
const ccssOnlyLcs = ccssLcs.antijoin(stateLcs, 'identifier');

console.log(`\n✅ LEARNING COMPONENTS ANALYSIS:\n`);
console.log(`State Standard: ${STATE_STANDARD_CODE}`);
console.log(`CCSS Standard: ${CCSS_STANDARD_CODE}`);
console.log();

console.log(`📊 SHARED LEARNING COMPONENTS (${sharedLcs.numRows()}):`);
console.log('These are the concrete pedagogical overlaps between the two standards:\n');
sharedLcs.objects().forEach((lc, idx) => {
  console.log(`  ✅ ${idx + 1}. ${lc.description}`);
});
console.log();

console.log(`📊 STATE-ONLY LEARNING COMPONENTS (${stateOnlyLcs.numRows()}):`);
stateOnlyLcs.objects().forEach((lc, idx) => {
  console.log(`  ➖ ${idx + 1}. ${lc.description}`);
});
console.log();

console.log(`📊 CCSS-ONLY LEARNING COMPONENTS (${ccssOnlyLcs.numRows()}):`);
ccssOnlyLcs.objects().forEach((lc, idx) => {
  console.log(`  ➕ ${idx + 1}. ${lc.description}`);
});
console.log();
This join lists the actual overlapping LCs and their description, which are the concrete pedagogical overlap between the two standards.

Summary

You’ve learned how to use crosswalk data to compare state standards with CCSSM. The relationships.csv file provides a ready-made, evidence-based mapping layer that simplifies cross-state comparison and supports deeper curriculum analysis. Key takeaways
  • Each crosswalk is a measurable alignment built from shared Learning Components.
  • The Jaccard index quantifies similarity; LC counts explain scope and overlap.
  • Relationships always point from state → CCSSM and exist only when at least one LC is shared.
  • You can use this data to explore how state standards correspond to Common Core, identify close matches, and guide alignment work across frameworks.