Conjuntos con Python

Esta notebook fue creada originalmente como un blog post por Raúl E. López Briega en Mi blog sobre Python. El contenido esta bajo la licencia BSD.

Introducción

Una característica notable de los seres humanos es su inherente necesidad y capacidad de agrupar objetos de acuerdo a criterios específicos. La idea de la clasificación de ciertos objetos en grupos similares, o conjuntos, es uno de los conceptos más fundamentales de la matemática moderna. La teoría de conjuntos ha sido el marco unificador para todas las matemáticas desde que el matemático alemán Georg Cantor la formulara alrededor de 1870. Ningún campo de las matemáticas podría describirse hoy en día sin hacer referencia a algún tipo de conjunto abstracto. En términos más generales, el concepto de membresía de un conjunto, que se encuentra en el corazón de la teoría de conjuntos, explica cómo sentencias con sustantivos y predicados son formulados en nuestro lenguaje, o en cualquier lenguaje abstracto como las matemáticas. Debido a esto, la teoría de conjuntos está íntimamente ligada a la lógica y sirve de base para todas las matemáticas.

¿Qué es un conjunto?

Un conjunto es una colección de objetos distintos, a menudo llamados elementos o miembros. Existen dos características hacen de los conjuntos algo totalmente distinto a cualquier otra colección de objetos. En primer lugar, un conjunto está siempre "bien definido", es decir que si realizamos la pregunta ¿Este objeto particular, se encuentra en esta colección?; siempre debe existir una respuesta clara por sí o por no basada en una regla o algunos criterios dados. La segunda característica, es que no hay dos miembros de un mismo conjunto que sean exactamente iguales, es decir, que no hay elementos repetidos. Un conjunto puede contener cualquier cosa imaginable, incluyendo números, letras, colores, incluso otros conjuntos!. Sin embargo, ninguno de los objetos del conjunto puede ser el propio conjunto. Descartamos esta posibilidad para evitar encontrarnos con la Paradoja de Russell, un problema famoso en la lógica matemática desenterrado por el gran lógico británico Bertrand Russell en 1901.

Notación de Conjuntos

Cuando escribimos a los conjuntos utilizamos letras mayúsculas para sus nombres y para representar al conjunto propiamente dicho simplemente listamos sus elementos separándolos por comas y luego englobamos todos estos elementos dentro de un par de llaves. Así, por ejemplo, A = {1,2,3, ..., 10} es el conjunto de los 10 primeros números naturales o para contar, B = {Rojo, Azul, Verde} es el conjunto de colores primarios, N = {1,2,3, ...} es el conjunto de todos los números naturales, y Z = {..., - 3, -2, -1,0,1,2,3, ...} es el conjunto de todos los números enteros. Los puntos suspensivos "..." se utilizan para describir el carácter infinito de los números en los conjuntos N y Z.

También se utiliza el símbolo $ \in $ para expresar que determina objeto pertenece o es miembro de un conjunto y el símbolo $ \notin $ para indicar que no pertenece a un conjunto. Utilizando los ejemplos anteriores, podríamos por ejemplo escribir que $7 \in A$ y $12 \notin A$.

Dado que muchos conjuntos no se pueden describir listando todos sus miembros, ya que en muchos casos esto es imposible, también se utiliza la mucho más potente notación de constructor de conjuntos o predicado. En esta notación escribimos el conjunto de acuerdo a qué tipos de objetos pertenecen al conjunto, que se colocan a la izquierda del símbolo "|", que significa "de tal manera que," dentro de las llaves; así como las condiciones que estos objetos deben cumplir para pertenecer al conjunto, las cuales se colocan a la derecha de "|" dentro de las llaves. Por ejemplo, el conjunto de los números racionales, o fracciones, que se denota por Q no puede ser descrito por el método de listar todos sus miembros. En su lugar, se define a Q utilizando la notación de predicado de la siguiente manera: $Q=\{\frac{p}{q} \mid p, q \in Z$ y $q \ne 0 \}$ Esto se lee "Q es el conjunto de todas las fracciones de la forma p sobre q, tal que p y q son números enteros y q no es cero." También podríamos escribir al conjunto A de nuestro ejemplo anterior como $A = \{x \mid x \in N$ y $x < 11\}$.

Conjuntos numéricos

