Feature: Node Selection (Python)
Relevant source files
The following files were used as context for generating this wiki page:Introduction
The Selection.py script provides a simulation of population change under evolutionary selection pressure. Contrary to what the topic "Node Selection" might imply in a network science context, this script does not operate on nodes within a graph. Instead, it models a population of individuals, each possessing a specific 'Trait' value. Selection is performed by removing a fraction of the population with the least advantageous traits in each generation. This tool is part of a larger collection of programs designed to accompany the Barabasi Network Science textbook.
While other components of the repository, such as Network.py and Form1.cs, focus on analyzing properties of network graphs like degree distribution and clustering coefficients, Selection.py explores a different, albeit related, concept of selection within a population. The simulation iteratively calculates changes in population size and the mean value of the trait over a specified number of generations, visualizing the outcome at each step.
Sources: Selection.py, README.md, Network.py, Form1.cs
Simulation Configuration
The simulation's behavior is controlled by several global constants defined at the beginning of the script. These parameters set the initial conditions and the evolutionary pressures for the entire run.
| Parameter | Default Value | Description |
|---|---|---|
INIT_POP | 10000 | The initial number of individuals in the population at generation 0. |
INIT_MEAN | 100 | The initial mean of the 'Trait' for the population, drawn from a normal distribution. |
INIT_SD | 16 | The initial standard deviation of the 'Trait' for the population. |
PREDATION | 0.03 | The fraction of the population with the lowest 'Trait' value to be removed each generation. |
GROWTH | 0.03 | A factor used to calculate the number of new individuals added to the population after selection. |
GENERATIONS | 20 | The total number of generations the simulation will run for. |
Sources: Selection.py:10-15
Simulation Flow
The script executes a main loop that iterates for a defined number of GENERATIONS. In each generation, it models population initialization, selection, reproduction, and visualization.
This diagram illustrates the process flow for a single generation within the simulation.
Sources: Selection.py:19-41
1. Population Initialization
At the start of each generation, a pandas DataFrame is created to represent the current population. Each individual is assigned a 'Trait' value sampled from a normal distribution with the current trait_mean and trait_sd. A 'Survive' column is initialized to 'Yes' for all individuals.
# Selection.py:21-23
pop = pd.DataFrame(index=np.arange(population))
pop['Trait'] = np.random.default_rng().normal(trait_mean, trait_sd, pop.shape[0])
pop['Survive'] = 'Yes'
Sources: Selection.py:21-23
2. Selection Mechanism
The core selection logic is implemented by sorting the population based on the 'Trait' in ascending order. A cutoff point is calculated based on the PREDATION rate, and individuals below this cutoff (i.e., those with the lowest trait values) have their 'Survive' status changed to 'No'. This simulates a survival disadvantage for individuals with lower trait scores.
# Selection.py:24-26
pop.sort_values(by='Trait', ascending=True, inplace=True, ignore_index=True)
cutoff = int(pop.shape[0] * PREDATION)
pop.loc[pop.index < cutoff, 'Survive'] = 'No'
Sources: Selection.py:24-26
3. Visualization
After selection is determined, the script uses seaborn and matplotlib to generate and display a histogram for the current generation. The histogram shows the distribution of the 'Trait' and visually distinguishes between individuals marked to 'Survive' and those marked 'No'. The plot title includes the current generation number and the population's mean trait value.
# Selection.py:27-31
sns.histplot(pop, x='Trait', hue='Survive', element='step', multiple='stack')
plt.xlim(0)
title_str = 'Generation: ' + str(gen) + ', Trait mean: %1.1f' % trait_mean
plt.title(title_str)
plt.show()
Sources: Selection.py:27-31
4. Population Update and Reproduction
Following visualization, the individuals who did not survive are removed from the DataFrame. The simulation then prepares for the next generation:
- The
populationsize is updated to the count of survivors. - The
trait_meanis recalculated from the surviving population's 'Trait' values. - The number of new individuals to be added (
reproduction) is calculated based on the new population size, an equilibrium condition, and theGROWTHrate. - The
populationfor the next generation is increased by the number of reproduced individuals.
The equilibrium condition is defined as 1 / (1 - PREDATION).
# Selection.py:17, 32-37
equilibrium = 1 / (1 - PREDATION) # Equilibrium condition
# ...
pop.drop(pop[pop['Survive'] == 'No'].index, inplace=True)
population = pop.shape[0]
trait_mean = pop['Trait'].mean()
reproduction = int(population * equilibrium * GROWTH)
population += reproduction
Sources: Selection.py:17, Selection.py:32-37
Data Structure
The primary data structure is a pandas DataFrame that holds the state of the population in each generation.
| Column | Data Type | Description |
|---|---|---|
Trait | float | The numerical trait value for each individual, drawn from a normal distribution. |
Survive | string | Status indicating if the individual survives the selection phase ('Yes' or 'No'). |
Sources: Selection.py:22-26
Summary
The Selection.py script is a self-contained simulation of evolutionary selection. It operates on a population of individuals defined by a single trait, applying selection pressure to remove the least fit members and modeling population growth over successive generations. While part of a network science project that includes tools for graph generation (Barabasi.cs) and analysis (Network.py, Form1.cs), this feature provides a functional example of population dynamics rather than graph-based node selection.
Sources: Selection.py, Barabasi.cs, Network.py, Form1.cs