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.
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.
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.
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\}$.
Dentro de las matemáticas, los principales conjuntos numéricos que podemos encontrar y que tienen un carácter universal son:
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 {}.
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.
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:
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.
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.
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]:
In [2]:
# Creando un conjunto a partir de una lista
lista = ["bananas", "manzanas", "naranjas", "limones"]
B = set(lista)
B
Out[2]:
In [3]:
# Los conjuntos eliminan los elementos duplicados
lista = ["bananas", "manzanas", "naranjas", "limones",
"bananas", "bananas", "limones", "naranjas"]
B = set(lista)
B
Out[3]:
In [4]:
# Creando el conjunto vacío
O = set()
O
Out[4]:
In [5]:
# Cardinalidad de un conjunto con len().
print("La cardinalidad del conjunto A = {0} es {1}".format(A,len(A)))
In [6]:
# comprobando membresía
2 in A
Out[6]:
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]:
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]:
In [9]:
# Subconjunto propio
A.issubset(B) and A != B
Out[9]:
In [10]:
# Union de conjuntos
A = {1,2,3,4,5}
B = {4,5,6,7,8,9,10}
A.union(B)
Out[10]:
In [11]:
# Intersección de conjuntos
A.intersection(B)
Out[11]:
In [12]:
# Diferencia entre conjuntos
A - B
Out[12]:
In [13]:
B - A
Out[13]:
In [14]:
# Utilizando FiniteSet de sympy
from sympy import FiniteSet
C = FiniteSet(1, 2, 3)
C
Out[14]:
In [15]:
# Generando el conjunto potencia. Esto no se puede
# hacer utilizando el conjunto por defecto de python.
C.powerset()
Out[15]:
In [16]:
# Cardinalidad
print("La cardinalidad del conjunto potencia del conjunto C = {0} es {1}".
format(C, len(C.powerset())))
In [17]:
# Igualdad
A = FiniteSet(1, 2, 3)
B = FiniteSet(1, 3, 2)
A == B
Out[17]:
In [18]:
A = FiniteSet(1, 2, 3)
B = FiniteSet(1, 3, 4)
A == B
Out[18]:
In [19]:
# Subconjunto y subconjunto propio
A = FiniteSet(1,2,3)
B = FiniteSet(1,2,3,4,5)
A.is_subset(B)
Out[19]:
In [20]:
A.is_proper_subset(B)
Out[20]:
In [21]:
# A == B. El test de subconjunto propio da falso
B = FiniteSet(2,1,3)
A.is_proper_subset(B)
Out[21]:
In [22]:
# Union de dos conjuntos
A = FiniteSet(1, 2, 3)
B = FiniteSet(2, 4, 6)
A.union(B)
Out[22]:
In [23]:
# Interseccion de dos conjuntos
A = FiniteSet(1, 2)
B = FiniteSet(2, 3)
A.intersect(B)
Out[23]:
In [24]:
# Diferencia entre conjuntos
A - B
Out[24]:
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]:
In [26]:
for elem in P:
print(elem)
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]:
In [28]:
P3 = A ** 3
P3
Out[28]:
In [29]:
for elem in P3:
print(elem)
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.