Dentro de las matemáticas, los principales conjuntos numéricos que podemos encontrar y que tienen un carácter universal son:

  • $\mathbb{N} = \{1,2,3, ...\}$ es el conjunto de los números naturales.
  • $\mathbb{W} = \{0,1,2,3, ...\}$ es el conjunto de los números enteros positivos.
  • $\mathbb{Z} = \{...,-3,-2,-1,0,1,2,3, ...\}$ es el conjunto de todos los números enteros.
  • $\mathbb{Q} =\{\frac{p}{q} \mid p, q \in Z$ y $q \ne 0 \}$ es el conjunto de los números racionales.
  • $\mathbb{R}$, es el conjunto de los números reales. Estos son todos los números que pueden ser colocados en una recta numérica unidimensional que se extiende sin fin tanto en negativo como positivo.
  • $\mathbb{I}$, es el conjunto de los números irracionales. Algunos de los números más importantes en matemáticas pertenecen a este conjunto,incluyendo $\pi, \sqrt{2}, e$ y $\phi$.
  • $\mathbb{C}$, es el conjunto de los números complejos. Estos son los números que contienen una parte real y otra parte imaginaria.

Igualdad entre conjuntos

El concepto de igualdad en los conjuntos, difiere levemente del clásico concepto de igualdad que solemos tener. Dos conjuntos A y B se dice que son iguales (expresado por A = B), si y sólo si ambos conjuntos tienen exactamente los mismos elementos. Por ejemplo el conjunto A={1,2,3,4} es igual al conjunto B={4,3,2,1}. Un conjunto importante, y que todavía no hemos mencionado es el conjunto vacío, el cual no tiene elementos y por tanto no puede ser igualado con ningún otro conjunto. Se expresa con el símbolo $\emptyset$ o {}.

Cardinalidad

La cardinalidad de un conjunto A es el número de elementos que pertenecen a A y lo expresamos como n(A). La cardinalidad de un conjunto puede ser pensada tambien como una medida de su "tamaño". Si la cardinalidad de un conjunto es un número entero, entonces el conjunto se dice que es finito. De lo contrario, el conjunto se dice que es infinito. Así por ejemplo la cardinalidad del conjunto A={1,2,...,9,10} es 10 y lo expresamos como n(A)=10.

Subconjunto y subconjunto propio

Si todos los elementos de un conjunto A son también elementos de otro conjunto B, entonces A se llama un subconjunto de B y lo expresamos como $A \subseteq B$. En cierto sentido, se puede pensar al subconjunto A como dentro, o contenido en el conjunto B. Si un conjunto A es un subconjunto de B y los dos conjuntos no son iguales, entonces llamamos A un subconjunto propio de B y lo expresamos como $A \subset B$. En este caso, se dice que el conjunto A esta propiamente contenido en B. Algunas propiedades importantes relacionadas con subconjuntos y subconjuntos propios son las siguientes:

  • Cualquier conjunto A es un subconjunto de sí mismo. Por lo tanto $A \subseteq A$. Esto es claramente cierto.
  • Menos obvio es el hecho de que el conjunto vacío es un subconjunto de cualquier conjunto A. Por lo tanto $\emptyset \subseteq A$. Esta propiedad se prueba a través de la contradicción, ya que si asumimos que existe un conjunto A del que el conjunto vacío no es un subconjunto, entonces esto quiere decir que el conjunto vacío debe contener un elemento que no se encuentra en A y esto es absurdo ya que el conjunto vacío no contiene ningún elemento.
  • El conjunto vacío es un subconjunto propio de cualquier conjunto A, siempre y cuando A no se también un conjunto vacío.
  • Para los conjuntos finitos A y B, si $A \subseteq B$, entonces $n(A) \leq n(B)$.
  • De forma similar, para los conjuntos finitos A y B, si $A \subset B$, entonces $n(A) < n(B)$.

Conjunto potencia

El conjunto potencia de un conjunto A, expresado por $P_{A}$, es el conjunto formado por todos los distintos subconjuntos de A. Así por ejemplo el conjunto potencia del conjunto $A=\{1,2,3\}$; va a ser igual a $P_{A}=\{\emptyset,\{1\},\{2\},\{3\},\{1,2\},\{2,3\}, \{1,3\},\{1,2,3\}\}$.

Un teorema importante de la teoría de conjuntos establece que si A es un conjunto con k elementos, es decir que n(A) = k; entonces el conjunto potencia de A tiene exactamente $2^k$ elementos. Escribimos esto como $n(P_{A}) = 2^k$. En nuestro ejemplo anterior podemos ver que n(A)=3, por lo tanto $n(P_{A}) = 2^3$, lo que es igual a los 8 elementos que vimos que tiene el conjunto potencia de A.

Algebra de conjuntos

