Concepts / Bunch Objects in Scikit-Learn

Bunch Objects in Scikit-Learn

The load_breast_cancer function from scikit-learn returns the breast cancer dataset, stored as a Bunch object assigned here to the name cancer.

  • Programming

Loading a Real Dataset in a Few Lines

Machine learning is much easier to learn when you have a real dataset to experiment with. Scikit-learn ships with several datasets that are ready to use, and the breast cancer dataset is one of them. In this article you will load it, run a few lines of code, and examine what comes back. Each step starts with code you can trace, so you can check your understanding against what Python actually prints.

The data is loaded with the load_breast_cancer function. The function is imported from the sklearn.datasets module, called once, and its result is stored in a variable named cancer. The program below loads the dataset and prints the keys that the loaded object provides.

python
Notes on the code
  • The import brings in only the loader function from the sklearn.datasets module
  • load_breast_cancer() is called once and its result is stored in the name cancer
  • keys() lists the names of the pieces of information stored inside the object

Tracing What the Loader Returns

Think of the variable cancer as a container. Calling load_breast_cancer() does not hand you a bare table of numbers. It hands you one object that carries the numbers together with information about them, such as the names of the columns and a description of the dataset. The keys() call lets you see which labeled compartments that container has.

data569 rows of 30 measurementstargetone class label per rowfeature_namesa name for each of 30columnstarget_namesnames of the two classesDESCRtext description of thedatasetsame object
What keys does the Bunch hold, what does each one contain, and how does cancer.data relate to the same key lookup? Each key is a label on one compartment, and the dot form cancer.data reaches the same compartment as cancer['data'].

Run the program yourself to see the complete list of keys printed for your installed version of scikit-learn. The keys named in the diagram are the ones this article relies on. The most important ones are data, which holds the measurements, and feature_names, which labels the columns. Two other keys, target and target_names, describe the class each row belongs to.

What do you think happens?

Before running anything: if you print cancer.data.shape, what two numbers do you expect, and in what order?

Reveal answer
Answer:

(569, 30). The first number is the number of rows, which are the data points, and the second is the number of columns, which are the features.

The shape attribute of the data array reports the row count first and then the column count. The breast cancer dataset has 569 data points with 30 features each.

Bunch Objects: Dictionary Keys with Dot Access

Definition

A Bunch object is the container type that scikit-learn uses for most of its bundled datasets. It holds some information about the dataset together with the actual data. A Bunch behaves like a dictionary, with the added benefit that you can read its values using a dot.

This means bunch.key is an alternative to bunch['key']. Both forms look up the same stored value. Dot notation is shorter and easier to read, which is why most scikit-learn tutorials use it. The dictionary form is still useful when the key name is stored in a variable or when you want to loop over the keys.

python
Notes on the code
  • cancer.data uses dot notation to reach the data key
  • cancer['data'] reaches the same value with dictionary-style lookup
  • The last line checks that both forms return the same stored object

Reading the Shape: 569 Samples and 30 Features

The breast cancer dataset consists of 569 data points, with 30 features each. The shape attribute of the data array reports this directly. Printing cancer.data.shape shows the number of rows and the number of columns, in that order. Each row is one data point, and each column is one feature. So the 569 numbers count the rows and the 30 numbers count the columns.

column 0mean radiuscolumn 1mean texturecolumn 2mean perimetercolumn 29worst fractal dimensionnext column
Which axis of the 569 by 30 data array is samples and which is features, and how does one row relate to one column? Rows run down the array, one per data point, and each column holds one feature across all data points. Four of the thirty columns are shown with their feature names.
Worked example

Reading the Dataset Dimensions

Given the shape (569, 30) of cancer.data, say what each number counts and how many values the array holds in total.

  1. 1
    Identify the first number

    569 is the first entry of the shape, so it counts rows. Each row is one data point.

  2. 2
    Identify the second number

    30 is the second entry, so it counts columns. Each column is one feature.

  3. 3
    Count the class totals

    The dataset has 212 malignant and 357 benign labeled points. Adding them gives 212 plus 357, which equals 569, matching the number of rows.

  4. 4
    Interpret the total

    Each of the 569 rows holds 30 feature values, so the data array holds 569 times 30 values in total.