El álgebra de conjuntos es el estudio de las operaciones básicas que podemos realizar con los conjuntos. Las operaciones básicas del álgebra de conjuntos son:

  • Unión. La unión de dos conjuntos A y B es el conjunto $A \cup B$ que contiene todos los elementos de A y de B.

  • Intersección. La intersección de dos conjuntos A y B es el conjunto $A \cap B$ que contiene todos los elementos comunes de A y B.

  • Diferencia. La diferencia entre dos conjuntos A y B es el conjunto $A \setminus B$ que contiene todos los elementos de A que no pertenecen a B.

  • Complemento. El complemento de un conjunto A es el conjunto $A^∁$ que contiene todos los elementos que no pertenecen a A.

  • Producto cartesiano. El producto cartesiano de dos conjuntos A y B es el conjunto $A \times B$ que contiene todos los pares ordenados (a, b) cuyo primer elemento pertenece a A y su segundo elemento pertenece a B.

Conjuntos con Python

Luego de todo este repaso por los fundamentos de la teoría de conjuntos, es tiempo de ver como podemos utilizar a los conjuntos dentro de Python; ya que el lenguaje trae como una de sus estructuras de datos por defecto a los conjuntos. También veremos que podemos utilizar el constructor FiniteSet que nos proporciona sympy, el cual tiene ciertas ventajas sobre la versión por defecto de Python.


In [1]:
# Creando un conjunto en python
A = {1,2,3}
A


Out[1]:
{1, 2, 3}

In [2]:
# Creando un conjunto a partir de una lista
lista = ["bananas", "manzanas", "naranjas", "limones"]
B = set(lista)
B


Out[2]:
{'bananas', 'limones', 'manzanas', 'naranjas'}

In [3]:
# Los conjuntos eliminan los elementos duplicados
lista = ["bananas", "manzanas", "naranjas", "limones",
        "bananas", "bananas", "limones", "naranjas"]
B = set(lista)
B


Out[3]:
{'bananas', 'limones', 'manzanas', 'naranjas'}

In [4]:
# Creando el conjunto vacío
O = set()
O


Out[4]:
set()

In [5]:
# Cardinalidad de un conjunto con len().
print("La cardinalidad del conjunto A = {0} es {1}".format(A,len(A)))


La cardinalidad del conjunto A = {1, 2, 3} es 3

In [6]:
# comprobando membresía
2 in A


Out[6]:
True

In [7]:
# Igualdad entre conjuntos. El orden de los elementos no importa.
A = {1,2,3,4}
B = {4,2,3,1}
A == B


Out[7]:
True

In [8]:
# Subconjunto. No hay distincion entre subconjunto y propio
# para el conjunto por defecto de python.
A = {1,2,3}
B = {1,2,3,4,5}
A.issubset(B)


Out[8]:
True

In [9]:
# Subconjunto propio
A.issubset(B) and A != B


Out[9]:
True

In [10]:
# Union de conjuntos
A = {1,2,3,4,5}
B = {4,5,6,7,8,9,10}
A.union(B)


Out[10]:
{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}

In [11]:
# Intersección de conjuntos
A.intersection(B)


Out[11]:
{4, 5}

In [12]:
# Diferencia entre conjuntos
A - B


Out[12]:
{1, 2, 3}

In [13]:
B - A


Out[13]:
{6, 7, 8, 9, 10}

In [14]:
# Utilizando FiniteSet de sympy
from sympy import FiniteSet
C = FiniteSet(1, 2, 3)
C


Out[14]:
{1, 2, 3}

In [15]:
# Generando el conjunto potencia. Esto no se puede
# hacer utilizando el conjunto por defecto de python.
C.powerset()


Out[15]:
{EmptySet(), {1}, {2}, {3}, {1, 2}, {1, 3}, {2, 3}, {1, 2, 3}}

In [16]:
# Cardinalidad
print("La cardinalidad del conjunto potencia del conjunto C = {0} es {1}".
     format(C, len(C.powerset())))


La cardinalidad del conjunto potencia del conjunto C = {1, 2, 3} es 8

In [17]:
# Igualdad
A = FiniteSet(1, 2, 3)
B = FiniteSet(1, 3, 2)
A == B


Out[17]:
True

In [18]:
A = FiniteSet(1, 2, 3)
B = FiniteSet(1, 3, 4)
A == B


Out[18]:
False

In [19]:
# Subconjunto y subconjunto propio
A = FiniteSet(1,2,3)
B = FiniteSet(1,2,3,4,5)
A.is_subset(B)


Out[19]:
True

In [20]:
A.is_proper_subset(B)


Out[20]:
True

In [21]:
# A == B. El test de subconjunto propio da falso
B = FiniteSet(2,1,3)
A.is_proper_subset(B)


Out[21]:
False

In [22]:
# Union de dos conjuntos
A = FiniteSet(1, 2, 3)
B = FiniteSet(2, 4, 6)
A.union(B)


Out[22]:
{1, 2, 3, 4, 6}

In [23]:
# Interseccion de dos conjuntos
A = FiniteSet(1, 2) 
B = FiniteSet(2, 3) 
A.intersect(B)


Out[23]:
{2}

In [24]:
# Diferencia entre conjuntos
A - B


Out[24]:
{1}

In [25]:
# Calculando el producto cartesiano. Con el conjunto por 
# defecto de python no podemos hacer esto con el operador *
A = FiniteSet(1, 2)
B = FiniteSet(3, 4)
P = A * B
P


Out[25]:
{1, 2} x {3, 4}

In [26]:
for elem in P:
    print(elem)


(1, 3)
(1, 4)
(2, 3)
(2, 4)

In [27]:
# Elevar a la n potencia un conjunto. Calcula el n 
# producto cartesiano del mismo conjunto.
A = FiniteSet(1, 2, 3, 4)
P2 = A ** 2
P2


Out[27]:
{1, 2, 3, 4} x {1, 2, 3, 4}

In [28]:
P3 = A ** 3
P3


Out[28]:
{1, 2, 3, 4} x {1, 2, 3, 4} x {1, 2, 3, 4}

In [29]:
for elem in P3:
    print(elem)


(1, 1, 1)
(1, 1, 2)
(1, 1, 3)
(1, 1, 4)
(1, 2, 1)
(1, 2, 2)
(1, 2, 3)
(1, 2, 4)
(1, 3, 1)
(1, 3, 2)
(1, 3, 3)
(1, 3, 4)
(1, 4, 1)
(1, 4, 2)
(1, 4, 3)
(1, 4, 4)
(2, 1, 1)
(2, 1, 2)
(2, 1, 3)
(2, 1, 4)
(2, 2, 1)
(2, 2, 2)
(2, 2, 3)
(2, 2, 4)
(2, 3, 1)
(2, 3, 2)
(2, 3, 3)
(2, 3, 4)
(2, 4, 1)
(2, 4, 2)
(2, 4, 3)
(2, 4, 4)
(3, 1, 1)
(3, 1, 2)
(3, 1, 3)
(3, 1, 4)
(3, 2, 1)
(3, 2, 2)
(3, 2, 3)
(3, 2, 4)
(3, 3, 1)
(3, 3, 2)
(3, 3, 3)
(3, 3, 4)
(3, 4, 1)
(3, 4, 2)
(3, 4, 3)
(3, 4, 4)
(4, 1, 1)
(4, 1, 2)
(4, 1, 3)
(4, 1, 4)
(4, 2, 1)
(4, 2, 2)
(4, 2, 3)
(4, 2, 4)
(4, 3, 1)
(4, 3, 2)
(4, 3, 3)
(4, 3, 4)
(4, 4, 1)
(4, 4, 2)
(4, 4, 3)
(4, 4, 4)

In [30]:
# graficos embebidos
%matplotlib inline

In [31]:
# Dibujanto el diagrama de venn de 2 conjuntos
from matplotlib_venn import venn2, venn2_circles
import matplotlib.pyplot as plt
   
A = FiniteSet(1, 3, 5, 7, 9, 11, 13, 15, 17, 19)
B = FiniteSet(2, 3, 5, 7, 11, 13, 17, 19, 8)

plt.figure(figsize=(6, 8))
v = venn2(subsets=[A, B], set_labels=('A', 'B'))
v.get_label_by_id('10').set_text(A - B)
v.get_label_by_id('11').set_text(A.intersection(B))
v.get_label_by_id('01').set_text(B - A)
c = venn2_circles(subsets=[A, B], linestyle='dashed')
c[0].set_ls('solid')
plt.show()


Además de las aplicaciones que pueden tener los conjuntos de Python en matemáticas, los mismos también pueden ser una estructura de datos poderosa y ayudarnos a resolver varios problemas de programación en forma muy sencilla. A tenerlos en cuenta!

Con esto termino este artículo; espero que les haya gustado y les sea de utilidad.

Saludos!

Este post fue escrito utilizando IPython notebook. Pueden descargar este notebook o ver su version estática en nbviewer.