Result

The 569 counts data points (rows) and the 30 counts features (columns). The per-class counts 212 and 357 together account for all 569 rows.

The two per-class counts are worth comparing. The dataset has 212 malignant points and 357 benign points, so the benign group is the larger of the two. You can confirm the counts in code by counting how many entries of the target array fall into each class.

python
Notes on the code
  • np.bincount counts how many times each class label appears in the target array
  • The sum of the counts equals the number of rows, which is 569

Feature Names: Ten Measurements Reported Three Ways

To find out what each column in the data represents, look at the feature_names attribute. It gives the semantic meaning of each feature as a name. Printing it produces a list of 30 names. The names are not arbitrary. They follow a repeated pattern built from a small set of base measurements, and each base measurement appears in three versions.

python
Notes on the code
  • len confirms there are 30 names, one per column
  • Indexes 0, 10, and 20 pick out the first name in each of three groups of ten
30 feature namesradiusmean radiusmeantextureradius errorerrorperimeterworst radiusworstareamean texturemeansmoothnesstexture errorerrorcompactnessworst textureworstconcavitymean perimetermeanconcave pointsperimeter errorerrorsymmetryworst perimeterworstfractal dimensionmean areameanarea errorerrorworst areaworstmean smoothnessmeansmoothness errorerrorworst smoothnessworstmean compactnessmeancompactness errorerrorworst compactnessworstmean concavitymeanconcavity errorerrorworst concavityworstmean concave pointsmeanconcave points errorerrorworst concave pointsworstmean symmetrymeansymmetry errorerrorworst symmetryworstmean fractaldimensionmeanfractal dimensionerrorerrorworst fractaldimensionworstmeanerrorworstmeanerrorworstmeanerrorworstmeanerrorworstmeanerrorworstmeanerrorworstmeanerrorworstmeanerrorworstmeanerrorworstmeanerrorworst
How do the 30 feature names group into 10 measurements, each reported three ways, and which columns belong to each group? Each measurement branches into a mean, an error, and a worst version. Only the radius branch is spelled out in full, and the other branches use the same three-way pattern.

Mistakes Beginners Make with Bunch Objects

  • Common mistake

    Treating the Bunch as a plain array

    What it looks like
    print(cancer.shape)
    Why it fails

    The Bunch is a container with several keys, and the shape belongs to the data stored under the data key, not to the whole object.

    Do this instead
    print(cancer.data.shape)
  • Common mistake

    Assuming the 569 is the number of columns

    Why it fails

    In the shape (569, 30) the first number counts rows, which are data points. The second number counts columns, which are features.

    Do this instead

    Read the shape in order: rows first, then columns.

  • Common mistake

    Thinking the feature names are random strings

    Why it fails

    The names follow a repeated pattern built from ten base measurements, each reported as mean, error, or worst.

    Do this instead

    Look for the base measurement and the statistic word inside each name.

  • Common mistake

    Using a key name that does not exist

    What it looks like

    cancer.Data

    Why it fails

    Key names are case sensitive, so Data does not match the stored key data.

    Do this instead

    Use the exact lowercase key name, such as cancer.data, after checking cancer.keys().

Practice: Read the Dataset Yourself

EASY

Load the breast cancer dataset into a variable named cancer. Print the shape of cancer.data, then print the first three entries of cancer.feature_names. Before you run the code, write down what the first number of the shape counts and what the three names will look like. Then check your answer against the printed output.

Hints
  • Use the dot form cancer.data.shape to read the shape.
  • Slicing a list with [0:3] returns its first three items.
  • The first number in the shape counts rows, and each row is one data point.

Key Takeaways

  • load_breast_cancer from sklearn.datasets returns the dataset as a Bunch object, which the example stores in the name cancer.
  • A Bunch behaves like a dictionary, so cancer.data and cancer['data'] read the same stored value.
  • The data array has shape (569, 30): 569 rows are data points and 30 columns are features. The per-class counts 212 malignant and 357 benign sum to 569.
  • The 30 feature names follow a mean, error, and worst pattern across ten base measurements, so each column's name tells you what it measures and which statistic it reports.

Related concepts

More concepts starting with B