<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/"
    xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/" version="2.0">
    <channel>
        
        <title>
            <![CDATA[ Fernando Cardellino - freeCodeCamp.org ]]>
        </title>
        <description>
            <![CDATA[ Descubre miles de cursos de programación escritos por expertos. Aprende Desarrollo Web, Ciencia de Datos, DevOps, Seguridad y obtén asesoramiento profesional para desarrolladores. ]]>
        </description>
        <link>https://www.freecodecamp.org/espanol/news/</link>
        <image>
            <url>https://cdn.freecodecamp.org/universal/favicons/favicon.png</url>
            <title>
                <![CDATA[ Fernando Cardellino - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/espanol/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Wed, 27 May 2026 16:02:07 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/espanol/news/author/fernando-cardellino/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ Cómo funcionan los clasificadores Naive Bayes: con ejemplos de código de Python ]]>
                </title>
                <description>
                    <![CDATA[ Los clasificadores Naive Bayes (NBC por su siglas en inglés) son algoritmos de aprendizaje automático simples pero potentes. Se basan en la probabilidad condicional y el teorema de Bayes. En esta publicación, explico "el truco" detrás de NBC y les daré un ejemplo que podemos usar para resolver un problema ]]>
                </description>
                <link>https://www.freecodecamp.org/espanol/news/como-funcionan-los-clasificadores-naive-bayes-con-ejemplos-de-codigo-de-python/</link>
                <guid isPermaLink="false">6015cfe562984e09f60851c3</guid>
                
                    <category>
                        <![CDATA[ Aprendizaje Automatico ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Fernando Cardellino ]]>
                </dc:creator>
                <pubDate>Wed, 28 Apr 2021 05:08:20 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/espanol/news/content/images/2021/01/naive_bayes_classif.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Los clasificadores Naive Bayes (NBC por su siglas en inglés) son algoritmos de aprendizaje automático simples pero potentes. Se basan en la probabilidad condicional y el teorema de Bayes.</p><p>En esta publicación, explico "el truco" detrás de NBC y les daré un ejemplo que podemos usar para resolver un problema de clasificación.</p><p>En las próximas secciones, hablaré sobre las matemáticas detrás de NBC. Siéntete libre de omitir esas secciones y pasar a la parte de implementación si no estás interesado en las matemáticas.</p><p>En la sección de implementación, te mostraré un algoritmo NBC simple. Luego lo usaremos para resolver un problema de clasificación. La tarea será determinar si cierto pasajero del Titanic sobrevivió al accidente o no.</p><h2 id="probabilidad-condicional">Probabilidad condicional</h2><p>Antes de hablar sobre el algoritmo en sí, hablemos de las matemáticas detrás de él. Necesitamos entender qué es la probabilidad condicional y cómo podemos usar el teorema de Bayes para calcularla.</p><p>Piense en un dado equilibrado con seis lados. ¿Cuál es la probabilidad de obtener un seis al lanzar el dado? Eso es fácil, es 1/6. Tenemos seis resultados posibles e igualmente probables, pero solo nos interesa uno de ellos. Entonces, 1/6 lo es.</p><p>Pero, ¿qué pasa si te digo que ya lancé el dado y el resultado es un número par? ¿Cuál es la probabilidad de que tengamos un seis ahora?</p><p>Esta vez, los posibles resultados son solo tres porque solo hay tres números pares en el dado. Todavía estamos interesados en solo uno de esos resultados, por lo que ahora la probabilidad es mayor: 1/3. ¿Cuál es la diferencia entre ambos casos?</p><p>En el primer caso, no teníamos información <strong>previa</strong> sobre el resultado. Por lo tanto, necesitábamos considerar todos los resultados posibles.</p><p>En el segundo caso, se nos dijo que el resultado era un número par, por lo que podíamos reducir el espacio de posibles resultados a solo los tres números pares que aparecen en un dado normal de seis caras.</p><p>En general, al calcular la probabilidad de un evento A, dada la ocurrencia de otro evento B, decimos que estamos calculando la <strong>probabilidad condicional</strong> de A dado B, o simplemente la probabilidad de A dado B. Lo denotamos <code>P(A|B)</code>.</p><p>Por ejemplo, la probabilidad de obtener un seis dado que el número que tenemos es par: <code>P(Seis|Par) = 1/3</code>. Aquí, denotamos con <strong>Seis</strong> el evento de obtener un seis y con <strong>Par</strong> el evento de obtener un número par.</p><p>Pero, ¿cómo calculamos las probabilidades condicionales? ¿Existe una fórmula?</p><h2 id="c-mo-calcular-probabilidades-condicionales-y-el-teorema-de-bayes">Cómo calcular probabilidades condicionales y el teorema de Bayes</h2><p>Ahora, te daré un par de fórmulas para calcular probabilidades condicionales. Prometo que no serán difíciles y son importantes si deseas comprender la ideas detrás de los algoritmos de aprendizaje automático de los que hablaremos más adelante.</p><p>La probabilidad de un evento A dada la ocurrencia de otro evento B se puede calcular de la siguiente manera:</p><pre><code class="language-pseudocode">P(A|B) = P(A,B)/P(B)
</code></pre><p>Donde <code>P(A,B)</code> denota la probabilidad de A y B ocurriendo al mismo tiempo, y <code>P(B)</code> denota la probabilidad de B.</p><p>Observa que necesitamos <code>P(B) &gt; 0</code> porque no tiene sentido hablar de la probabilidad de A dado B si la ocurrencia de B no es posible.</p><p>También podemos calcular la probabilidad de un evento A, dada la ocurrencia de múltiples eventos B1, B2, ..., Bn:</p><pre><code class="language-pseudocode">P(A|B1,B2,...,Bn) = P(A,B1,B2,...,Bn)/P(B1,B2,...,Bn)
</code></pre><p>Hay otra forma de calcular probabilidades condicionales. Esta forma es el llamado Teorema de Bayes.</p><pre><code class="language-pseudocode">P(A|B) = P(B|A)P(A)/P(B)

P(A|B1,B2,...,Bn) = P(B1,B2,...,Bn|A)P(A)/P(B1,B2,...,Bn)
</code></pre><p>Observa que estamos calculando la probabilidad del evento A dado el evento B, <em>invirtiendo</em> el orden de ocurrencia de los eventos.</p><p>Ahora suponemos que ha ocurrido el evento A y queremos calcular la probabilidad del evento B (o eventos B1, B2, ..., Bn en el segundo y más general ejemplo).</p><p>Un dato importante que se puede derivar de este Teorema es la fórmula para calcular <code>P(B1,B2,...,Bn,A)</code>. Eso se llama la regla de la cadena para las probabilidades.</p><pre><code class="language-pseudocode">P(B1,B2,...,Bn,A) = P(B1 | B2, B3, ..., Bn, A)P(B2,B3,...,Bn,A)
= P(B1 | B2, B3, ..., Bn, A)P(B2 | B3, B4, ..., Bn, A)P(B3, B4, ..., Bn, A)
= P(B1 | B2, B3, ..., Bn, A)P(B2 | B3, B4, ..., Bn, A)...P(Bn | A)P(A)
</code></pre><p>Esa es una fórmula fea, ¿no? Pero bajo algunas condiciones podemos hacer una solución y evitarlo.</p><p>Hablemos del último concepto que necesitamos saber para entender los algoritmos.</p><h2 id="independencia">Independencia</h2><p>El último concepto del que vamos a hablar es el de independencia. Decimos que los eventos A y B son independientes si</p><pre><code class="language-pseudocode">P(A|B) = P(A)
</code></pre><p>Eso significa que la probabilidad del evento A no se ve afectada por la ocurrencia del evento B. Una consecuencia directa es que <code>P(A,B) = P(A)P(B)</code>.</p><p>En términos sencillos, esto significa que la probabilidad de la ocurrencia de A y B al mismo tiempo es igual al producto de las probabilidades de los eventos A y B que ocurren por separado.</p><p>Si A y B son independientes, también se sostiene que:</p><pre><code class="language-pseudocode">P(A,B|C) = P(A|C)P(B|C)
</code></pre><p>¡Ahora estamos listos para hablar sobre los clasificadores Naive Bayes!</p><h2 id="clasificadores-naive-bayes">Clasificadores Naive Bayes</h2><p>Supongamos que tenemos un vector <strong>X</strong> de <em>n</em> características (features) y queremos determinar la clase de ese vector a partir de un conjunto de <em>k</em> clases <em>y1, y2, ..., yk</em>. Por ejemplo, si queremos determinar si lloverá hoy o no.</p><p>Tenemos dos clases posibles <em>(k = 2)</em>: <em>lluvia</em>, <em>no lluvia</em>, y la longitud del vector de características podría ser 3 (<em>n = 3</em>).</p><p>La primera característica podría ser si está nublado o soleado, la segunda característica podría ser si la humedad es alta o baja, y la tercera característica sería si la temperatura es alta, media o baja.</p><p>Entonces, estos podrían ser posibles vectores de características.</p><pre><code class="language-pseudocode">&lt;Nublado, H_Alta, T_Baja&gt;
&lt;Soleado, H_Baja, T_Media&gt;
&lt;Nublado, H_Baja, T_Alta&gt;
</code></pre><p>Nuestra tarea es determinar si lloverá o no, dadas las características meteorológicas.</p><p>Después de conocer las probabilidades condicionales, parece natural abordar el problema tratando de calcular la probabilidad de que llueva dadas las características:</p><pre><code class="language-pseudocode">R = P(Llueve | Nublado, H_Alta, T_Baja)
NR = P(NoLlueve | Nublado, H_Alta, T_Baja)
</code></pre><p>Si <code>R &gt; NR</code> respondemos que va a llover, de lo contrario decimos que no.</p><p>En general, si tenemos <em>k</em> clases <em>y1, y2, ..., yk</em>, y un vector de <em>n</em> características <strong>X = &lt;X1, X2, ..., Xn&gt;</strong>, queremos encontrar la clase yi que maximiza</p><pre><code class="language-pseudocode">P(yi | X1, X2, ..., Xn) = P(X1, X2,..., Xn, yi)/P(X1, X2, ..., Xn)
</code></pre><p>Observa que el denominador es constante y no depende de la clase <em>yi</em>. Entonces, podemos ignorarlo y enfocarnos en el numerador.</p><p>En una sección anterior, vimos cómo calcular <code>P(X1, X2,..., Xn, yi)</code> descomponiéndolo en un producto de probabilidades condicionales (la fórmula fea):</p><pre><code>P(X1, X2,..., Xn, yi) = P(X1 | X2,..., Xn, yi)P(X2 | X3,..., Xn, yi)...P(Xn | yi)P(yi)
</code></pre><p>Suponiendo que todas las características <strong>Xi</strong> son independientes y usando el teorema de Bayes, podemos calcular la probabilidad condicional de la siguiente manera:</p><pre><code>P(yi | X1, X2,..., Xn) = P(X1, X2,..., Xn | yi)P(yi)/P(X1, X2, ..., Xn)
= P(X1 | yi)P(X2 | yi)...P(Xn | yi)P(yi)/P(X1, X2, ..., Xn)
</code></pre><p>Y solo tenemos que centrarnos en el numerador.</p><p>Al encontrar la clase <em>yi</em> que maximiza la expresión anterior, estamos clasificando el vector de entrada. Pero, ¿cómo podemos obtener todas esas probabilidades?</p><h2 id="c-mo-calcular-las-probabilidades">Cómo calcular las probabilidades</h2><p>Al resolver este tipo de problemas necesitamos tener un conjunto de ejemplos previamente clasificados.</p><p>Por ejemplo, en el problema de adivinar si lloverá o no, necesitamos tener varios ejemplos de vectores de características y sus clasificaciones que se obtendrían de pronósticos meteorológicos anteriores.</p><p>Entonces, tendríamos algo como esto:</p><pre><code class="language-pseudocode">...
&lt;Nublado, H_Alta, T_Baja&gt; -&gt; Llueve
&lt;Soleado, H_Baja, T_Media&gt; -&gt; No Llueve
&lt;Nublado, H_Baja, T_Alta&gt; -&gt; No Llueve
...
</code></pre><p>Supongamos que necesitamos clasificar un nuevo vector <code>&lt;Nublado, H_Baja, T_Alta&gt;</code>. Necesitamos calcular:</p><pre><code>P(Llueve | Nublado, H_Baja, T_Baja) = P(Nublado | H_Baja, T_Baja, Llueve)P(H_Baja | T_Baja, Llueve)P(T_Baja | Llueve)P(Llueve)/P(Nublado, H_Baja, T_Baja)
</code></pre><p>Obtenemos la expresión anterior aplicando la definición de probabilidad condicional y la regla de la cadena. Recuerda que solo necesitamos enfocarnos en el numerador por lo que podamos eliminar el denominador.</p><p>También necesitamos calcular la probabilidad para <code>NoLlueve</code>, pero podemos hacerlo de una forma similar.</p><p>Podemos encontrar <code>P(Llueve) = # Llueve/Total</code>. Eso significa contar las entradas en el conjunto de datos que se clasifican con <em>Llueve</em> y dividir ese número por el tamaño del conjunto de datos.</p><p>Para calcular <code>P(Nublado | H_Baja, T_Baja, Llueve)</code> necesitamos contar todas las entradas que tienen las características <em>H_Baja, T_Baja</em> y <em>Nublado</em>. Esas entradas también deben clasificarse como <code>Llueve</code>. Luego, ese número se divide por la cantidad total de datos. Calculamos el resto de factores de la fórmula de forma similar.</p><p>Hacer esos cálculos para todas las clases posibles es muy costoso y lento. Por tanto, necesitamos hacer suposiciones sobre el problema que simplifiquen los cálculos.</p><p>Los clasificadores Naive Bayes asumen que todas las características son independientes entre sí. Entonces podemos reescribir nuestra fórmula aplicando el teorema de Bayes y asumiendo la independencia entre cada par de características:</p><pre><code>P(Llueve | Nublado, H_Baja, T_Baja) = P(Nublado | Llueve)P(H_Baja | Llueve)P(T_Baja | Llueve)P(Llueve)/P(Nublado, H_Baja, T_Baja)
</code></pre><p>Ahora calculamos <code>P(Nublado | Llueve)</code> contando el número de entradas que están clasificadas como <code>Llueve</code> y estaban <code>Nublado</code>.</p><blockquote>El algoritmo se llama Naive (que significa ingenuo en inglés) debido a esta suposición de independencia. Hay dependencias entre las características (features) la mayor parte del tiempo. No podemos decir que en la vida real no existe una dependencia entre la humedad y la temperatura, por ejemplo. Los clasificadores Naive Bayes también se denominan Bayes Indepentientes o Bayes Simples.</blockquote><p>La fórmula general sería:</p><pre><code>P(yi | X1, X2, ..., Xn) = P(X1 | yi)P(X2 | yi)...P(Xn | yi)P(yi)/P(X1, X2, ..., Xn)
</code></pre><p>Recuerda que puedes deshacerte del denominador. Solo calculamos el numerador y respondemos la clase que lo maximiza.</p><p>Ahora, implementemos nuestro NBC y usémoslo en un problema.</p><h2 id="-programemos-">¡Programemos!</h2><p>Les mostraré una implementación de un NBC simple y luego lo veremos en la práctica.</p><p>El problema que vamos a resolver es determinar si un pasajero del Titanic sobrevivió o no, dadas algunas características como su género y su edad.</p><p>Aquí puedes ver la implementación de un NBC muy simple:</p><pre><code class="language-python">class NaiveBayesClassifier:
    
    def __init__(self, X, y):
        
        '''
        X e y denotan las características y las etiquetas de destino respectivamente
        '''
        self.X, self.y = X, y 
        
        self.N = len(self.X) # Tamaño del conjunto de entrenamiento

        self.dim = len(self.X[0]) # Dimensión del vector de características

        self.attrs = [[] for _ in range(self.dim)] # Aquí almacenaremos las columnas del conjunto de entrenamiento.

        self.output_dom = {} # Clases de salida con el número de ocurrencias en el conjunto de entrenamiento. En este caso solo tenemos 2 clases

        self.data = [] # To store every row [Xi, yi]
        
        
        for i in range(len(self.X)):
            for j in range(self.dim):
                # si nunca hemos visto este valor para este atributo antes, 
                # luego lo agregamos a la matriz attrs en la posición correspondiente
                if not self.X[i][j] in self.attrs[j]:
                    self.attrs[j].append(self.X[i][j])
                    
            # si nunca hemos visto esta clase de salida antes,
            # luego lo agregamos a output_dom y contamos una ocurrencia por ahora
            if not self.y[i] in self.output_dom.keys():
                self.output_dom[self.y[i]] = 1
            # de lo contrario, incrementamos la ocurrencia de esta salida en el conjunto de entrenamiento en 1
            else:
                self.output_dom[self.y[i]] += 1
            # almacenar la fila
            self.data.append([self.X[i], self.y[i]])
            
            

    def classify(self, entry):

        solve = None # Resultado final
        max_arg = -1 # máximo parcial

        for y in self.output_dom.keys():

            prob = self.output_dom[y]/self.N # P(y)

            for i in range(self.dim):
                cases = [x for x in self.data if x[0][i] == entry[i] and x[1] == y] # all rows with Xi = xi
                n = len(cases)
                prob *= n/self.N # P *= P(Xi = xi)
                
            # si tenemos una probabilidad mayor para esta salida que el máximo parcial ...
            if prob &gt; max_arg:
                max_arg = prob
                solve = y

        return solve
</code></pre><p>Aquí, asumimos que cada característica tiene un dominio discreto. Eso significa que toman un valor de un conjunto finito de valores posibles.</p><p>Lo mismo ocurre con las clases. Ten en cuenta que almacenamos algunos datos en el método <code>__init__</code> por lo que no es necesario repetir algunas operaciones. La clasificación de una nueva entrada se lleva a cabo en el método <code>classify</code>.</p><blockquote>Este es un ejemplo simple de implementación. En las aplicaciones del mundo real, no necesitas (y es mejor si no creas) tu propia implementación. Por ejemplo, la biblioteca <code>sklearn</code> en Python contiene varias buenas implementaciones de NBC.</blockquote><p>¡Observa lo fácil que es implementarlo!</p><p>Ahora, apliquemos nuestro nuevo clasificador para resolver un problema. Tenemos un conjunto de datos con la descripción de 887 pasajeros en el Titanic. También podemos ver si un pasajero determinado sobrevivió a la tragedia o no.</p><p>Entonces, nuestra tarea es determinar si otro pasajero que no está incluido en el conjunto de entrenamiento lo hizo o no.</p><p>En este ejemplo, usaré la biblioteca de <code>pandas</code> para leer y procesar los datos. No utilizo ninguna otra herramienta.</p><p>Los datos se almacenan en un archivo llamado <em>titanic.csv</em>, por lo que el primer paso es leer los datos y obtener una descripción general.</p><pre><code class="language-python">import pandas as pd

data = pd.read_csv('titanic.csv')

print(data.head())
</code></pre><p>La salida es:</p><pre><code class="language-text">Survived  Pclass                                               Name  \
0         0       3                             Mr. Owen Harris Braund   
1         1       1  Mrs. John Bradley (Florence Briggs Thayer) Cum...   
2         1       3                              Miss. Laina Heikkinen   
3         1       1        Mrs. Jacques Heath (Lily May Peel) Futrelle   
4         0       3                            Mr. William Henry Allen   

      Sex   Age  Siblings/Spouses Aboard  Parents/Children Aboard     Fare  
0    male  22.0                        1                        0   7.2500  
1  female  38.0                        1                        0  71.2833  
2  female  26.0                        0                        0   7.9250  
3  female  35.0                        1                        0  53.1000  
4    male  35.0                        0                        0   8.0500  
</code></pre><p>Observa que tenemos el nombre de cada pasajero. No usaremos esa característica para nuestro clasificador porque no es significativa para nuestro problema. También eliminaremos la característica Fare (tarifa en inglés) porque es continua y nuestras funciones deben ser discretas.</p><blockquote>Hay clasificadores Naive Bayes que admiten caracterísitcas (features) continuas. Por ejemplo, el clasificador Naive Bayes Gausseano.</blockquote><pre><code class="language-python">y = list(map(lambda v: 'yes' if v == 1 else 'no', data['Survived'].values)) # valores objetivo como cadena

# No usaremos el campo 'Nombre'(Name) ni 'Tarifa' (Fare)

X = data[['Pclass', 'Sex', 'Age', 'Siblings/Spouses Aboard', 'Parents/Children Aboard']].values # valores de características
</code></pre><p>Luego, necesitamos separar nuestro conjunto de datos en un conjunto de entrenamiento y un conjunto de validación. El último se utiliza para validar qué tan bien está funcionando nuestro algoritmo.</p><pre><code class="language-python">print(len(y)) # &gt;&gt; 887

# Tomaremos 600 ejemplos para entrenar y el resto para el proceso de validación.
y_train = y[:600]
y_val = y[600:]

X_train = X[:600]
X_val = X[600:]
</code></pre><p>Creamos nuestro NBC con el conjunto de entrenamiento y luego clasificamos cada entrada en el conjunto de validación.</p><p>Medimos la precisión de nuestro algoritmo dividiendo el número de entradas que clasificó correctamente por el número total de entradas en el conjunto de validación.</p><pre><code class="language-python">## Crear la instancia de Naive Bayes Classifier con los datos de entrenamiento

nbc = NaiveBayesClassifier(X_train, y_train)


total_cases = len(y_val) # tamaño del conjunto de validación

# Ejemplos bien clasificados y ejemplos mal clasificados
good = 0
bad = 0

for i in range(total_cases):
    predict = nbc.classify(X_val[i])
#     print(y_val[i] + ' --------------- ' + predict)
    if y_val[i] == predict:
        good += 1
    else:
        bad += 1

print('TOTAL EXAMPLES:', total_cases)
print('RIGHT:', good)
print('WRONG:', bad)
print('ACCURACY:', good/total_cases)
</code></pre><p>La salida:</p><pre><code>TOTAL EXAMPLES: 287
RIGHT: 200
WRONG: 87
ACCURACY: 0.6968641114982579
</code></pre><p>No es genial pero es algo. Podemos obtener una mejora de aproximadamente un 10% en la precisión si eliminamos otras funciones como <em>hermanos / cónyuges a bordo</em> y <em>padres / hijos a bordo.</em></p><p>Puedes ver un cuaderno con el código y el conjunto de datos <a href="https://github.com/josejorgers/naive-bayes-classifier-example">aquí</a>.</p><h2 id="conclusiones">Conclusiones</h2><p>Hoy en día, tenemos redes neuronales y otros algoritmos de ML complejos y costosos por todas partes.</p><p>Los NBC son algoritmos muy sencillos que nos permiten conseguir buenos resultados en algunos problemas de clasificación sin necesidad de muchos recursos. También escalan muy bien, lo que significa que podemos agregar muchas más funciones y el algoritmo seguirá siendo rápido y confiable.</p><p>Incluso en el caso de que los NBC no fueran adecuados para el problema que estábamos tratando de resolver, podrían ser muy útiles como referencia.</p><p>Primero podríamos intentar resolver el problema usando un NBC con unas pocas líneas de código y poco esfuerzo. Luego podríamos intentar lograr mejores resultados con algoritmos más complejos y costosos.</p><p>Este proceso puede ahorrarnos mucho tiempo y nos da una retroalimentación inmediata sobre si los algoritmos complejos realmente valen la pena para nuestra tarea.</p><p>En este artículo, leíste sobre las probabilidades condicionales, la independencia y el teorema de Bayes. Esos son los conceptos matemáticos detrás de los clasificadores Naive Bayes.</p><p>Después de eso, vimos una implementación simple de un NBC y resolvimos el problema de determinar si un pasajero del Titanic sobrevivió al accidente.</p><p>Espero que este artículo te haya resultado útil. Puedes leer sobre temas relacionados con la informática en mi <a href="https://jj.hashnode.dev/">blog personal</a> y siguiéndome en <a href="https://twitter.com/josejorgexl">Twitter</a>.</p><p>Traducido del artículo de <a href="https://www.freecodecamp.org/news/author/jose/">Jose J. Rodríguez</a> - <a href="https://www.freecodecamp.org/news/how-naive-bayes-classifiers-work/">How Naive Bayes Classifiers Work – with Python Code Examples</a></p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Tutorial de Google BERT para PNL con aprendizaje automático ]]>
                </title>
                <description>
                    <![CDATA[ Hay muchas aplicaciones para el aprendizaje automático, y una de ellas es el procesamiento del lenguaje natural o PNL. PNL maneja cosas como respuestas de texto, descifrar el significado de las palabras dentro de un contexto y mantener conversaciones con nosotros. Ayuda a las computadoras a comprender el lenguaje humano ]]>
                </description>
                <link>https://www.freecodecamp.org/espanol/news/tutorial-de-google-bert-para-pnl-con-aprendizaje-automatico/</link>
                <guid isPermaLink="false">600f04dba4e0700982aa0cf7</guid>
                
                    <category>
                        <![CDATA[ Aprendizaje Automatico ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Fernando Cardellino ]]>
                </dc:creator>
                <pubDate>Tue, 30 Mar 2021 04:25:18 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/espanol/news/content/images/2021/01/BERT-Tutorial.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Hay muchas aplicaciones para el aprendizaje automático, y una de ellas es el procesamiento del lenguaje natural o PNL.</p><p>PNL maneja cosas como respuestas de texto, descifrar el significado de las palabras dentro de un contexto y mantener conversaciones con nosotros. Ayuda a las computadoras a comprender el lenguaje humano para que podamos comunicarnos de diferentes maneras.</p><p>Desde los bots de chat hasta las solicitudes de empleo y la clasificación de tu correo electrónico en diferentes carpetas, PNL se utiliza en todas partes a nuestro alrededor.</p><p>En esencia, el procesamiento del lenguaje natural es una combinación de informática y lingüística. La lingüística nos brinda las reglas que debemos usar para entrenar nuestros modelos de aprendizaje automático y obtener los resultados que buscamos.</p><p>Hay muchas razones por las que el procesamiento del lenguaje natural se ha convertido en una parte importante del aprendizaje automático. Ayuda a las máquinas a detectar el sentimiento de los comentarios de un cliente, puede ayudar a clasificar los tickets de soporte para cualquier proyecto en el que estés trabajando y puede leer y comprender el texto de manera coherente.</p><p>Y dado que opera con un conjunto de reglas lingüísticas, no tiene los mismos prejuicios que los humanos.</p><p>Dado que PNL es un área de estudio tan grande, hay una serie de herramientas que puedes utilizar para analizar datos para tus propósitos específicos.</p><p>Existe el enfoque basado en reglas en el que se configuran muchas declaraciones si-entonces (if-then) para manejar cómo se interpreta el texto. Por lo general, un lingüista será responsable de esta tarea y lo que producen es muy fácil de entender para la gente.</p><p>Esto puede ser bueno para empezar, pero se vuelve muy complejo a medida que comienzas a trabajar con grandes conjuntos de datos.</p><p>Otro enfoque es utilizar aprendizaje automático donde no es necesario definir reglas. Esto es excelente cuando intentas analizar grandes cantidades de datos de forma rápida y precisa.</p><p>Elegir el algoritmo correcto para que el enfoque de aprendizaje automático funcione es importante en términos de eficiencia y precisión. Existen algoritmos comunes como Naïve Bayes y Support Vector Machines. Luego están los algoritmos más específicos como Google BERT</p><h2 id="-qu-es-bert">¿Qué es BERT?</h2><p>BERT es una biblioteca de código abierto creada en 2018 en Google. Es una técnica nueva para PNL y adopta un enfoque de modelos de entrenamiento completamente diferente al de cualquier otra técnica.</p><p>BERT es un acrónimo de Representaciones de codificador bidireccional de Transformer. Eso significa que, a diferencia de la mayoría de las técnicas que analizan oraciones de izquierda a derecha o de derecha a izquierda, BERT va en ambas direcciones usando el codificador Transformer. Su objetivo es generar un modelo de lenguaje.</p><p>Esto le da una precisión y un rendimiento increíbles en conjuntos de datos más pequeños, lo que resuelve un gran problema en el procesamiento del lenguaje natural.</p><p>Si bien hay una gran cantidad de datos basados en texto disponibles, muy pocos de ellos se han etiquetado para usar en el entrenamiento de un modelo de aprendizaje automático. Dado que la mayoría de los enfoques para los problemas de PNL aprovechan el aprendizaje profundo (deep learning), necesita grandes cantidades de datos para entrenar.</p><p>Realmente se ven las grandes mejoras en un modelo cuando se ha entrenado con millones de datos. Para ayudar a solucionar este problema de no tener suficientes datos etiquetados, los investigadores encontraron formas de entrenar modelos de representación de lenguaje de propósito general a través del entrenamiento previo usando textos de Internet.</p><p>Estos modelos de representación previamente entrenados se pueden ajustar para que funcionen con conjuntos de datos específicos que son más pequeños que los que se usan comúnmente en el aprendizaje profundo. Estos conjuntos de datos más pequeños pueden ser para problemas como el análisis de opiniones o la detección de spam. Esta es la forma en que se abordan la mayoría de los problemas de PNL porque proporciona resultados más precisos que comenzar con un conjunto de datos más pequeño.</p><p>Es por eso que BERT es un gran descubrimiento. Proporciona una forma de pre-entrenar con mayor precisión tus modelos con menos datos. El enfoque bidireccional que utiliza significa que obtiene más contexto para una palabra que si solo estuviera entrenando en una dirección. Con este contexto adicional, puede aprovechar otra técnica llamada LM enmascarada.</p><h2 id="en-qu-se-diferencia-de-otros-algoritmos-de-aprendizaje-autom-tico">En qué se diferencia de otros algoritmos de aprendizaje automático</h2><p>El LM enmascarado enmascara al azar el 15% de las palabras en una oración con un símbolo o token [MASK] y luego trata de predecirlas basándose en las palabras que rodean a la palabra enmascarada. Así es como BERT puede ver las palabras de izquierda a derecha y de derecha a izquierda.</p><p>Esto es completamente diferente de cualquier otro modelo de lenguaje existente porque mira las palabras antes y después de una palabra enmascarada, al mismo tiempo. Gran parte de la precisión que tiene BERT se puede atribuir a esto.</p><p>Para que BERT funcione con tu conjunto de datos, debes agregar un poco de metadatos. Deberá haber <strong>incrustaciones de tokens (token embeddings)</strong> para marcar el principio y el final de las oraciones. Deberá tener <strong>incrustaciones de segmentos (segment embeddings)</strong> para poder distinguir diferentes oraciones. Por último, necesitará <strong>incrustaciones posicionales (positional embeddings)</strong> para indicar la posición de las palabras en una oración.</p><p>Se verá similar a esto.</p><pre><code>[CLS] the [MASK] has blue spots [SEP] it rolls [MASK] the parking lot [SEP]</code></pre><p>Con los metadatos agregados a tus puntos de datos (data points), LM enmascarado está listo para funcionar.</p><p>Una vez que ha terminado de predecir palabras, BERT aprovecha la predicción de la siguiente oración. Esto analiza la relación entre dos oraciones. Hace esto para comprender mejor el contexto de todo el conjunto de datos al tomar un par de oraciones y predecir si la segunda oración es la siguiente en función del texto original.</p><p>Para que la predicción de la siguiente oración funcione en la técnica BERT, la segunda oración se envía a través del modelo basado en Transformer.</p><p>Hay cuatro versiones diferentes de BERT previamente entrenadas según la escala de datos con la que estés trabajando. Puedes aprender más sobre ellos aquí: <a href="https://github.com/google-research/bert#bert">https://github.com/google-research/bert#bert</a></p><p>El inconveniente de este enfoque es que la función de pérdida solo considera las predicciones de palabras enmascaradas y no las predicciones de las demás. Eso significa que la técnica BERT converge más lentamente que las otras técnicas de derecha a izquierda o de izquierda a derecha.</p><p>BERT se puede aplicar a cualquier problema de PNL que se te ocurra, incluida la predicción de intenciones, las aplicaciones de respuesta a preguntas y la clasificación de texto.</p><h2 id="ejemplo-de-c-digo">Ejemplo de Código</h2><h3 id="prepar-ndote">Preparándote</h3><p>Ahora veremos un ejemplo de BERT en acción. Lo primero que deberás hacer es clonar el repositorio de Bert.</p><pre><code>git clone https://github.com/google-research/bert.git</code></pre><p>Ahora necesita descargar los archivos de modelo BERT previamente entrenados desde la <a href="https://github.com/google-research/bert#pre-trained-models">página BERT en GitHub</a>. A lo largo del resto de este tutorial, me referiré al directorio de este repositorio como directorio raíz.</p><p>Estos archivos te brindan los hiperparámetros, pesos y otras cosas que necesitas con la información que Bert aprendió durante el entrenamiento previo. Usaré el modelo <a href="https://storage.googleapis.com/bert_models/2018_10_18/uncased_L-12_H-768_A-12.zip">BERT-Base, Uncased</a>, pero encontrarás varias otras opciones en diferentes idiomas en la página de GitHub.</p><p>Algunas de las razones por las que elegirías el modelo BERT-Base, Uncased es si no tienes acceso a una TPU de Google, en cuyo caso normalmente elegirías un modelo Base.</p><p>Si cree que el texto que estás tratando de analizar distingue entre mayúsculas y minúsculas (esa distinción le da un significado contextual real), entonces optarías por un modelo de tipo Cased.</p><p>Si la distinción entre mayúsculas y minúsculas no es importante o aún no está muy seguro, entonces un modelo de tipo Uncased sería una opción válida.</p><p>Trabajaremos con algunas reseñas de Yelp como nuestro conjunto de datos. Recuerda, BERT espera los datos en un formato determinado utilizando esas <strong>incrustaciones de tokens </strong>y otros. Necesitaremos agregarlos a un archivo .tsv. Este archivo será similar a un .csv, pero tendrá cuatro columnas y ninguna fila de encabezado.</p><p>Así es como se verán las cuatro columnas.</p><ul><li>Columna 0: ID de la fila</li><li>Columna 1: Etiqueta de la fila (debe ser un número entero)</li><li>Columna 2: Una columna de la misma letra para todas las filas (no se usa para nada, pero BERT lo espera)</li><li>Columna 3: El texto que queremos clasificar</li></ul><p>Deberás crear una carpeta llamada datos en el directorio donde clonaste BERT y agregar tres archivos allí: <em>train.tsv</em>, <em>dev.tsv</em>, <em>test.tsv.</em></p><p>En los archivos <em>train.tsv</em> y <em>dev.tsv</em>, tendremos las cuatro columnas de las que hablamos anteriormente. En el archivo <em>test.tsv</em>, solo tendremos el ID de fila y el texto que queremos clasificar como columnas. Estos serán los archivos de datos que usaremos para entrenar y probar nuestro modelo.</p><h3 id="preparando-los-datos">Preparando los datos</h3><p>Primero necesitamos obtener los datos con los que trabajaremos. Puedes descargar las reseñas de Yelp aquí: <a href="https://course.fast.ai/datasets#nlp">https://course.fast.ai/datasets#nlp</a> Estará en la sección NLP y querrás la versión Polarity.</p><p>La razón por la que trabajaremos con esta versión es porque los datos ya tienen una polaridad, lo que significa que ya tienen un sentimiento asociado. Guarda este archivo en el directorio de datos.</p><p>Ahora estamos listos para comenzar a escribir código. Crea un nuevo archivo en el directorio raíz llamado <em>pre_processing.py</em> y agrega el siguiente código.</p><pre><code class="language-python">import pandas as pd
# esto es para extraer los datos de ese archivo .tgz
import tarfile
from sklearn.preprocessing import LabelEncoder
from sklearn.model_selection import train_test_split

# obtener todos los datos de ese .tgz
yelp_reviews = tarfile.open('data/yelp_review_polarity_csv.tgz')
yelp_reviews.extractall('data')
yelp_reviews.close()

# comprueba cómo se ven los datos antes de empezar
# mira el conjunto de datos de entrenamiento
train_df = pd.read_csv('data/yelp_review_polarity_csv/train.csv', header=None)
print(train_df.head())

# mira el conjunto de datos de prueba
test_df = pd.read_csv('data/yelp_review_polarity_csv/test.csv', header=None)
print(test_df.head())</code></pre><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2020/07/image-44.png" class="kg-image" alt="image-44" width="600" height="400" loading="lazy"></figure><p>En este código, hemos importado algunos paquetes de Python y descomprimimos los datos para ver cómo se ven. Notarás que los valores asociados con las reseñas son 1 y 2, siendo 1 una mala reseña y 2 una buena reseña. Necesitamos convertir estos valores a etiquetas más estándar, es decir 0 y 1. Puedes hacerlo con el siguiente código.</p><pre><code class="language-python">train_df[0] = (train_df[0] == 2).astype(int)
test_df[0] = (test_df[0] == 2).astype(int)</code></pre><p>Siempre que realizes cambios a tus datos, es importante comprobar si todo salió bien. Entonces lo haremos con los siguientes comandos.</p><pre><code class="language-python">print(train_df.head())
print(test_df.head())</code></pre><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2020/07/image-45.png" class="kg-image" alt="image-45" width="600" height="400" loading="lazy"></figure><p>Cuando veas que tus valores de polaridad han cambiado para ser lo que esperabas. Ahora los datos deberían tener unos y ceros.</p><p>Dado que hemos limpiado los datos iniciales, es hora de preparar las cosas para BERT. Tendremos que hacer que nuestros datos se ajusten a los formatos de columna de los que hablamos anteriormente. Comencemos con los datos de entrenamiento.</p><p>Los datos de entrenamiento tendrán las cuatro columnas: ID de fila, etiqueta de fila, letra única, texto que queremos clasificar.</p><p>BERT espera dos archivos para entrenamiento llamados <em>train</em> y <em>dev</em>. Crearemos esos archivos dividiendo el archivo de entrenamiento inicial en dos archivos después de formatear nuestros datos con los siguientes comandos.</p><pre><code class="language-python">bert_df = pd.DataFrame({
    'id': range(len(train_df)),
    'label': train_df[0],
    'alpha': ['q']*train_df.shape[0],
    'text': train_df[1].replace(r'\n', ' ', regex=True)
})

train_bert_df, dev_bert_df = train_test_split(bert_df, test_size=0.01)</code></pre><p>Con la variable <em>bert_df</em>, hemos formateado los datos para que sean los que espera BERT. Puedes elegir cualquier otra letra para el valor alpha si lo deseas. El método <em>train_test_split</em> que importamos al principio se encarga de dividir los datos de entrenamiento en los dos archivos que necesitamos.</p><p>Observa cómo se formatearon los datos con este comando.</p><pre><code class="language-python">print(train_bert_df.head())</code></pre><p>Ahora necesitamos formatear los datos de prueba. Esto se verá diferente de cómo manejamos los datos de entrenamiento. BERT solo espera dos columnas para los datos de prueba: ID de fila, texto que queremos clasificar. No necesitamos hacer nada más con los datos de prueba una vez que los tengamos en este formato y lo haremos con el siguiente comando.</p><pre><code class="language-python">test_bert_df = pd.DataFrame({
    'id': range(len(test_df)),
    'text': test_df[1].replace(r'\n', ' ', regex=True)
})</code></pre><p>Es similar a lo que hicimos con los datos de entrenamiento, solo que sin dos de las columnas. Echa un vistazo a los datos de prueba recién formateados.</p><pre><code class="language-python">test_bert_df.head()</code></pre><p>Si todo se ve bien, puede guardar estas variables como los archivos .tsv con los que trabajará BERT.</p><pre><code class="language-python">train_bert_df.to_csv('data/train.tsv', sep='\t', index=False, header=False)
dev_bert_df.to_csv('data/dev.tsv', sep='\t', index=False, header=False)
test_bert_df.to_csv('data/test.tsv', sep='\t', index=False, header=False)</code></pre><h3 id="entrenando-el-modelo">Entrenando el modelo</h3><p>Una nota rápida antes de comenzar a entrenar el modelo: BERT puede consumir muchos recursos en las computadoras portátiles. Puede causar errores de memoria porque no hay suficiente RAM o algún otro hardware no es lo suficientemente potente. Podrías intentar hacer que <em>training_batch_size</em> sea más pequeño, pero eso hará que el entrenamiento del modelo sea realmente lento.</p><p>Agrega una carpeta al directorio raíz llamada <em>model_output</em>. Ahí es donde se guardará nuestro modelo una vez finalizado el entrenamiento. Ahora abre una terminal y ve al directorio raíz de este proyecto. Una vez que estés en el directorio correcto, ejecuta el siguiente comando y comenzará a entrenar tu modelo.</p><pre><code class="language-bash">python run_classifier.py --task_name=cola --do_train=true --do_eval=true --data_dir=./data/ --vocab_file=./uncased_L-12_H-768_A-12/vocab.txt --bert_config_file=./uncased_L-12_H-768_A-12/bert_config.json --init_checkpoint=./uncased_L-12_H768_A-12/bert_model.ckpt.index --max_seq_length=128 --train_batch_size=32 --learning_rate=2e-5 --num_train_epochs=3.0 --output_dir=./model_output --do_lower_case=False</code></pre><p>Deberías ver algunos resultados desplazándose a través de tu terminal. Una vez que esto termine de ejecutarse, tendrás un modelo entrenado que está listo para hacer predicciones.</p><h3 id="haciendo-una-predicci-n">Haciendo una predicción</h3><p>Si echas un vistazo al directorio <em>model_output</em>, notarás que hay un montón de archivos <em>model.ckpt.</em> Estos archivos tienen los pesos del modelo entrenado en diferentes puntos durante el entrenamiento, por lo que deseas encontrar el que tenga el número más alto. Ese será el modelo entrenado final que querrás usar.</p><p>Ahora ejecutaremos <em>run_classifier.py</em> nuevamente con opciones ligeramente diferentes. En particular, cambiaremos el valor <em>init_checkpoint</em> al punto de control del modelo más alto y estableceremos un nuevo valor <em>--do_predict</em> en verdadero. Aquí está el comando que necesitas ejecutar en tu terminal.</p><pre><code class="language-bash">python run_classifier.py --task_name=cola --do_predict=true --data_dir=./data --vocab_file=./uncased_L-12_H-768-A-12/bert_config.json --init_checkpoint=./model_output/model.ckpt-&lt;highest checkpoint number&gt; --max_seq_length=128 --output_dir=./model_output</code></pre><p>Una vez que el comando termine de ejecutarse, debería ver un nuevo archivo llamado <em>test_results.tsv</em>. ¡Esto tendrá tus resultados predichos basados en el modelo que entrenaste!</p><p>Acabas de utilizar BERT para analizar algunos datos reales y, con suerte, todo esto tiene sentido.</p><h2 id="otros-pensamientos">Otros pensamientos</h2><p>Sentí que era necesario pasar por el proceso de limpieza de datos aquí en caso de que alguien no lo haya pasado antes. A veces, el aprendizaje automático parece mágico, pero realmente se trata de tomarse el tiempo para que tus datos estén en las condiciones adecuadas para entrenar con un algoritmo.</p><p>BERT todavía es relativamente nuevo desde que se lanzó en 2018, pero hasta ahora ha demostrado ser más preciso que los modelos existentes, incluso si es más lento.</p><p>Traducido del artículo de <a href="https://www.freecodecamp.org/news/author/milecia/">Milecia McGregor</a> - <a href="https://www.freecodecamp.org/news/google-bert-nlp-machine-learning-tutorial/">Google BERT NLP Machine Learning Tutorial</a></p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Tutorial para un clasificador basado en bosques aleatorios: cómo utilizar algoritmos basados en árboles para el aprendizaje automático ]]>
                </title>
                <description>
                    <![CDATA[ Los algoritmos basados en árboles son métodos populares de aprendizaje automático que se utilizan para resolver problemas de aprendizaje supervisado. Estos algoritmos son flexibles y pueden resolver cualquier tipo de problema (clasificación o regresión). Los algoritmos basados en árboles tienden a usar la media para características (features) continuas o el ]]>
                </description>
                <link>https://www.freecodecamp.org/espanol/news/random-forest-classifier-tutorial-how-to-use-tree-based-algorithms-for-machine-learning/</link>
                <guid isPermaLink="false">600ee747a4e0700982aa0a6c</guid>
                
                    <category>
                        <![CDATA[ Aprendizaje Automatico ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Fernando Cardellino ]]>
                </dc:creator>
                <pubDate>Mon, 22 Mar 2021 04:28:14 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/espanol/news/content/images/2021/01/random_tree.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Los algoritmos basados en árboles son métodos populares de aprendizaje automático que se utilizan para resolver problemas de aprendizaje supervisado. Estos algoritmos son flexibles y pueden resolver cualquier tipo de problema (clasificación o regresión).</p><p>Los algoritmos basados en árboles tienden a usar la <strong>media</strong> para características (features) continuas o el <strong>modo</strong> para características categóricas cuando hacen predicciones sobre muestras de entrenamiento en las regiones a las que pertenecen. También producen predicciones con <strong>alta precisión</strong>, <strong>estabilidad</strong> y <strong>facilidad de interpretación</strong>.</p><h1 id="ejemplos-de-algoritmos-basados-en-rboles">Ejemplos de algoritmos basados en árboles</h1><p>Hay diferentes algoritmos basados en árboles que puedes usar, como por ejemplo</p><ul><li>Árboles de Decisiones (Decision Trees)</li><li>Bosques Aleatorios (Random Forest)</li><li>Aumento de Gradiente (Gradient Boosting)</li><li>Bagging (Agregación Bootstrap &nbsp;"Bootstrap Aggregation")</li></ul><p>Por lo tanto, todo científico de datos debería aprender estos algoritmos y usarlos en sus proyectos de aprendizaje automático.</p><p>En este artículo, aprenderás sobre el algoritmo de bosques aleatorios (random forest). Después de completar este artículo, podrás dominar el uso del algoritmo de bosque aleatorio para resolver y crear modelos predictivos para problemas de clasificación con scikit-learn.</p><h1 id="-qu-es-el-algoritmo-de-bosques-aleatorios">¿Qué es el algoritmo de bosques aleatorios?</h1><p>Bosque aleatorio es uno de los algoritmos de aprendizaje supervisado basados en árboles más populares. También es el más flexible y fácil de usar.</p><p>El algoritmo se puede utilizar para resolver problemas de clasificación y regresión. El bosque aleatorio tiende a combinar cientos de <strong>árboles de decisión</strong> y luego entrena cada árbol de decisión en una muestra diferente de las observaciones.</p><p>Las predicciones finales del bosque aleatorio se realizan promediando las predicciones de cada árbol individual.</p><p>Los beneficios son numerosos. Los árboles de decisión individuales tienden a <strong>sobre ajustarse (overfit)</strong> a los datos de entrenamiento, pero el bosque aleatorio puede mitigar ese problema al <strong>promediar</strong> los resultados de predicción de diferentes árboles. Esto le da al algoritmo de bosques aleatorios una mayor precisión predictiva que un solo árbol de decisión.</p><p>El algoritmo de bosque aleatorio también puede ayudarte a encontrar características que son importantes en tu conjunto de datos. Esto se debe al algoritmo de Boruta, que selecciona características importantes en un conjunto de datos.</p><p>El bosque aleatorio se ha utilizado en una variedad de aplicaciones, por ejemplo, para proporcionar recomendaciones de diferentes productos a los clientes en el comercio electrónico.</p><p>En medicina, el algoritmo puede ser utilizado para identificar la enfermedad del paciente a través del análisis de su historial médico.</p><p>También en el sector bancario, puede ser utilizado para determinar fácilmente si el cliente es fraudulento o legítimo.</p><h1 id="-c-mo-funciona-el-algoritmo-de-bosques-aleatorios">¿Cómo funciona el algoritmo de bosques aleatorios?</h1><p>El algoritmo funciona completando los siguientes pasos: </p><p><strong>Paso 1</strong>: El algoritmo selecciona muestras en forma aleatoria de la base de datos proporcionada.</p><p><strong>Paso 2: </strong>El algoritmo creará un árbol de decisión para cada muestra seleccionada. Luego obtendrá un resultado de predicción de cada árbol creado.</p><p><strong>Paso 3: </strong>A continuación, se realizará la votación para cada resultado previsto. Para un problema de clasificación, usará la <strong>moda</strong>, y para un problema de regresión, usará la <strong>media</strong>.</p><p><strong>Paso 4</strong>: Y finalmente, el algoritmo seleccionará el resultado de predicción más votado como predicción final.</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2020/08/how-random-forest-classifier-work.PNG" class="kg-image" alt="how-random-forest-classifier-work" width="600" height="400" loading="lazy"><figcaption>como funciona</figcaption></figure><h1 id="algoritmo-de-bosques-aleatorios-en-la-pr-ctica">Algoritmo de bosques aleatorios en la práctica</h1><p><br>Ahora que conoces el funcionamiento del algoritmo de bosque aleatorio, creemos un clasificador.</p><p>Construiremos un clasificador utilizando el conjunto de datos de diabetes de los indios Pima. El conjunto de datos de diabetes de los indios Pima implica predecir la aparición de la diabetes en un plazo de 5 años según los detalles médicos proporcionados. Este es un problema de clasificación binaria.</p><p>Nuestro objetivo es analizar y crear un modelo sobre aquel conjunto de datos para predecir si un paciente en particular tiene riesgo de desarrollar diabetes, dados otros factores independientes.</p><p>Comenzaremos importando paquetes importantes que usaremos para cargar el conjunto de datos y crear un clasificador de bosque aleatorio. Usaremos la biblioteca scikit-learn para cargar y usar el algoritmo de bosque aleatorio.</p><pre><code class="language-python"># importar paquetes importantes
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns

%matplotlib inline

from sklearn.model_selection import train_test_split
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import accuracy_score
from sklearn.preprocessing import StandardScaler, MinMaxScaler
import pandas_profiling

from matplotlib import rcParams
import warnings

warnings.filterwarnings("ignore")

# tamaño de la figura en pulgadas
rcParams["figure.figsize"] = 10, 6
np.random.seed(42)</code></pre><h3 id="conjunto-de-datos">Conjunto de datos</h3><p>Luego, carga el conjunto de datos desde el directorio de datos:</p><pre><code class="language-python"># Cargar conjunto de datos
data = pd.read_csv("../data/pima_indians_diabetes.csv")</code></pre><p>Ahora podemos observar la muestra del conjunto de datos.</p><pre><code class="language-python">
# mostrar muestra del conjunto de datos
data.sample(5)</code></pre><figure class="kg-card kg-image-card kg-width-wide"><img src="https://www.freecodecamp.org/news/content/images/2020/08/5-rows.PNG" class="kg-image" alt="5-rows" width="600" height="400" loading="lazy"></figure><p>Como puedes ver, en nuestro conjunto de datos tenemos deferentes características con valores numéricos.</p><p>Entendamos la lista de características que tenemos en este conjunto de datos.</p><pre><code class="language-python"># mostrar columnas
data.columns</code></pre><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2020/08/columns.PNG" class="kg-image" alt="columns" width="600" height="400" loading="lazy"></figure><p>En este conjunto de datos, hay 8 características &nbsp;de entrada y 1 característica de salida / destino. Se cree que los valores que faltan están codificados con valor cero. El significado de los nombres de las características es el siguiente (desde la primera hasta la última):</p><ul><li>Número de embarazos.</li><li>Concentración de glucosa en plasma a 2 horas en una prueba oral de tolerancia a la glucosa.</li><li>Presión arterial diastólica (mm Hg).</li><li>Espesor del pliegue cutáneo del tríceps (mm).</li><li>Insulina sérica de 2 horas (mu U / ml).</li><li>Índice de masa corporal (peso en kg / (altura en m) ^ 2).</li><li>Función del pedigrí de la diabetes.</li><li>Edad (años).</li><li>Variable de clase (0 o 1).</li></ul><p>Luego, dividimos el conjunto de datos en características independientes y característica &nbsp;de destino. Nuestra característica de destino para este conjunto de datos se llama <strong>class</strong>.</p><pre><code class="language-python"># dividir los datos en características de entrada y de destino

X = data.drop("class", axis=1)
y = data["class"]</code></pre><h3 id="preprocesamiento-del-conjunto-de-datos">Preprocesamiento del Conjunto de Datos</h3><p>Antes de crear un modelo, necesitamos estandarizar nuestras características independientes usando el método <code>standardScaler</code> de scikit-learn.</p><pre><code class="language-python"># estandarizar el conjunto de datos
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)</code></pre><h3 id="dividiendo-el-conjunto-de-datos-en-datos-de-entrenamiento-y-prueba">Dividiendo el conjunto de datos en datos de entrenamiento y prueba</h3><p>Ahora dividimos nuestro conjunto de datos procesados en datos de prueba y entrenamiento. Los datos de prueba serán el 10% de todo el conjunto de datos procesados.</p><pre><code class="language-python"># dividir en conjunto de entrenamiento (train) y 
#conjunto de prueba (test)
X_train, X_test, y_train, y_test = train_test_split(
    X_scaled, y, stratify=y, test_size=0.10, random_state=42
)</code></pre><h3 id="construyendo-el-clasificador-de-bosque-aleatorio">Construyendo el Clasificador de bosque aleatorio</h3><p>Ahora es el momento de crear nuestro clasificador de bosque aleatorio y luego entrenarlo en el conjunto de entrenamiento. También pasaremos el número de árboles (100) del bosque que queremos usar mediante el parámetro llamado <strong>n_estimators</strong>.</p><pre><code class="language-python"># crear el clasificador
classifier = RandomForestClassifier(n_estimators=100)

# Entrenar el modelo usando el conjunto de entranamiento
classifier.fit(X_train, y_train)</code></pre><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2020/08/default-parameters.PNG" class="kg-image" alt="default-parameters" width="600" height="400" loading="lazy"></figure><p>El resultado anterior muestra diferentes valores de parámetros del clasificador de bosque aleatorio utilizado durante el proceso de entrenamiento en los datos de entrenamiento.</p><p>Después del entrenamiento, podemos realizar predicciones sobre los datos de la prueba.</p><pre><code class="language-python"># predicción en el conjunto de prueba
y_pred = classifier.predict(X_test)</code></pre><p>Luego, verificamos la precisión utilizando los valores reales y los predichos de los datos de prueba.</p><pre><code class="language-python"># Calcular la precisión del modelo
print("Precisión:", accuracy_score(y_test, y_pred))</code></pre><p>Precisión: 0.8051948051948052</p><p>Nuestra precisión es de alrededor del 80,5%, lo cual es bueno. Pero siempre podemos hacerlo mejor.</p><h3 id="identificar-caracter-sticas-importantes">Identificar características importantes</h3><p>Como dije antes, también podemos verificar las características importantes usando la variable <strong>feature_importances_</strong> del algoritmo de bosque aleatorio en scikit-learn.</p><pre><code class="language-python"># verificar características importantes
feature_importances_df = pd.DataFrame(
    {"feature": list(X.columns), "importance": classifier.feature_importances_}
).sort_values("importance", ascending=False)

# Mostrar
feature_importances_df</code></pre><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2020/08/feature-importance-list.PNG" class="kg-image" alt="feature-importance-list" width="600" height="400" loading="lazy"><figcaption>Important Features</figcaption></figure><p>La figura anterior muestra la importancia relativa de las características y su contribución al modelo. También podemos visualizar estas características y sus puntuaciones utilizando las bibliotecas seaborn y matplotlib.</p><pre><code class="language-python"># visualizarcaracterísticas importantes

# Crear un diagrama de barras
sns.barplot(x=feature_importances_df.feature, y=feature_importances_df.importance)
# agregar estiquestas

plt.xlabel("Feature Importance Score")
plt.ylabel("Features")
plt.title("Visualizing Important Features")
plt.xticks(
    rotation=45, horizontalalignment="right", fontweight="light", fontsize="x-large"
)
plt.show()</code></pre><figure class="kg-card kg-image-card kg-width-wide"><img src="https://www.freecodecamp.org/news/content/images/2020/08/visualize-feature-importance.PNG" class="kg-image" alt="visualize-feature-importance" width="600" height="400" loading="lazy"></figure><p>En la figura anterior, puedes ver que la variable <strong>triceps_skinfold_thickness</strong> tiene poca importancia y no contribuye mucho a la predicción.</p><p>Esto significa que podemos eliminar esta variable y entrenar nuestro clasificador &nbsp;nuevamente y luego ver si puede mejorar su rendimiento en los datos de prueba.</p><pre><code class="language-python"># cargar datos con características seleccionadas
X = data.drop(["class", "triceps_skinfold_thickness"], axis=1)
y = data["class"]

# estandarizar el conjunto de datos
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)

# dividir en conjunto de entrenamiento y de prueba
X_train, X_test, y_train, y_test = train_test_split(
    X_scaled, y, stratify=y, test_size=0.10, random_state=42
)</code></pre><p>Entrenaremos el algoritmo con las características procesadas seleccionadas de nuestro conjunto de datos, realizaremos predicciones y luego calcularemos la precisión del modelo.</p><pre><code class="language-python"># crear clasificador
clf = RandomForestClassifier(n_estimators=100)

# Entrenar el modelo usando el conjunto de entrenamiento
clf.fit(X_train, y_train)

# predicción en el conjunto de prueba
y_pred = clf.predict(X_test)

# Calcular la precisión del modelo,
print("Precisión:", accuracy_score(y_test, y_pred))</code></pre><p>Precisión: 0.8181818181818182</p><p>Ahora, la precisión del modelo ha aumentado del <strong>80,5%</strong> al <strong>81,8%</strong> después de que eliminamos la característica menos importante llamada <em>triceps_skinfold_thickness</em>.</p><p>Esto sugiere que es muy importante verificar las características importantes y ver si puedes eliminar las menos importantes para aumentar el rendimiento de su modelo.</p><h1 id="en-resumen">En resumen</h1><p>Los algoritmos basados en árboles son realmente importantes para que los aprenda todo científico de datos. En este artículo, has aprendido los conceptos básicos de los algoritmos basados en árboles y cómo crear un modelo de clasificación utilizando el algoritmo de bosque aleatorio.</p><p>¡Felicitaciones, has llegado al final de este artículo!</p><p>Si aprendiste algo nuevo o disfrutaste leyendo este artículo, compártelo para que otros puedan verlo. Hasta entonces, ¡nos vemos en el próximo post! También me pueden contactar en Twitter <a href="https://twitter.com/Davis_McDavid">@Davis_McDavid</a></p><p>Traducido del artículo de <a href="https://www.freecodecamp.org/news/author/davis/">Davis David</a> - <a href="https://www.freecodecamp.org/news/how-to-use-the-tree-based-algorithm-for-machine-learning/">Random Forest Classifier Tutorial: How to Use Tree-Based Algorithms for Machine Learning</a></p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ La guía definitiva del paquete NumPy para computación científica en Python ]]>
                </title>
                <description>
                    <![CDATA[ NumPy (se pronuncia "numb pie") es uno de los paquetes más importantes a entender cuando estás comenzando a aprender Python. El paquete es conocido por una estructura de datos muy útil llamado arreglo de NumPy. NumPy también permite a los desarrolladores de Python realizar en forma rápida una amplia variedad ]]>
                </description>
                <link>https://www.freecodecamp.org/espanol/news/la-guia-definitiva-del-paquete-numpy-para-computacion-cientifica-en-python/</link>
                <guid isPermaLink="false">6002eeb6a4e0700982a9de01</guid>
                
                    <category>
                        <![CDATA[ Numpy ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Fernando Cardellino ]]>
                </dc:creator>
                <pubDate>Sat, 20 Mar 2021 05:38:17 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/espanol/news/content/images/2021/01/numpy.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>NumPy (se pronuncia "numb pie") es uno de los paquetes más importantes a entender cuando estás comenzando a aprender Python.</p><p>El paquete es conocido por una estructura de datos muy útil llamado arreglo de NumPy. NumPy también permite a los desarrolladores de Python realizar en forma rápida una amplia variedad de cálculo numéricos.</p><p>Este tutorial te enseñará los fundamentos de NumPy que puedes usar para crear aplicaciones numéricas en Python hoy.</p><h2 id="tabla-de-contenidos"><strong>Tabla de Contenidos</strong></h2><p>Puedes saltear una sección específica de este tutorial de NumPy utilizando esta tabla de contenidios:</p><ul><li>Introducción a NumPy</li><li>Arreglos de NumPy</li><li>Métodos y Operaciones de NumPy</li><li>Indexaciones y Asignaciones en NumPy</li><li>Pensamientos finales y oferta especial</li></ul><h2 id="introducci-n-a-numpy"><strong>Introducción a NumPy</strong></h2><p>En esta sección, introduciremos la librería de NumPy en Python.</p><h3 id="-qu-es-numpy"><strong>¿Qué es NumPy?</strong></h3><p>NumPy es una librería de Python para computación científica. NumPy significa &nbsp;Python numérico. Aquí está la descripción oficial de la librería indicada en su página web:</p><p><em>"NumPy es el paquete fundamental para la computación científica con Python. Contiene entre otras cosas:</em></p><ul><li><em>un poderoso objeto de </em>arreglo<em> N-dimensional</em></li><li><em>funciones (</em>radiodifusión<em>) sofisticadas</em></li><li><em>herramientas para integrar </em>código<em> en C/C++ y Fortran</em></li><li><em>útiles capacidades de álgebra lineal, transformación de Fourier y números aleatorios</em></li></ul><p><em>Además de sus obvios usos científicos, NumPy puede ser utilizado como un eficiente contenedor multidimensional de datos </em>genéricos<em>. Tipos de datos arbitrarios puede ser definidos. Esto permite que NumPy se integre sin problemas y con rapidez con una amplia variedad de bases de datos.</em></p><p><em>NumPy está licenciado bajo el formato BSD, lo que permite la reutilización con pocas restricciones".</em></p><p>NumPy es una librería de Python tan importante que hay otras librerías (incluyendo pandas) que están construidas enteramente sobre NumPy.</p><h3 id="el-principal-beneficio-de-numpy"><strong>El principal beneficio de NumPy</strong></h3><p>El principal beneficio de NumPy es que permite una generación y manejo de datos extremadamente rápido. NumPy tiene su propia estructura de datos incorporada llamado <code>arreglo</code> que es similar a la <code>lista</code> normal de Python, pero puede almacenar y operar con datos de manera mucho más eficiente.</p><h3 id="que-aprenderemos-sobre-numpy"><strong>Que aprenderemos sobre NumPy</strong></h3><p>Los practicantes avanzados de Python pasarán mucho más tiempo trabajando con pandas que trabajando con NumPy. AUn así, dado que pandas se basa en NumPy, es importante comprender los aspectos más importantes de la biblioteca NumPy.</p><p>En las siguientes secciones, cubriremos la siguiente información sobre la librería de NumPy:</p><ul><li>Arreglos de NumPy</li><li>Indexación y asignación de NumPy</li><li>Métodos y operaciones de NumPy</li></ul><h3 id="continuemos"><strong>Continuemos</strong></h3><p>Pasemos a aprender sobre los arreglos de NumPy, la estructura de datos central con la que todo profesional de NumPy debe estar familiarizado.</p><h2 id="arreglos-de-numpy"><strong>Arreglos de NumPy</strong></h2><p>En esta sección, aprenderemos sobre los arreglos de NumPy.</p><h3 id="-qu-son-los-arreglos-de-numpy"><strong>¿Qué son los Arreglos de NumPy?</strong></h3><p>Los arreglos NumPy son la forma principal de almacenar datos utilizando la biblioteca NumPy. Son similares a las listas normales en Python, pero tienen la ventaja de ser más rápidas y tener más métodos integrados.</p><p>Los arreglos de NumPy son creados llamando al método <code>array()</code> de la librería de NumPy. Dentro del método, deberías pasar una lista.</p><p>A continuación, se muestra un ejemplo de un arreglo de NumPy básico. Ten en cuenta que mientras ejecuto la instrucción <code>import numpy as np</code> al comienzo de este bloque de código, se excluirá de los otros bloques de código en esta sección por razones de brevedad.</p><pre><code>import numpy as np

sample_list = [1, 2, 3]

np.array(sample_list)
</code></pre><p>La última línea de ese bloque de código dará como resultado una salida que se ve así.</p><pre><code>array([1,2,3])
</code></pre><p>El contenedor <code>array()</code> indica que esta ya no es una lista normal de Python. En cambio, es un arreglo de NumPy.</p><h3 id="los-dos-tipos-diferentes-de-arreglos-de-numpy"><strong>Los dos tipos diferentes de arreglos de NumPy</strong></h3><p>Hay dos tipos diferentes de arreglos de NumPy: vectores y matrices.</p><p>Los vectores son arreglos de NumPy uni-dimensionales y se ve así:</p><pre><code>my_vector = np.array(['este', 'es', 'un', 'vector'])
</code></pre><p>Las matrices son arreglo bi-dimensionales y son creadas pasando una lista de lista dentro del método <code>np.array()</code>. Un ejemplo es el siguiente.</p><pre><code>my_matrix = [[1, 2, 3],[4, 5, 6],[7, 8, 9]]

np.array(my_matrix)
</code></pre><p>También puedes expandir los arreglos de NumPy para trabajar con matrices de tres, cuatro, cinco, seis o más dimensiones, pero son raras y están en gran parte fuera del alcance de este curso (después de todo, este es un curso sobre programación Python, no álgebra lineal).</p><h3 id="arreglos-de-numpy-m-todos-incorporados"><strong>Arreglos de NumPy: Métodos Incorporados</strong></h3><p>Los arreglos de NumPy vienen con un número de métodos incorporados útiles. Dedicaremos el resto de esta sección analizando estos métodos en detalle.</p><h4 id="c-mo-obtener-un-rango-de-n-meros-en-python-utilizando-numpy"><strong>Cómo obtener un rango de números en Python utilizando Numpy</strong></h4><p>NumPy tiene un método útil llamado <code>arange</code> que toma dos números y devuelve un arreglo de números enteros que son mayores o iguales a (<code>&gt;=</code>) el primer número y menores que (<code>&lt;</code>) el segundo número.</p><p>Un ejemplo del método <code>arange</code> es el siguiente.</p><pre><code>np.arange(0,5)

#Devuevle array([0, 1, 2, 3, 4])
</code></pre><p>También puedes incluir una tercera variable en el método <code>arange</code> que proporciona un tamaño de paso para que la función regrese. Pasar <code>2</code> como tercera variable devolverá cada segundo número en el rango, pasar <code>5</code> como tercera variable devolverá cada quinto número en el rango, y así sucesivamente.</p><p>Un ejemplo de uso de la tercera variable en el método <code>arange</code> se encuentra a continuación.</p><pre><code>np.arange(1,11,2)

#Returns array([1, 3, 5, 7, 9])
</code></pre><h3 id="c-mo-generar-unos-y-ceros-en-python-usando-numpy"><strong>Cómo generar Unos y Ceros en Python usando NumPy</strong></h3><p>Mientras programas, de vez en cuando necesitará crear arreglos de unos o ceros. NumPy tiene métodos incorporados que te permiten hacer ambas cosas.</p><p>Podemos crear arreglos de ceros utilizando el método <code>zeros</code> de NumPy. Le pasas el número de enteros que quisieras crear como el argumento de la función. Un ejemplo es el siguiente.</p><pre><code>np.zeros(4)

#Devuelve array([0, 0, 0, 0])
</code></pre><p>También puedes hacer algo similar utilizando matrices tridimensionales. Por ejemplo, <code>np.zeros(5, 5)</code> crea un arreglo de 5x5 que contiene todos ceros.</p><p>Podemos crear arreglos de unos usando un método similar llamado <code>ones</code>. Un ejemplo es el que sigue.</p><pre><code>np.ones(5)

#Returns array([1, 1, 1, 1, 1])
</code></pre><h4 id="c-mo-dividir-uniformemente-un-rango-de-n-meros-en-python-usando-numpy">Cómo dividir uniformemente un rango de números en Python usando NumPy</h4><p>Hay muchas situaciones en las que tienes un rango de números y te gustaría dividir por igual ese rango de números en intervalos. El método <code>linspace</code> de NumPy está diseñado para resolver este problema. <code>linspace</code> tiene tres argumentos:</p><ol><li>El inicio del intervalo</li><li>El fin del intervalo</li><li>El número de subintervalos en los que deseas que se divida el intervalo</li></ol><p>Un ejemplo del método <code>linspace</code> es el siguiente.</p><pre><code>np.linspace(0, 1, 10)

#Devuelve array([0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0])
</code></pre><h4 id="c-mo-crear-un-arreglo-identidad-en-python-usando-numpy"><strong>Cómo crear un arreglo Identidad en Python usando NumPy</strong></h4><p>Cualquiera que haya estudiado álgebra lineal estará familiarizado con el concepto de un "arregloidentidad", que es un arreglo cuadrada cuyos valores diagonales son todos <code>1</code>. NumPy tiene una función incorporada que incluye un argumento para construir matrices de identidad. La función es <code>eye</code>.</p><p>Algunos ejemplos:</p><pre><code>np.eye(1)

#Devuelve un arreglo identidad de 1x1

np.eye(2) 

#Devuelve un arreglo identidad de 2x2

np.eye(50)

#Devuelve un arreglo identidad de 50x50
</code></pre><h4 id="c-mo-crear-n-meros-aleatorios-en-python-usando-numpy"><strong>Cómo crear números </strong>aleatorios<strong> en Python usando NumPy</strong></h4><p>NumPy tiene varios métodos integrados que te permiten crear matrices de números aleatorios. Cada uno de estos métodos comienza con <code>random</code>. A continuación se muestran algunos ejemplos:</p><pre><code>np.random.rand(sample_size)

#Devuelve una muestra de números aleatorios entre 0 y 1.

#El tamaño de la muestra puede ser un número entero (para un arreglo unidimensional) o dos enteros separados por comas (para un arreglo bidimensional).

np.random.randn(sample_size)

#Devuelve una muestra de números aleatorios entre 0 y 1, siguiendo la distribución normal

#El tamaño de la muestra puede ser un número entero (para un arreglo unidimensional) o dos enteros separados por comas (para un arreglo bidimensional).

np.random.randint(low, high, sample_size)

#Devuelve una muestra de números enteros que son mayores o iguales que 'low' y menores que 'high' 
</code></pre><h4 id="c-mo-remodelar-arreglos-de-numpy"><strong>Cómo remodelar arreglos de NumPy</strong></h4><p>Es muy común tomar un arreglo con ciertas dimensiones y transformar ese arreglo en una forma diferente. Por ejemplo, es posible que tengas un arreglo unidimensional con 10 elementos y desee cambiarla a un arreglo bidimensional de 2x5.</p><p>A continuación se muestra un ejemplo:</p><pre><code>arr = np.array([0,1,2,3,4,5])

arr.reshape(2,3)
</code></pre><p>La salida de esta operación es:</p><pre><code>array([[0, 1, 2],

       [3, 4, 5]])
</code></pre><p>Ten en cuenta que para usar el método <code>reshape</code>, el arreglo original debe tener la misma cantidad de elementos que el arreglo en el que estás tratando de remodelarlo.</p><p>Si tienes curiosidad sobre la forma actual de un arreglo NumPy, puede determinar su forma utilizando el atributo <code>shape</code> de NumPy. Usando nuestra estructura de la variable <code>arr</code> anterior, a continuación se muestra un ejemplo de cómo llamar al atributo <code>shape</code>:</p><pre><code>arr = np.array([0,1,2,3,4,5])

arr.shape

#Devuelve (6,)- ten en cuenta que no hay un segundo elemento ya que es un arreglo unidimensional

arr = arr.reshape(2,3)

arr.shape

#Devuelve (2,3)
</code></pre><p>También puede combinar el método &nbsp;<code>reshape</code> con el atributo &nbsp;<code>shape</code> en una línea como esta:</p><pre><code>arr.reshape(2,3).shape

#Devuelve (2,3)
</code></pre><h4 id="c-mo-encontrar-el-valor-m-ximo-y-m-nimo-de-un-arreglo-numpy">Cómo encontrar el valor máximo y mínimo de un arreglo NumPy</h4><p>Para concluir esta sección, aprendamos cuatro métodos útiles para identificar los valores máximo y mínimo dentro de un arreglo NumPy. Trabajaremos con este arreglo:</p><pre><code>simple_array = [1, 2, 3, 4]
</code></pre><p>Podemos usar el método <code>max</code> para encontrar el máximo valor de un arreglo de NumPy. A continuación se muestra un ejemplo.</p><pre><code>simple_array.max()

#Devuelve 4
</code></pre><p>Podemos usar también el método <code>argmax</code> para encontrar el índice del máximo valor dentro de un arreglo. Esto es útil cuando deseas encontrar la ubicación del valor máximo pero no necesariametne te interesa su valor en si.</p><p>Un ejemplo se observa a continuación.</p><pre><code>simple_array.argmax()

#Devuelve 3
</code></pre><p>En forma similar, podemos usar los métodos <code>min</code> y <code>argmin</code> para encontrar el valor e índice del mínimo valor dentro de un arreglo de NumPy.</p><pre><code>simple_array.min()

#Devuelve 1

simple_array.argmin()

#Devuelve 0
</code></pre><h3 id="continuemos-1"><strong>Continuemos</strong></h3><p>En esta sección, analizaremos varios atributos y métodos de los arreglos de NumPy. </p><p>Seguiremos trabajando en algunos problemas de práctica de arreglos NumPy en la siguiente sección.</p><h2 id="m-todos-y-operaciones-de-nump"><strong>Métodos y Operaciones de NumP</strong></h2><p>En esta sección, trabajaremos a través de <a href="https://nickmccullum.com/advanced-python/numpy-methods-operations/">varias operaciones incluidas en la biblioteca NumPy.</a></p><p>A lo largo de esta sección, asumiremos que el comando <code>import numpy as np</code> ya ha sido ejecutada.</p><h3 id="el-arreglo-usado-en-esta-secci-n"><strong>El arreglo usado en esta sección</strong></h3><p>Para esta sección, trabajaré con un arreglo de longitud 4 creada usando <code>np.arange</code> en todos los ejemplos.</p><p>Si deseas comparar mi arreglo con las salidas utilizadas en esta sección, así es como creé e imprimí el arreglo:</p><pre><code>arr = np.arange(4)

arr
</code></pre><p>Los valores del arreglo están debajo.</p><pre><code>array([0, 1, 2, 3])
</code></pre><h3 id="c-mo-realizar-operaciones-aritm-ticas-en-python-usando-numpy">Cómo realizar operaciones aritméticas en Python usando <strong>NumPy</strong></h3><p>NumPy facilita realizar operaciones aritméticas con arreglos. Puedes realizarlas usando el arreglo y un sólo número, o puedes realizarlas entre dos arreglos NumPy.</p><p>Exploramos cada una de las principales operaciones matemáticas a continuación.</p><h4 id="suma"><strong>Suma</strong></h4><p>Al sumar un sólo número a un arreglo de NumPy, ese número se suma a cada elemento en el arreglo. A continuación se ve un ejemplo:</p><pre><code>2 + arr

#Devuelve array([2, 3, 4, 5])
</code></pre><p>Puedes sumar dos arreglos NumPy usando el operador <code>+</code>. Los arreglos se suman elemento por elemento (lo que significa que los primeros elementos se suman entre si, los segundos elementos se suman se suman entre se, y así sucesivamente).</p><p>A continuación se ve un ejemplo.</p><pre><code>arr + arr

#Devuelve array([0, 2, 4, 6])
</code></pre><h4 id="resta"><strong>Resta</strong></h4><p>Como la suma, la resta se realiza elemento por elemento para arreglos de NumPy. Puedes encontrar un ejemplo para el caso de un solo número y para el de otro arreglo NumPy a continuación</p><pre><code>arr - 10

#Devuelve array([-10,  -9,  -8,  -7])

arr - arr

#Devuelve array([0, 0, 0, 0])
</code></pre><h4 id="multiplicaci-n"><strong>Multiplicación</strong></h4><p>La multiplicación también se realiza elemento por elemento tanto para casos de un sólo número como para casos de opraciones entre arreglos de NumPy.</p><p>A continuación se ven dos ejemplo.</p><pre><code>6 * arr

#Devuelve array([ 0,  6, 12, 18])

arr * arr

#Devuelve array([0, 1, 4, 9])
</code></pre><h4 id="divisi-n"><strong>División</strong></h4><p>En este punto, probablemente no te sorprende saber que la división en arreglos NumPy se realiza elemento por elemento. Un ejemplo de división de <code>arr</code> por un sólo número se ve a continuación:</p><pre><code>arr / 2

#Devuelve array([0. , 0.5, 1. , 1.5])
</code></pre><p>La división tiene una excepción notable en comparación con las otras operaciones matemáticas que hemos visto en esta sección. Dado que no podemos dividir por cero, al hacerlo, el campo correspondiente se completará con un valor <code>nan</code>, que es la abreviatura de Python para "No es un número" (“Not A Number”). Jupyter Notebook también imprimirá una advertencia similar a esta:</p><pre><code>RuntimeWarning: invalid value encountered in true_divide
</code></pre><p>Un ejemplo de dividir por cero es con un arreglo NumPy que se muestra a continuación.</p><pre><code>arr / arr

#Devuelve array([nan,  1.,  1.,  1.])
</code></pre><p>Aprenderemos cómo tratar los valores <code>nan</code> con más detalle más adelante en este curso.</p><h3 id="operaciones-complejas-en-arreglos-de-numpy"><strong>Operaciones complejas en arreglos de NumPy</strong></h3><p>Muchas operaciones no se pueden realizar simplemente aplicando la sintaxis normal a un arreglo NumPy. En esta sección, exploraremos varias operaciones matemáticas que tienen métodos incorporados en la biblioteca NumPy.</p><h4 id="c-mo-calcular-ra-z-cuadrada-usando-numpy"><strong>Cómo calcular raíz cuadrada usando NumPy</strong></h4><p>Puedes calcular la raíz cuadrada de cada elemento en un arreglo usando el método <code>np.sqrt</code>:</p><pre><code>np.sqrt(arr)

#Devuelve array([0., 1., 1.41421356, 1.73205081])
</code></pre><p>A continuación se muestran muchos otros ejemplos (ten en cuenta que no te serán evaluados, pero aún así es útil ver las capacidades de NumPy):</p><pre><code>np.exp(arr)

#Devuelve e ^ elemento para cada elemento del arreglo

np.sin(arr)

#Calcula el seno trigonométrico de cada valor en el arreglo

np.cos(arr)

#Calcula el coseno trigonométrico de cada valor en el arreglo

np.log(arr)

#Calcula el logaritmo en base diez de cada valor en el arreglo
</code></pre><h3 id="continuemos-2"><strong>Continuemos</strong></h3><p>En esta sección, exploramos los diversos métodos y operaciones disponibles en la biblioteca NumPy Python. Evaluaremos tu conocimiento de estos conceptos en los problemas de práctica que se presentan a continuación.</p><h2 id="indexaci-n-y-asignaci-n-en-numpy"><strong>Indexación y Asignación en NumPy</strong></h2><p>En esta sección, exploraremos la <a href="https://nickmccullum.com/advanced-python/numpy-indexing-assignment/">indexación y la asignación en arreglos NumPy.</a></p><h3 id="el-arreglo-que-usar-en-esta-secci-n"><strong>El arreglo que usaré en esta sección</strong></h3><p>Como antes, usaré un arreglo específico a través de esta sección. Esta vez se generará utilizando el método <code>np.random.rand</code>. Así es como generé el arreglo:</p><pre><code>arr = np.random.rand(5)
</code></pre><p>Aquí está el arreglo real:</p><pre><code>array([0.69292946, 0.9365295 , 0.65682359, 0.72770856, 0.83268616])
</code></pre><p>Para que este arreglo sea más fácil de ver, redondearé cada elemento a 2 decimales usando el método <code>round</code> de NumPy:</p><pre><code>arr = np.round(arr, 2)
</code></pre><p>Aquí está el nuevo arreglo:</p><pre><code>array([0.69, 0.94, 0.66, 0.73, 0.83])
</code></pre><h3 id="c-mo-retornar-un-elemento-espec-fico-de-un-arreglo-de-numpy"><strong>Cómo retornar un elemento específico de un arreglo de NumPy</strong></h3><p>Podemos seleccionar (y retornar) un elemento específico desde un arreglo NumPy de la misma forma que realiza con una lista normal de Python: usando los corchetes. </p><p>Un ejemplo se ve a continuación:</p><pre><code>arr[0]

#Devuelve 0.69
</code></pre><p>También podemos referenciar múltiples elementos de un arreglo NumPy usando los dos puntos. Por ejemplo, el índice <code>[2:]</code> selecciona cada elemento desde el índice 2 en adelante. El índice <code>[:3]</code> selecciona cada elemento hasta el índice 3 excluido. El índice <code>[2:4]</code> retorna cada elemento desde el índice 2 al índice 4, excluyendo este último. El criterio de valoración más alto siempre se excluye.</p><p>A continuación se muestran algunos ejemplos de indexación mediante el operador de dos puntos.</p><pre><code>arr[:]

#Retorna el arreglo completo: array([0.69, 0.94, 0.66, 0.73, 0.83])

arr[1:]

#Devuelve array([0.94, 0.66, 0.73, 0.83])

arr[1:4] 

#Devuelve array([0.94, 0.66, 0.73])
</code></pre><h3 id="asignaci-n-de-elementos-en-arreglos-de-numpy">Asignación de elementos en arreglos de NumPy</h3><p>Podemos asignar nuevos valores a un elemento de un arreglo NumPy usando el operador <code>=</code>, al igual que las listas de Python normales. A continuación se muestran algunos ejemplos (ten en cuenta que todo esto es un bloque de código, lo que significa que las asignaciones de elementos se llevan adelante de paso a paso)</p><pre><code>array([0.12, 0.94, 0.66, 0.73, 0.83])

arr

#Devuelve array([0.12, 0.94, 0.66, 0.73, 0.83])

arr[:] = 0

arr

#Devuelve array([0., 0., 0., 0., 0.])

arr[2:5] = 0.5

arr

#Devuelve array([0. , 0. , 0.5, 0.5, 0.5])


</code></pre><h3 id="referenciaci-n-de-arreglos-en-numpy"><strong>Referenciación de arreglos en NumPy</strong></h3><p>NumPy hace uso de un concepto llamado "Referencia de arreglos" (array referencing) que es una fuente común de confusiones para las personas que son nuevas en la librería.</p><p>Para entender la referencia de arreglo, primero veamos un ejemplo:</p><pre><code>
new_array = np.array([6, 7, 8, 9])

second_new_array = new_array[0:2]

second_new_array

#Devuelve array([6, 7])

second_new_array[1] = 4

second_new_array 

#Devuelve array([6, 4]), como se esperaba

new_array 

#Devuelve array([6, 4, 8, 9]) 

#que es DIFERENTE de su valor original de array([6, 7, 8, 9])

#¿Que ha pasado?
</code></pre><p>Como puedes ver, la modificación de <code>second_new_array</code> cambió también el valor de <code>new_array</code>.</p><p>¿Por qué es esto?</p><p>Por defecto, NumPy no crea una copia de un arreglo cuando hace referencia a la variable del arreglo original usando el operador de asignación <code>=</code>. En cambio, simplemente apunta la nueva variable a la anterior, lo que permite que la segunda variable realice modificaciones en la variable original, incluso si esta no es tu intención.</p><p>Esto puede parecer extraño, pero tiene una explicación lógica. El propósito de la referencia de arreglos es conservar poder computacional. Al trabajar con grandes conjuntos de datos, rápidamente te quedarías sin RAM si crearas un nuevo arreglo cada vez que quisieras trabajar con una porción de él.</p><p>Afortunadamente, existe una solución para la referencia de arreglos. Puede utilizar el método <code>copy</code> para copiar explícitamente un arreglo NumPy. </p><p>A continuación se muestra un ejemplo de esto.</p><pre><code>array_to_copy = np.array([1, 2, 3])

copied_array = array_to_copy.copy()

array_to_copy

#Returns array([1, 2, 3])

copied_array

#Returns array([1, 2, 3])
</code></pre><p>Como puede ver a continuación, realizar modificaciones al arreglo copiado no altera el original.</p><pre><code>copied_array[0] = 9

copied_array

#Devuelve array([9, 2, 3])

array_to_copy

#Devuelve array([1, 2, 3])
</code></pre><p>Hasta ahora en la sección, solo hemos explorado cómo hacer referencia a arreglos NumPy unidimensionales. Ahora exploraremos la indexación de matrices bidimensionales.</p><h3 id="indexando-arreglos-numpy-de-dos-dimensiones"><strong>Indexando arreglos NumPy de dos dimensiones</strong></h3><p>Para comenzar, creemos un arreglo NumPy de dos dimensiones llamado <code>mat</code>:</p><pre><code>mat = np.array([[5, 10, 15],[20, 25, 30],[35, 40, 45]])

mat

"""

Devuelve:

array([[ 5, 10, 15],

       [20, 25, 30],

       [35, 40, 45]])

"""
</code></pre><p>Hay dos formas de indexar un arreglo NumPy de dos dimensiones:</p><ul><li><code>mat[fila, columna]</code></li><li><code>mat[fila][colulma]</code></li></ul><p>Personalmente, prefiero indexar usando la nomenclatura <code>mat[fila][colulma]</code> porque es más fácil de visualizar paso a paso. Por ejemplo:</p><pre><code>#Primero, vamos a conseguir la primera fila:

mat[0]

#Luego, obtengamos el último elemento de la primera fila:

mat[0][-1]
</code></pre><p>También puede generar submatrices a partir de un arreglo NumPy bidimensional utilizando esta notación:</p><pre><code>mat[1:][:2]

"""

Devuelve:

array([[20, 25, 30],

       [35, 40, 45]])

"""
</code></pre><p>La referencia de arreglos también se aplica a arreglos bidimensionales en NumPy, así que asegúrate de utilizar el método <code>copy</code> si deseas evitar modificar inadvertidamente un arreglo original después de guardar una porción de él en un nuevo nombre de variable.</p><h3 id="selecci-n-condicional-mediante-arreglos-de-numpy">Selección condicional mediante arreglos de NumPy</h3><p>Los arreglos NumPy admiten una función llamada <code>conditional selection</code>, que le permite generar un nuevo arreglo de valores booleanos que indican si cada elemento dentro del arreglo satisface una declaración <code>if</code> particular.</p><p>Un ejemplo de esto está abajo (también recreé nuestra variable <code>arr</code> original ya que ha pasado un tiempo desde que la vimos):</p><pre><code>arr = np.array([0.69, 0.94, 0.66, 0.73, 0.83])

arr &gt; 0.7

#Devuelve array([False,  True, False,  True,  True])
</code></pre><p>También puedes generar un nuevo arreglo de valores que satisfagan esta condición pasando la condición entre corchetes (como lo hacemos para indexar).</p><p>Un ejemplo de esto está abajo:</p><pre><code>arr[arr &gt; 0.7]

#Devuelve array([0.94, 0.73, 0.83])
</code></pre><p>La selección condicional puede volverse significativamente más compleja que esto. Exploraremos más ejemplos en los problemas de práctica asociados a esta sección.</p><h3 id="continuemos-3"><strong>Continuemos</strong></h3><p>En esta sección, exploramos la indexación y la asignación de matrices NumPy en detalle. Fortaleceremos aún más su conocimiento de estos conceptos trabajando en una serie de problemas de práctica en la siguiente sección.</p><h2 id="pensamientos-finales-y-oferta-especial">Pensamientos finales y oferta especial</h2><p>Gracias por leer este artículo sobre NumPy, que es uno de mis paquetes favoritos de Python y una biblioteca imprescindible para todos los desarrolladores de Python.</p><p>Traducido del artículo de <strong><a href="https://www.freecodecamp.org/news/author/nick/">Nick McCullum</a> - <a href="https://www.freecodecamp.org/news/the-ultimate-guide-to-the-numpy-scientific-computing-library-for-python/">The Ultimate Guide to the NumPy Package for Scientific Computing in Python</a></strong></p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Cómo hacer scrape de sitios web con Python 3 ]]>
                </title>
                <description>
                    <![CDATA[ Hacer scrape es el proceso de extraer datos de sitios web. Antes de realizar la extracción de datos de una página web, debes asegurarte de que el proveedor lo permita en sus términos de servicio. Además, deberías verificar si no puedes usar una API en su lugar. Una extracción masiva ]]>
                </description>
                <link>https://www.freecodecamp.org/espanol/news/como-hacer-scrape-de-una/</link>
                <guid isPermaLink="false">5fea33008c7cd154bb980e20</guid>
                
                    <category>
                        <![CDATA[ Web Scraping ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Fernando Cardellino ]]>
                </dc:creator>
                <pubDate>Fri, 29 Jan 2021 14:00:00 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/espanol/news/content/images/2021/01/python.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Hacer scrape es el proceso de extraer datos de sitios web.</p><p>Antes de realizar la extracción de datos de una página web, debes asegurarte de que el proveedor lo permita en sus términos de servicio. Además, deberías verificar si no puedes usar una API en su lugar.</p><p>Una extracción masiva de datos puede poner al servidor bajo un enorme esfuerzo, lo cual puede resultar en una denegación de servicio. Y no quieres eso.</p><h2 id="-qui-n-deber-a-leer-esto">¿Quién debería leer esto?</h2><p>Este artículo es para lectores avanzados. Se asume que ya estás familiarizado con el lenguaje de programación de Python.</p><p>Como mínimo, debes entender la comprensión de listas, el administrador de contexto y las funciones. También debes saber cómo configurar un entorno virtual.</p><p>Ejecutaremos el código en tu máquina local para explorar algunos sitios web. </p><h2 id="qu-aprender-s-en-este-art-culo">Qué aprenderás en este artículo</h2><p>Al final de este artículo, sabrás cómo descargar una página web, analizarla en busca de información interesante y darle un formato utilizable para su posterior procesamiento. Esto también se conoce como ETL.</p><p>Este artículo también explicará qué hacer si ese sitio web usa JavaScript para representar (render) contenido (como React.js o Angular).</p><h2 id="pre-requisitos">Pre-requisitos</h2><p>Antes de comenzar, deseo asegurarme de que estemos listo para dar inicio. Por favor, establece un entorno virtual e instálale los siguientes paquetes:</p><ul><li>beautifulsoup4 (versión 4.9.0 al momento de estar escribiendo el artículo)</li><li>requests (versión 2.23.0 al momento de estar escribiendo el artículo)</li><li>wordcloud (versión 1.17.0 al momento de estar escribiendo el artículo, opcional)</li><li>selenium (versión 3.141.0 al momento de estar escribiendo el artículo, opcional)</li></ul><p>Puedes encontrar el código	 de este proyecto en este <a href="https://github.com/Ryuno-Ki/fcc-web-scraping-example">repositorio git en GitHub</a></p><p>Para este ejemplo, realizaremos una extracción (scrape) de la <a href="https://www.gesetze-im-internet.de/gg/index.html">Ley Básica para la República Federal de Alemania</a>. (No te preocupes, ya verifiqué los Términos de Servicios. Ofrecen una versión XML para procesamiento de máquina, pero esta página sirve como un ejemplo de procesamiento de HTML. Entonces debería estar bien.)</p><h2 id="paso-1-descargar-la-fuente">Paso 1: Descargar la fuente</h2><p>Primero lo primero: creé un archivo <code>urls.txt</code> que contiene todos los URLs que deseo descargar:</p><figure class="kg-card kg-code-card"><pre><code>https://www.gesetze-im-internet.de/gg/art_1.html
https://www.gesetze-im-internet.de/gg/art_2.html
https://www.gesetze-im-internet.de/gg/art_3.html
https://www.gesetze-im-internet.de/gg/art_4.html
https://www.gesetze-im-internet.de/gg/art_5.html
https://www.gesetze-im-internet.de/gg/art_6.html
https://www.gesetze-im-internet.de/gg/art_7.html
https://www.gesetze-im-internet.de/gg/art_8.html
https://www.gesetze-im-internet.de/gg/art_9.html
https://www.gesetze-im-internet.de/gg/art_10.html
https://www.gesetze-im-internet.de/gg/art_11.html
https://www.gesetze-im-internet.de/gg/art_12.html
https://www.gesetze-im-internet.de/gg/art_12a.html
https://www.gesetze-im-internet.de/gg/art_13.html
https://www.gesetze-im-internet.de/gg/art_14.html
https://www.gesetze-im-internet.de/gg/art_15.html
https://www.gesetze-im-internet.de/gg/art_16.html
https://www.gesetze-im-internet.de/gg/art_16a.html
https://www.gesetze-im-internet.de/gg/art_17.html
https://www.gesetze-im-internet.de/gg/art_17a.html
https://www.gesetze-im-internet.de/gg/art_18.html
https://www.gesetze-im-internet.de/gg/art_19.html</code></pre><figcaption>urls.txt</figcaption></figure><p>Luego, escribí un poco de código en Python en un archivo llamado <code>scraper.py</code> para descargar el HTML de estos archivos.</p><p>En un escenario real, esto sería demasiado costoso y, en su lugar, utilizarías una base de datos. Para simplificar las cosas, descargaré archivos en el mismo directorio y usaré su nombre como nombre de archivo.</p><figure class="kg-card kg-code-card"><pre><code class="language-py">from os import path
from pathlib import PurePath

import requests

with open('urls.txt', 'r') as fh:
    urls = fh.readlines()
urls = [url.strip() for url in urls]  # strip `\n`

for url in urls:
    file_name = PurePath(url).name
    file_path = path.join('.', file_name)
    text = ''

    try:
        response = requests.get(url)
        if response.ok:
            text = response.text
    except requests.exceptions.ConnectionError as exc:
        print(exc)
    
    with open(file_path, 'w') as fh:
        fh.write(text)

    print('Written to', file_path)</code></pre><figcaption>scraper.py</figcaption></figure><p>Al descargar los archivos, los puedo procesar localmente tanto como lo desee sin depender de unos servidos. Trata de ser un buen ciudadano web, ¿si?</p><h2 id="paso-2-analizar-la-fuente">Paso 2: Analizar la fuente</h2><p>Ahora que he descargado los archivos, es tiempo de extraer información interesante. Por lo tanto me dirijo a alguna de las páginas que descargué, la abro en un navegador web, y aprieto Crtl-U para ver su código fuente. Al inspeccionarlo me mostrará su estructura HTML.</p><p>En mi caso, quería el texto de la ley sin ningún marcado. El elemento que lo envuelve tiene un id de <code>container</code>. Usando BeautifulSoup puedo ver que una combinación de <a href="https://www.crummy.com/software/BeautifulSoup/bs4/doc/#find"><code>find</code></a> y <code><a href="https://www.crummy.com/software/BeautifulSoup/bs4/doc/#get-text">get_text</a></code> hará lo que quiero.</p><p>Como tengo un segundo paso ahora, voy a refactorizar un poco el código poniéndolo en funciones y agregando una CLI mínima.</p><figure class="kg-card kg-code-card"><pre><code class="language-py">from os import path
from pathlib import PurePath
import sys

from bs4 import BeautifulSoup
import requests


def download_urls(urls, dir):
    paths = []

    for url in urls:
        file_name = PurePath(url).name
        file_path = path.join(dir, file_name)
        text = ''

        try:
            response = requests.get(url)
            if response.ok:
                text = response.text
            else:
                print('Mala respuesta para', url, response.status_code)
        except requests.exceptions.ConnectionError as exc:
            print(exc)
    
        with open(file_path, 'w') as fh:
            fh.write(text)

        paths.append(file_path)

    return paths

def parse_html(path):
    with open(path, 'r') as fh:
        content = fh.read()

    return BeautifulSoup(content, 'html.parser')

def download(urls):
    return download_urls(urls, '.')

def extract(path):
    return parse_html(path)

def transform(soup):
    container = soup.find(id='container')
    if container is not None:
        return container.get_text()

def load(key, value):
    d = {}
    d[key] = value
    return d

def run_single(path):
    soup = extract(path)
    content = transform(soup)
    unserialised = load(path, content.strip() if content is not None else '')
    return unserialised

def run_everything():
    l = []

    with open('urls.txt', 'r') as fh:
        urls = fh.readlines()
    urls = [url.strip() for url in urls]

    paths = download(urls)
    for path in paths:
        print('Written to', path)
        l.append(run_single(path))

    print(l)

if __name__ == "__main__":
    args = sys.argv

    if len(args) is 1:
      run_everything()
    else:
        if args[1] == 'download':
            download([args[2]])
            print('Done')
        if args[1] == 'parse':
            path = args[2]
            result = run_single(path)
            print(result)
</code></pre><figcaption>scraper.py</figcaption></figure><p>Ahora puedo ejecutar el código de tres maneras:</p><ol><li>Sin ningún argumento para ejecutar todo (es decir, descargar todas las URL y extraerlas, luego guardarlas en el disco) a través de: <code>python scraper.py</code></li><li>Con un argumento de <code>download</code> y una url para descargar: <code>python scraper.py download https://www.gesetze-im-internet.de/gg/art_1.html</code>. Esto no procesará el archivo.</li><li>Con un argumento de <code>parse</code> y una ruta de archivo para analizar: <code>python scraper.py art_1.html</code>. Esto omitirá el paso de descarga.</li></ol><p>Con esto, solo falta una última cosa.</p><h2 id="paso-3-dar-formato-a-la-fuente-para-su-posterior-procesamiento">Paso 3: Dar formato a la fuente para su posterior procesamiento</h2><p>Digamos que quiero generar una nube de palabras para cada artículo. Esta puede ser una forma rápida de tener una idea de lo que trata un texto. Para ello, instala el paquete <code>wordcloud</code> y actualiza el archivo así:</p><figure class="kg-card kg-code-card"><pre><code class="language-py">from os import path
from pathlib import Path, PurePath
import sys

from bs4 import BeautifulSoup
import requests
from wordcloud import WordCloud

STOPWORDS_ADDENDUM = [
    'Das',
    'Der',
    'Die',
    'Diese',
    'Eine',
    'In',
    'InhaltsverzeichnisGrundgesetz',
    'im',
    'Jede',
    'Jeder',
    'Kein',
    'Sie',
    'Soweit',
    'Über'
]
STOPWORDS_FILE_PATH = 'stopwords.txt'
STOPWORDS_URL = 'https://raw.githubusercontent.com/stopwords-iso/stopwords-de/master/stopwords-de.txt'


def download_urls(urls, dir):
    paths = []

    for url in urls:
        file_name = PurePath(url).name
        file_path = path.join(dir, file_name)
        text = ''

        try:
            response = requests.get(url)
            if response.ok:
                text = response.text
            else:
                print('Mala respuesta para', url, response.status_code)
        except requests.exceptions.ConnectionError as exc:
            print(exc)
    
        with open(file_path, 'w') as fh:
            fh.write(text)

        paths.append(file_path)

    return paths

def parse_html(path):
    with open(path, 'r') as fh:
        content = fh.read()

    return BeautifulSoup(content, 'html.parser')

def download_stopwords():
    stopwords = ''

    try:
        response = requests.get(STOPWORDS_URL)
        if response.ok:
            stopwords = response.text
        else:
            print('Mala respuesta para', url, response.status_code)
    except requests.exceptions.ConnectionError as exc:
        print(exc)

    with open(STOPWORDS_FILE_PATH, 'w') as fh:
        fh.write(stopwords)

    return stopwords

def download(urls):
    return download_urls(urls, '.')

def extract(path):
    return parse_html(path)

def transform(soup):
    container = soup.find(id='container')
    if container is not None:
        return container.get_text()

def load(filename, text):
    if Path(STOPWORDS_FILE_PATH).exists():
        with open(STOPWORDS_FILE_PATH, 'r') as fh:
            stopwords = fh.readlines()
    else:
        stopwords = download_stopwords()

    # Tira de espacios en blanco alrededor
    stopwords = [stopword.strip() for stopword in stopwords]
    # Extienda las stopwords con las propias, que se determinaron después de 	  la primera ejecución stopwords = stopwords + STOPWORDS_ADDENDUM

    try:
        cloud = WordCloud(stopwords=stopwords).generate(text)
        cloud.to_file(filename.replace('.html', '.png'))
    except ValueError:
        print('No se pudo generar la nube de palabras para', key)

def run_single(path):
    soup = extract(path)
    content = transform(soup)
    load(path, content.strip() if content is not None else '')

def run_everything():
    with open('urls.txt', 'r') as fh:
        urls = fh.readlines()
    urls = [url.strip() for url in urls]

    paths = download(urls)
    for path in paths:
        print('Written to', path)
        run_single(path)
    print('Done')

if __name__ == "__main__":
    args = sys.argv

    if len(args) is 1:
      run_everything()
    else:
        if args[1] == 'download':
            download([args[2]])
            print('Done')
        if args[1] == 'parse':
            path = args[2]
            run_single(path)
            print('Done')</code></pre><figcaption>scraper.py</figcaption></figure><p>¿Qué cambió? Por un lado, descargué una <a href="https://github.com/stopwords-iso/stopwords-de/">lista de palabras vacías</a> (stopwords) alemanas de GitHub. De esta manera, puedo eliminar las palabras más comunes del texto de la ley descargado.</p><p>Luego, creé una instancia de WordCloud con la lista de palabras vacías que descargué y el texto de la ley. Se convertirá en una imagen con el mismo nombre de base.</p><p>Después de la primera ejecución, descubrí que la lista de palabras vacías está incompleta. Así que agregué palabras adicionales que quiero excluir de la imagen resultante.</p><p>Con esto, la parte principal de la extracción web está completa.</p><h2 id="bonus-y-los-spa">Bonus: ¿Y los SPA?</h2><p>Los SPA, o aplicaciones de página única, son aplicaciones web donde toda la experiencia está controlada por JavaScript, que se ejecuta en el navegador. Como tal, descargar el archivo HTML no nos lleva muy lejos. ¿Qué deberíamos hacer en su lugar?</p><p>Usaremos el navegador. Con Selenium. Asegúrate de instalar también un controlador. Descarga el archivo .tar.gz y descomprímelo en la carpeta bin de tu entorno virtual para que Selenium lo encuentre. Ese es el directorio donde puedes encontrar el script de activación (en sistemas GNU / Linux).</p><p>Como ejemplo, estoy usando el sitio web de Angular aquí. Angular es un SPA-Framework popular escrito en JavaScript y se garantiza que será controlado por él por el momento.</p><p>Dado que el código será más lento, creé un nuevo archivo llamado crawler.py para él. El contenido tiene este aspecto:</p><figure class="kg-card kg-code-card"><pre><code class="language-py">from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from wordcloud import WordCloud

def extract(url):
    elem = None
    driver = webdriver.Firefox()
    driver.get(url)

    try:
        found = WebDriverWait(driver, 10).until(
            EC.visibility_of(
                driver.find_element(By.TAG_NAME, "article")
            )
        )
        # Haz una copia de los datos relevantes, porque Selenium arrojará si
        # intenta acceder a las propiedades después de que el controlador se 			cierre
        elem = {
          "text": found.text
        }
    finally:
        driver.close()

    return elem

def transform(elem):
    return elem["text"]
        
def load(text, filepath):
    cloud = WordCloud().generate(text)
    cloud.to_file(filepath)

if __name__ == "__main__":
    url = "https://angular.io/"
    filepath = "angular.png"

    elem = extract(url)
    if elem is not None:
        text = transform(elem)
        load(text, filepath)
    else:
        print("Lo siento, no se pudieron extraer datos")</code></pre><figcaption>crawler.py</figcaption></figure><p>Aquí, Python abre una instancia de Firefox, navega por el sitio web y busca un elemento <code>&lt;article&gt;</code>. Está copiando su texto en un diccionario, que se lee en el paso <code>transform</code> y se convierte en WordCloud durante <code>load</code>.</p><p>Cuando se trata de sitios con mucho JavaScript, a menudo es útil usar Waits y tal vez incluso ejecutar <code><a href="https://selenium-python.readthedocs.io/api.html#selenium.webdriver.remote.webdriver.WebDriver.execute_script">execute_script</a></code> para diferir a JavaScript si es necesario.</p><h2 id="resumen">Resumen</h2><p>¡Gracias por leer hasta aquí! Resumamos lo que hemos aprendido ahora:</p><ol><li>Cómo hacer una extracción (scrape) un sitio web con el paquete <code>requests</code> de Python.</li><li>Cómo traducirla en una estructura con sentido usando <code>beautifulsoup</code>.</li><li>Cómo procesar aún más esa estructura en algo con lo que puedas trabajar. </li><li>Qué hacer si la página de destino se basa en JavaScript.</li></ol><h2 id="otras-lecturas">Otras lecturas</h2><p>Si quieres saber más sobre mí, puedes <a href="https://twitter.com/AndreJaenisch">seguirme en Twitter</a> o visitar mi <a href="https://jaenis.ch/">sitio web</a>.</p><p>No soy el primero que escribió sobre Web Scraping aquí en freeCodeCamp. Yasoob Khalid y Dave Gray también lo hicieron en el pasado:</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://www.freecodecamp.org/news/an-intro-to-web-scraping-with-lxml-and-python-b02b7a3f3098/"><div class="kg-bookmark-content"><div class="kg-bookmark-title">An Intro to Web Scraping with lxml and Python</div><div class="kg-bookmark-description">by Timber.io An Intro to Web Scraping with lxml and PythonPhoto by Fabian Grohs[https://unsplash.com/photos/dC6Pb2JdAqs?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText] on Unsplash[https://unsplash.com/search/photos/web?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText…</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://www.freecodecamp.org/news/favicon.png" width="600" height="400" alt="favicon" loading="lazy"><span class="kg-bookmark-author">freeCodeCamp.org</span><span class="kg-bookmark-publisher">freeCodeCamp.org</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://cdn-media-1.freecodecamp.org/images/0*AXQfWm6LMJwLwS2f.png" width="800" height="357" alt="0*AXQfWm6LMJwLwS2f" loading="lazy"></div></a></figure><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://www.freecodecamp.org/news/better-web-scraping-in-python-with-selenium-beautiful-soup-and-pandas-d6390592e251/"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Better web scraping in Python with Selenium, Beautiful Soup, and pandas</div><div class="kg-bookmark-description">by Dave Gray Web ScrapingUsing the Python programming language, it is possible to “scrape” data from theweb in a quick and efficient manner. Web scraping is defined as: &amp;gt; a tool for turning the unstructured data on the web into machine readable,structured data which is ready for analysis. (sou…</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://www.freecodecamp.org/news/favicon.png" width="600" height="400" alt="favicon" loading="lazy"><span class="kg-bookmark-author">freeCodeCamp.org</span><span class="kg-bookmark-publisher">freeCodeCamp.org</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://cdn-media-1.freecodecamp.org/images/1*DiffPQdgEAjDK4M_unUd4Q.jpeg" width="800" height="533" alt="1*DiffPQdgEAjDK4M_unUd4Q" loading="lazy"></div></a></figure><p>Traducido del artículo de <strong><a href="https://www.freecodecamp.org/news/author/ryuno-ki/">André Jaenisch</a> - <a href="https://www.freecodecamp.org/news/webscraping-in-python/">How Scrape Websites with Python 3</a></strong></p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Cómo hacer tu primer pull request en GitHub ]]>
                </title>
                <description>
                    <![CDATA[ ¿Qué es hacer un forking? Cuando nos gusta el repositorio de alguien y nos gustaría tenerlo en nuestra cuenta de GitHub, hacemos un fork o bifurcación para poder trabajar con él en forma separada. Cuando hacemos un fork de un repositorio, obtenemos una instancia de todo el repositorio con todo ]]>
                </description>
                <link>https://www.freecodecamp.org/espanol/news/como-hacer-tu-primer-pull-request-en-github/</link>
                <guid isPermaLink="false">5fe74e518c7cd154bb97ead7</guid>
                
                    <category>
                        <![CDATA[ GitHub ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Fernando Cardellino ]]>
                </dc:creator>
                <pubDate>Tue, 26 Jan 2021 13:00:00 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/espanol/news/content/images/2021/01/Untitled-design-1-.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <h2 id="-qu-es-hacer-un-forking">¿Qué es hacer un forking?</h2><p>Cuando nos gusta el repositorio de alguien y nos gustaría tenerlo en nuestra cuenta de GitHub, hacemos un fork o bifurcación para poder trabajar con él en forma separada.</p><p>Cuando hacemos un fork de un repositorio, obtenemos una instancia de todo el repositorio con todo su historial. Luego, podemos hacer lo que queramos sin afectar la versión original.</p><h2 id="-qu-es-un-pull-request">¿Qué es un pull request?</h2><p>Los pull requests son la forma de contribuir a un proyecto grupal o de código abierto.</p><p>Por ejemplo, un usuario llamado Harry realiza un fork de un repositorio de ThanoshanMV y le efectúa algunos cambios. Ahora Harry puede hacer un pull request a ThanoshanMV, pero dependerá de ThanoshanMV aceptar o declinarlo. Es como decir: "ThanoshanMV, ¿podrías por favor extraer (pull) mis cambios?"</p><h2 id="-que-significa-contribuir">¿Que significa contribuir?</h2><p>No solo podemos contribuir a un proyecto de código abierto con código, sino que podemos hacerlo de muchas otras maneras. Algunas de ellas están descritas abajo.</p><p>Como indica la guía de hacktitude para iniciados de la firma IT <a href="https://99x.io/">99xtechnology</a>, podemos contribuir a un proyecto de código abierto de las siguientes maneras:</p><ol><li>Diseñando: Puedes construir los diseños de un proyecto para mejorar su usabilidad, mejorar la navegación y el menú del proyecto en función de lo indicado por investigaciones acerca de las preferencias del usuario, crear arte para logotipos o camisetas y proporcionar guías de estilo para el proyecto.</li><li>Escribiendo: Puedes escribir y mejorar la documentación del proyecto o traducirla, iniciar un boletín o escribir tutoriales para el proyecto y tomar nota de los aspectos más destacados de la lista de correo, u organizar una carpeta de ejemplos mostrando cómo se utilizan los proyectos.</li><li>Organizando: Puedes vincular problemas duplicados, sugerir nuevas etiquetas de problemas, sugerir cerrar viejos problemas aún abiertos y hacer preguntas sobre problemas abiertos recientemente para hacer avanzar la discusión.</li><li>Ayuda a otros: Responde preguntas de problemas aún en discusión, revisa el código enviado por otras personas y ofrécete a ser mentor de otro colaborador.</li><li>Elaborando código: Ayuda a resolver problemas aún en discusión, consulta si puedes proveer nuevas funciones y mejorar las herramientas y las pruebas.</li></ol><h2 id="-realicemos-nuestro-primer-pull-request-">¡Realicemos nuestro primer pull request!</h2><h3 id="1-realicemos-un-fork-del-repositorio">1. Realicemos un fork del repositorio</h3><p>Realiza un fork del repositorio haciendo un clic en el botón fork de la parte superior de la página. Esto creará una instancia del repositorio completo en tu cuenta.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/espanol/news/content/images/2020/12/fork.jpg" class="kg-image" alt="fork" srcset="https://www.freecodecamp.org/espanol/news/content/images/size/w600/2020/12/fork.jpg 600w, https://www.freecodecamp.org/espanol/news/content/images/2020/12/fork.jpg 822w" sizes="(min-width: 720px) 720px" width="822" height="280" loading="lazy"></figure><h3 id="2-clona-el-repositorio">2. Clona el repositorio</h3><p>Una vez que el repositorio esté en tu cuenta, clónalo a tu computador para trabajarlo localmente.</p><p>Para clonarlo, has clic en el botón "Code" y copia el link.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/espanol/news/content/images/2020/12/clone.jpg" class="kg-image" alt="clone" srcset="https://www.freecodecamp.org/espanol/news/content/images/2020/12/clone.jpg 600w" width="600" height="419" loading="lazy"></figure><p>Abre la terminal y ejecuta el siguiente comando. Esto clonará el repositorio localmente.</p><pre><code>$ git clone [DIRECCIÓN HTTPS]</code></pre><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2020/01/clone2.png" class="kg-image" alt="clone2" width="600" height="400" loading="lazy"></figure><p>Ahora hemos configurado una copia de la rama maestra desde el repositorio principal del proyecto en línea.</p><p>Debemos ir al repositorio clonado ejecutando el siguiente comando:</p><pre><code>$ cd [NOMBRE DEL REPOSITORIO]</code></pre><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2020/01/clone3.png" class="kg-image" alt="clone3" width="600" height="400" loading="lazy"></figure><h3 id="3-crea-una-rama">3. Crea una rama</h3><p>Es una buena práctica crear una rama (branch) nueva cuando trabajas con repositorios, ya sea que se trate de un proyecto pequeño o estés contribuyendo en un equipo de trabajo.</p><p>El nombre de la rama debe ser breve y debe reflejar el trabajo que estamos haciendo.</p><p>Ahora crea una rama usando el comando <code>git checkout</code>:</p><pre><code>$ git checkout -b [Nombre de la Rama]</code></pre><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2020/01/branch1.png" class="kg-image" alt="branch1" width="600" height="400" loading="lazy"></figure><h3 id="4-realiza-cambios-y-conf-rmalos">4. Realiza cambios y confírmalos</h3><p>Has cambios esenciales al proyecto y guárdalos.</p><p>Luego ejecuta <code>git status</code> , y verás los cambios.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2020/01/status.png" class="kg-image" alt="status" width="600" height="400" loading="lazy"></figure><p>Agrega esos cambios a la rama recién creada usando el comando <code>git add</code>:</p><pre><code>$ git add .</code></pre><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2020/01/add1.png" class="kg-image" alt="add1" width="600" height="400" loading="lazy"></figure><p>Ahora confirma esos cambios utilizando el comando <code>git commit</code>:</p><pre><code>$ git commit -m "Adding an article to week 02 of articles of the week"</code></pre><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2020/01/commit.png" class="kg-image" alt="commit" width="600" height="400" loading="lazy"></figure><h3 id="5-env-a-los-cambios-a-github">5. Envía los cambios a GitHub</h3><p>Para enviar los cambios a GitHub, debemos identificar el nombre del repositorio remoto.</p><pre><code>$ git remote</code></pre><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2020/01/remote.png" class="kg-image" alt="remote" width="600" height="400" loading="lazy"></figure><p>Para este repositorio el nombre es "origin".</p><p>Luego de identificar el nombre podemos enviar en forma segura los cambios a GitHub.</p><pre><code>git push origin [Nombre de la Rama]</code></pre><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2020/01/branch2.png" class="kg-image" alt="branch2" width="600" height="400" loading="lazy"></figure><h3 id="6-crea-un-pull-request">6. Crea un pull request</h3><p>Ve a tu repositorio en GitHub y verás un botón llamado "Pull request", has clic en él.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/espanol/news/content/images/2020/12/pullReq.jpg" class="kg-image" alt="pullReq" width="512" height="278" loading="lazy"></figure><p>Por favor, provee todos los detalles necesarios de lo que has hecho (puedes referenciar problemas utilizando "#"). Ahora, envía el pull request.</p><p>¡Felicitaciones! Has hecho tu primer pull request.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2020/01/pullRequest-1.png" class="kg-image" alt="pullRequest-1" width="600" height="400" loading="lazy"></figure><p>Si tu pull request es aceptado recibirás un mail.</p><h3 id="7-sincroniza-tu-rama-maestra-con-la-del-repositorio-original">7. Sincroniza tu rama maestra con la del repositorio original</h3><p>Antes de enviar cualquier pull request al repositorio original debes sincronizar tu repositorio con aquel.</p><p>Incluso si no vas a enviar un pull request al repositorio original, es mejor efectuar la sincronización, ya que pueden haberse agregado algunas prestaciones o funciones adicionales y haberse corregido algunos errores desde la vez que realizaste un fork de aquel repositorio.</p><p>Sigue estos pasos para actualizar/sincronizar aquellos cambios con tu rama maestra:</p><ol><li>Primero, revisa en que rama estás ubicado.</li></ol><pre><code>$ git branch</code></pre><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2020/01/branch4.png" class="kg-image" alt="branch4" width="600" height="400" loading="lazy"></figure><p>Esto enumerará todas las ramas y indicará en verde la rama actual o activa.</p><p>2. Cambia a la rama maestra.</p><pre><code>$ git checkout master</code></pre><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2020/01/master9.png" class="kg-image" alt="master9" width="600" height="400" loading="lazy"></figure><p>3. Agrega el repositorio original como un repositorio upstream.</p><p>Para poder extraer los cambios desde el repositorio original a tu versión local, necesitas agregar el repositorio Git original como un repositorio upstream.</p><pre><code>$ git remote add upstream [HTTPS]</code></pre><p>Aquí, [HTTPS] es el URL que debes copiar del repositorio del propietario.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/espanol/news/content/images/2020/12/Screenshot-from-2020-12-26-17-16-23.png" class="kg-image" alt="Screenshot-from-2020-12-26-17-16-23" width="592" height="431" loading="lazy"></figure><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2020/01/remote-add.png" class="kg-image" alt="remote-add" width="600" height="400" loading="lazy"></figure><p>4. Busca (fetch) el repositorio.</p><p>Busca todos los cambios &nbsp;del repositorio original. Las confirmaciones (commits) del repositorio original serán almacenadas en una rama local llamada upstream/master.</p><pre><code>$ git fetch upstream</code></pre><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2020/01/fetch.png" class="kg-image" alt="fetch" width="600" height="400" loading="lazy"></figure><p>5. Fusionala.</p><p>Fusiona los cambios de la rama upstream/master a tu rama maestra local. Esto hará que tu rama maestra se sincronice con el repositorio upstream sin perder tus cambios locales.</p><pre><code>$ git merge upstream/master</code></pre><p>6. Envía (push) los cambios a GitHub</p><p>En este punto tu rama local está sincronizada con la rama maestra del repositorio original. Si deseas actualizar el repositorio de GitHub, necesitas enviar tus cambios.</p><pre><code>$ git push origin master</code></pre><p><strong>NOTA:</strong> Luego de sincronizar tu rama maestra puedes eliminar el repositorio upstream, si lo desea. Pero lo necesitará para actualizar/sincronizar tu repositorio en el futuro, por lo que es una buena práctica conservarlo.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2020/01/remote-dlt.png" class="kg-image" alt="remote-dlt" width="600" height="400" loading="lazy"></figure><pre><code>$ git remote rm [Nombre del Repositorio Remoto]</code></pre><h3 id="8-elimina-ramas-innecesarias">8. Elimina ramas innecesarias</h3><p>Las ramas son creadas para propósitos especiales. Una vez que ese propósito se cumple, aquellas ramas ya no son necesarias, por lo que puedes eliminarlas.</p><pre><code>$ git branch -d [Nombre de la Rama]</code></pre><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2020/01/delete.png" class="kg-image" alt="delete" width="600" height="400" loading="lazy"></figure><p>También, puedes eliminar su versión en GitHub.</p><pre><code>git push origin --delete [Nombre de la Rama]</code></pre><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2020/01/last.png" class="kg-image" alt="last" width="600" height="400" loading="lazy"></figure><h2 id="conclusi-n">Conclusión</h2><p>GitHub es una poderosa herramienta para controlar el historial de versiones. Todos pueden contribuir a proyectos de código abierto mediante pull requests. Las contribuciones no siempre son un código; también hay otras formas de contribuir.</p><p>Finalmente, debo decirte que no debes preocuparte si tus pull requests son rechazadas. Los encargados de los proyectos dedican mucho tiempo a mejorarlos y saben mucho más sobre sus proyectos que nosotros. Así que no te preocupes si tu solicitud no es tenida en cuenta.</p><blockquote>Mantente fuerte, positivo y nunca te rindas.<br>― Roy T. Bennett, <a href="https://www.goodreads.com/work/quotes/49604402" rel="noopener">The Light in the Heart</a></blockquote><p>Este artículo fue originalmente publicado en <a href="https://medium.com/@mvthanoshan9/how-to-make-your-first-pull-request-on-github-9aefca5cc837">Medium</a>.</p><p>Puedes contactarme y conectar conmigo en <a href="https://twitter.com/ThanoshanMV" rel="noopener">Twitter</a>.</p><p><strong>¡Sigue contribuyendo al mundo del código abierto!</strong></p><p>Traducido del arículo de <strong><a href="https://www.freecodecamp.org/news/author/thanoshan/">Thanoshan MV</a> - <a href="https://www.freecodecamp.org/news/how-to-make-your-first-pull-request-on-github-3/">How to make your first pull request on GitHu</a></strong></p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ El Manual Esencial de Git ]]>
                </title>
                <description>
                    <![CDATA[ Introducción Hola! Soy Sanjula [https://www.linkedin.com/in/sanjula-madurapperuma/], y en esta guía espero poder enseñarte un poco acerca de Git incluyendo:  * Qué es Git  * Porqué aprender Git  * Establecer variables de configuración  * Introducción al comando help en Git  * Cómo convertir un proyecto existente en ]]>
                </description>
                <link>https://www.freecodecamp.org/espanol/news/el-manual-esencial-de-git/</link>
                <guid isPermaLink="false">5fe4e5d38c7cd154bb97da15</guid>
                
                    <category>
                        <![CDATA[ Git ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Fernando Cardellino ]]>
                </dc:creator>
                <pubDate>Wed, 13 Jan 2021 14:00:00 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/espanol/news/content/images/2021/01/1_AhGSZ1spetb37qk_bZd9XA-1-.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <h3 id="introducci-n">Introducción</h3><p>Hola! Soy <a href="https://www.linkedin.com/in/sanjula-madurapperuma/" rel="noopener">Sanjula</a>, y en esta guía espero poder enseñarte un poco acerca de Git incluyendo:</p><ul><li>Qué es Git</li><li>Porqué aprender Git</li><li>Establecer variables de configuración</li><li>Introducción al comando help en Git</li><li>Cómo convertir un proyecto existente en un repositorio de Git local</li><li>Cosas que hacer antes del primer commit</li><li>Cómo agregar archivos al área de preparación (staging area)</li><li>Cómo eliminar archivos del área de preparación</li><li>Realizar tu primer commit</li><li>Cómo clonar un repositorio remoto</li><li>Ver información sobre el respositorio remoto</li><li>Cómo enviar (push) tus cambios al repositorio remoto</li><li>Como crear una rama (branch) para una prestación o problema específico </li><li>Enviar la rama al repositorio remoto luego de ejecutar el comando commit</li><li>Cómo fusionar (merge) una rama</li><li>Cómo eliminar una rama</li></ul><p>¡Empecemos!</p><h3 id="-qu-es-git">¿Qué es Git?</h3><p>En términos sencillos, Git es un <strong>sistema de control de versiones distribuido de código abierto</strong>.</p><p>Los sistemas de control de versiones ayudan a cualquier equipo de software a gestionar cambios en el código fuente de un producto o servicio a lo largo del tiempo. Realiza un seguimiento de todas las modificaciones al código fuente en una base de datos. Si se ha cometido un error crítico en el código fuente, los desarrolladores de un equipo de software pueden retrotraer el código fuente a una versión antes de que se realizara el cambio erróneo. Como resultado, los sistemas de control de versiones protegen el código fuente de desastres, errores humanos y consecuencias no deseadas (cuando una corrección de errores rompe otra parte de la aplicación, por ejemplo).</p><h3 id="entonces-porqu-aprender-git">Entonces, ¿Porqué aprender Git?</h3><p>Git es el sistema de control de versiones más utilizado en el mundo actualmente. Es un proyecto de código abierto maduro y mantenido activamente, desarrollado originalmente por Linus Torvalds.</p><p>Una cantidad asombrosa de proyectos de software dependen de Git para el control de versiones, incluidos proyectos comerciales y de código abierto, especialmente utilizando el servicio de alojamiento de repositorios de git, GitHub, que ahora es propiedad de Microsoft. De ahí la importancia de aprender Git.</p><h3 id="prerrequisitos-para-esta-gu-a">Prerrequisitos para esta guía</h3><p>Descarga e instala git desde <strong><a href="http://www.git-scm.com/downloads">aquí</a></strong></p><h3 id="verifica-la-versi-n-de-git">Verifica la versión de git</h3><pre><code>git --version</code></pre><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://cdn-media-1.freecodecamp.org/images/G81z00SqImj30aOmL1mnhLIa6tW08Xyws1z6" class="kg-image" alt="G81z00SqImj30aOmL1mnhLIa6tW08Xyws1z6" width="734" height="138" loading="lazy"><figcaption>Figure-2: Git version</figcaption></figure><p>Si el número de versión es devuelto, entonces significa que git ha sido instalado exitosamente en tu computador.</p><h3 id="estableciendo-los-valores-de-configuraci-n">Estableciendo los valores de configuración</h3><p>Ahora debemos establecer las variables de configuración global, que son muy importantes, especialmente si estás trabajando con otros desarrolladores. La principal ventaja de esto es que es más fácil averiguar quién ha hecho un commit de determinado bloque de código, por ejemplo.</p><pre><code>git config --global user.name “Sanjula Madurapperuma”</code></pre><pre><code>git config --global user.email “sanjula@mail.com”</code></pre><pre><code>git config --list</code></pre><h3 id="comando-help">Comando help</h3><p>Como puedes notar, <em>config</em> es un verbo que se ha usado con frecuencia hasta ahora en este manual y los verbos también se pueden usar como prefijo o sufijo con el comando help. Podemos usar el mismo ejemplo (el verbo <em>config</em>) de arriba para explicar estos comandos.</p><pre><code>git help config</code></pre><pre><code>git config --help</code></pre><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://cdn-media-1.freecodecamp.org/images/TpOqdmWxNM11sihKZDfCBkvpqrPyO0QVMkhj" class="kg-image" alt="TpOqdmWxNM11sihKZDfCBkvpqrPyO0QVMkhj" width="734" height="475" loading="lazy"><figcaption>Figure-3: Comando Help</figcaption></figure><p>Los dos comandos indicados realizan la misma acción. Muestran la página de manual del verbo especificado. Esto será útil para identificar capacidades más avanzadas de git.</p><h3 id="c-mo-inicializar-un-repositorio-a-partir-de-c-digo-existente">Cómo inicializar un repositorio a partir de código existente</h3><p>Si tienes un repositorio local que deseas convertir en un proyecto git para comenzar a rastrearlo, entonces podemos comenzar ejecutando el comando de abajo dentro del directorio del proyecto.</p><pre><code>git init</code></pre><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://cdn-media-1.freecodecamp.org/images/X5ju5iD8xMwFsvQ5xomZtkvkGbo2GCAWLYVQ" class="kg-image" alt="X5ju5iD8xMwFsvQ5xomZtkvkGbo2GCAWLYVQ" width="734" height="133" loading="lazy"><figcaption>Figure-4: Git init</figcaption></figure><p>¡Listo! Así, has convertido tu proyecto en un repositorio local de git. Si abres la carpeta del proyecto, verás que se ha creado un nuevo directorio llamado .git.</p><h3 id="que-hacer-antes-del-primer-commit">Que hacer antes del primer commit</h3><p>Ingresa el siguiente comando para ver los archivos sin seguimiento (untracked files):</p><pre><code>git status</code></pre><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://cdn-media-1.freecodecamp.org/images/A1cKNf7PUeDJ-SI2zyrkuH-g3NvF5YfHy-T7" class="kg-image" alt="A1cKNf7PUeDJ-SI2zyrkuH-g3NvF5YfHy-T7" width="734" height="239" loading="lazy"><figcaption>Figure-5: Git status</figcaption></figure><p>Si hay archivos que no deseas que otras personas vean en el repositorio, como archivos que contienen preferencias personales o las del IDE, has lo siguiente:</p><pre><code>touch .gitignore</code></pre><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://cdn-media-1.freecodecamp.org/images/AkaWuuihvkq5cE5P1r8E0QHOF6cgDzrQlJsy" class="kg-image" alt="AkaWuuihvkq5cE5P1r8E0QHOF6cgDzrQlJsy" width="673" height="20" loading="lazy"><figcaption>Figure-6: Crear archivo .gitignore</figcaption></figure><p>Para especificar qué archivos no se agregarán al repositorio de git, abre en un editor de texto el archivo .gitignore, que se puede editar como un archivo de texto normal. Ahora podemos ingresar lo siguiente en el archivo, por ejemplo:</p><pre><code>.project</code></pre><pre><code>*.java</code></pre><p>También se pueden utilizar caracteres comodín. En este caso, se ha utilizado para especificar que no se agreguen todos los archivos que terminan con la extensión .java al repositorio.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://cdn-media-1.freecodecamp.org/images/Q3wRtlkpWsPt02lPztKmqDDVfWuKovzkZGL5" class="kg-image" alt="Q3wRtlkpWsPt02lPztKmqDDVfWuKovzkZGL5" width="636" height="481" loading="lazy"><figcaption>Figure-7: Edición en el editor de texto</figcaption></figure><p>Ahora ejecuta nuevamente git status</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://cdn-media-1.freecodecamp.org/images/V5AwN6ykf9r1dBZ87ViMbvschLJI2iTfBJ4t" class="kg-image" alt="V5AwN6ykf9r1dBZ87ViMbvschLJI2iTfBJ4t" width="719" height="215" loading="lazy"><figcaption>Figure-8:Después de actualizar .gitignore</figcaption></figure><p>Ahora puedes ver que los archivos que indicamos en el archivo .gitignore ya no se muestran en la lista de archivos sin seguimiento. El archivo .gitignore debe confirmarse (usando el comando commit) en el repositorio para mantener las mismas exclusiones en todos los demás lugares.</p><h3 id="agregando-archivos-al-rea-de-preparaci-n-staging-area-">Agregando archivos al área de preparación (staging area)</h3><p>Todo este tiempo estuvimos en el directorio de trabajo. El área de preparación es donde organizamos todos los archivos que se rastrean y deben confirmarse antes de enviarlos al repositorio de git. Es un archivo que almacena lo que se debe incluir en la próxima confirmación.</p><p>Si deseas agregar todos los archivos que actualmente &nbsp;están sin seguimiento y has cambiado al área de preparación, usa el siguiente comando:</p><pre><code>git add -A</code></pre><p>Si deseas agregar archivos individualmente, podemos indicar el nombre del archivo después de git add. Por ejemplo,</p><pre><code>git add .gitignore</code></pre><p>Ahora, si escribes git status, verás que el archivo .gitignore está en el área de preparación.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://cdn-media-1.freecodecamp.org/images/HaV5Fai1lvx-xPkdMRsRdCM8Gp8D8Ns6M5fX" class="kg-image" alt="HaV5Fai1lvx-xPkdMRsRdCM8Gp8D8Ns6M5fX" width="615" height="203" loading="lazy"><figcaption>Figure-9: area para Staging</figcaption></figure><h3 id="eliminando-archivos-del-rea-de-preparaci-n">Eliminando archivos del área de preparación</h3><p>Para eliminar archivos del área de preparación de manera individual, escribe lo siguiente (por ejemplo):</p><pre><code>git reset simple.py</code></pre><p>Esto eliminará el archivo simple.py del área de preparación. Para ver este cambio, escribe nuevamente el comando git status.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://cdn-media-1.freecodecamp.org/images/hbseWQzJKSluv5zAwHbsj7gi6DBAWt6YBWwM" class="kg-image" alt="hbseWQzJKSluv5zAwHbsj7gi6DBAWt6YBWwM" width="700" height="273" loading="lazy"><figcaption>Figure-10: Eliminación del archivo del área de preparación</figcaption></figure><p>Si deseas eliminar todos los archivos del área de preparación, entonces ejecuta lo siguiente:</p><pre><code>git reset</code></pre><p>Ahora, si escribes git status, veremos que todos los archivos han cambiado a archivos sin seguimiento.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://cdn-media-1.freecodecamp.org/images/aUpZJl-E8YA74eLlnf6en0ojS1ohWSil09wY" class="kg-image" alt="aUpZJl-E8YA74eLlnf6en0ojS1ohWSil09wY" width="702" height="236" loading="lazy"><figcaption>Figure-11: Restablecer todos los archivos</figcaption></figure><h3 id="ejecutando-el-primer-commit">Ejecutando el primer commit</h3><p>Ahora ejecuta lo siguiente para agregar todos los archivos al área de preparación para ser confirmados.</p><pre><code>git add -A</code></pre><p>Si lo deseas, puedes ejecutar git status para ver todos los archivos que serán confirmados.</p><p>Para realizar un commit, escribe lo siguiente.</p><pre><code>git commit -m “Initial Commit”</code></pre><p>“-m” especifica un mensaje que se debe pasar describiendo la confirmación. Dado que este es nuestro primer commit, escribiremos Initial Commit.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://cdn-media-1.freecodecamp.org/images/lAHfY5GgwQEjkE8HBcuXiDGM9yDFdqxS0AvX" class="kg-image" alt="lAHfY5GgwQEjkE8HBcuXiDGM9yDFdqxS0AvX" width="725" height="124" loading="lazy"><figcaption>Figure-12: Initial Commit</figcaption></figure><p>Como puedes ver, el commit se ha ejecutado correctamente.</p><p>Si ahora ejecutas git status, verás que se indica que el directorio de trabajo está limpio ya que se han confirmado todos los archivos y no se ha modificado ninguno desde entonces.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://cdn-media-1.freecodecamp.org/images/UscWoVk2VszFJowNHo8kawe9dPqmanjl717h" class="kg-image" alt="UscWoVk2VszFJowNHo8kawe9dPqmanjl717h" width="599" height="55" loading="lazy"><figcaption>Figure-13: Árbol de trabajo después del commit</figcaption></figure><p>Si ejecutamos el siguiente comando:</p><pre><code>git log</code></pre><p>luego podemos ver el commit que habiamos ejcutado, incluyendo el número hash del commit.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://cdn-media-1.freecodecamp.org/images/cjCho8GR69IU5ACe0ghU7TsDOKFKuP4Flbjt" class="kg-image" alt="cjCho8GR69IU5ACe0ghU7TsDOKFKuP4Flbjt" width="591" height="111" loading="lazy"><figcaption>Figure-14: número de hash Commit</figcaption></figure><p>¡Ahora estamos rastreando exitosamente el proyecto local con git!</p><h3 id="clonando-un-repositorio-remoto">Clonando un repositorio remoto</h3><p>Si queremos rastrear un proyecto remoto existente con git, entonces tenemos que escribir un comando en el siguiente formato:</p><pre><code>git clone &lt;url&gt; &lt;directorio donde clonar&gt;</code></pre><p>A modo de ejemplo, usaré el repositorio de git en <a href="https://github.com/sanjulamadurapperuma/GitDemoMedium">este enlace</a>. </p><p>Primero me ubicaré en el directorio donde quiero clonar el proyecto, aunque puedes especificar esto tal como se muestra arriba.</p><p>Ve al enlace del repositorio indicado antes y has clic en "Code", luego copia el url que figura.</p><p>Luego escribe:</p><pre><code>git clone https://github.com/sanjulamadurapperuma/GitDemoMedium.git</code></pre><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://cdn-media-1.freecodecamp.org/images/lHzsIA1k-D5qeBSOciWt443gD3YClS8q8e9y" class="kg-image" alt="lHzsIA1k-D5qeBSOciWt443gD3YClS8q8e9y" width="726" height="179" loading="lazy"><figcaption>Figure-15: Clonación del repositorio remoto</figcaption></figure><p>De esta forma hemos clonado el repositorio exitosamente.</p><p>Si ingresamos el siguiente comando, veremos todos los archivos que ahora están en el directorio local.</p><pre><code>ls -la</code></pre><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://cdn-media-1.freecodecamp.org/images/2OMMDj4xttnnVsgamdc36jy5B2oopjLcSLsB" class="kg-image" alt="2OMMDj4xttnnVsgamdc36jy5B2oopjLcSLsB" width="714" height="147" loading="lazy"><figcaption>Figure-16: Listar todos los archivos en el directorio</figcaption></figure><h3 id="viendo-informaci-n-sobre-el-repositorio-remoto">Viendo información sobre el repositorio remoto</h3><p>Si escribes el siguiente comando:</p><pre><code>git remote -v</code></pre><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://cdn-media-1.freecodecamp.org/images/qkYzprJKHXHwd4KHfzDQwF3Sjj2Nh1niZIZU" class="kg-image" alt="qkYzprJKHXHwd4KHfzDQwF3Sjj2Nh1niZIZU" width="724" height="73" loading="lazy"><figcaption>Figure-17: Git remote -v</figcaption></figure><p>Este comando enumerará las ubicaciones de donde el repositorio local obtendrá los cambios realizados externamente y a dónde serán enviadas tus confirmaciones o cambios que realices al repositorio remoto.</p><p>Si escribes el comando:</p><pre><code>git branch -a</code></pre><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://cdn-media-1.freecodecamp.org/images/ig6sDj8Y1Gzqm2UMsvRvbwZlxnVrtKy6MBBl" class="kg-image" alt="ig6sDj8Y1Gzqm2UMsvRvbwZlxnVrtKy6MBBl" width="722" height="92" loading="lazy"><figcaption>Figure-18: Lista todas las ramas de git</figcaption></figure><p>Esto enumerará todas las ramas que se encuentran en el repositorio, tanto local como remotamente.</p><p>Para demostrar la actualización del repositorio remoto, haremos algunos cambios en los archivos del repositorio que clonamos.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://cdn-media-1.freecodecamp.org/images/n7tWT09vfQnKeaxoN0XyCY1r9Ql4pbwUozXw" class="kg-image" alt="n7tWT09vfQnKeaxoN0XyCY1r9Ql4pbwUozXw" width="564" height="453" loading="lazy"><figcaption>Figure-19: Realizar cambios en simple.py</figcaption></figure><p>Ahora que hemos realizado un cambio en nuestro código, la siguiente acción que debemos realizar es enviar estos cambios al repositorio remoto.</p><h3 id="enviando-los-cambios-al-repositorio-remoto">Enviando los cambios al repositorio remoto</h3><p>El siguiente comando mostrará todos los cambios que se han hecho a los archivos.</p><pre><code>git diff</code></pre><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://cdn-media-1.freecodecamp.org/images/UiWSb3gZiGs5A7fBksCDIDHkt99puF551amJ" class="kg-image" alt="UiWSb3gZiGs5A7fBksCDIDHkt99puF551amJ" width="721" height="165" loading="lazy"><figcaption>Figure-20: Ver los cambios en el archivo</figcaption></figure><p>Si ingresamos git status de nuevo, veremos que se han rastreado cambios y que simple.py ha sido modificado.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://cdn-media-1.freecodecamp.org/images/n9A8DdvhDyKjllzgS2ExFYrM4FsofyoUA0gR" class="kg-image" alt="n9A8DdvhDyKjllzgS2ExFYrM4FsofyoUA0gR" width="723" height="216" loading="lazy"><figcaption>Figure-21: Ver archivos modificados</figcaption></figure><p>Ahora agrégalos al área de preparación</p><pre><code>git add -A</code></pre><p>Ejecuta git status nuevamente</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://cdn-media-1.freecodecamp.org/images/7jaUjBjc3Y2870zUbEllhi8rWvQ1Hshgcyqx" class="kg-image" alt="7jaUjBjc3Y2870zUbEllhi8rWvQ1Hshgcyqx" width="725" height="216" loading="lazy"><figcaption>Figure-22: Agregar archivos al área de staging</figcaption></figure><p>Ahora vemos que simple.py esta listo para ser confirmado.</p><p>Luego escribe el comando commit con un mensaje</p><pre><code>git commit -m “Updated hello function”</code></pre><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://cdn-media-1.freecodecamp.org/images/XU3eet4u0GXZ7QHQNz98n2nN5fEVlswPV1s2" class="kg-image" alt="XU3eet4u0GXZ7QHQNz98n2nN5fEVlswPV1s2" width="733" height="75" loading="lazy"><figcaption>Figure-23: mensaje Commit</figcaption></figure><p>Ahora debemos enviar los cambios confirmados al repositorio remoto para que otras personas tengan acceso a ellos.</p><p>Dado que lo común es que hay varios desarrolladores trabajando en un solo proyecto, primero tenemos que extraer cualquier cambio que se haya realizado en el repositorio remoto antes de enviar nuestros cambios para evitar conflictos.</p><p>Ejecuta el siguiente comando:</p><pre><code>git pull origin master</code></pre><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://cdn-media-1.freecodecamp.org/images/5TkIfVHFN2pS9akhGmgjHVxHRoR6SrgwJEYc" class="kg-image" alt="5TkIfVHFN2pS9akhGmgjHVxHRoR6SrgwJEYc" width="733" height="89" loading="lazy"><figcaption>Figure-24: Extraer cambios del repositorio remoto</figcaption></figure><p>Como ya estamos actualizados, ahora podemos enviar nuestros cambios al repositorio remoto.</p><p>Ahora ejecuta lo siguiente:</p><pre><code>git push origin master</code></pre><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://cdn-media-1.freecodecamp.org/images/t7wVKea6PcQGihQzTeoz3WdS66L8IGjPdpqE" class="kg-image" alt="t7wVKea6PcQGihQzTeoz3WdS66L8IGjPdpqE" width="733" height="197" loading="lazy"><figcaption>Figure-25: Subir cambios al repositorio remoto</figcaption></figure><p>¡Hemos enviado con éxito nuestros cambios a la rama principal del repositorio remoto!</p><h3 id="creando-una-rama-para-una-prestaci-n-o-problema-especifico">Creando una rama para una prestación o problema especifico</h3><p>Hasta ahora hemos estado trabajando en nuestra rama maestra o principal, pero no es así como deberías trabajar en git como desarrollador porque la rama maestra debe ser una versión estable del proyecto en el que estás trabajando. Entonces, para cada prestación o problema, generalmente es la norma crear tu propia rama y luego trabajar sobre esa rama.</p><p>El comando para crear una nueva rama llamada simple-greeting es el siguiente:</p><pre><code>git branch simple-greeting</code></pre><p>Ahora si ejecutas</p><pre><code>git branch</code></pre><p>luego verás todas las ramas del repositorio, y la rama en la que tu estás ubicado se encuentra resaltada con un asterisco del lado izquierdo</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://cdn-media-1.freecodecamp.org/images/XlYSPXjn7qFPNQiLTIywhgNdYKjxD9MFzip4" class="kg-image" alt="XlYSPXjn7qFPNQiLTIywhgNdYKjxD9MFzip4" width="738" height="92" loading="lazy"><figcaption>Figure-26: git branch</figcaption></figure><p>Si deseas cambiarte a la rama recientemente creada por ti, escribe lo siguiente:</p><pre><code>git checkout simple-greeting</code></pre><p>Ahora, si escribes git branch verás que ahora te encuentras en la rama simple-greeting.</p><p>Ahora debemos realizar los cambios en el proyecto. Nos dirigimos al archivo y definimos la función greeting.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://cdn-media-1.freecodecamp.org/images/VLWULRA1hRT85jSYBs1d4JH90JBUQP2kDrrc" class="kg-image" alt="VLWULRA1hRT85jSYBs1d4JH90JBUQP2kDrrc" width="564" height="453" loading="lazy"><figcaption>Figure-27: Definir la función de saludo</figcaption></figure><p>Ahora repetimos el proceso para confirmar estos cambios:</p><pre><code>git status</code></pre><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://cdn-media-1.freecodecamp.org/images/lFNjI8aQZ7CZFUUnNMieYovVJ218kg9MO3Lf" class="kg-image" alt="lFNjI8aQZ7CZFUUnNMieYovVJ218kg9MO3Lf" width="734" height="161" loading="lazy"><figcaption>Figure-28: Ver los cambios que no son staged</figcaption></figure><pre><code>git add -A</code></pre><pre><code>git commit -m “Greeting Function”</code></pre><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://cdn-media-1.freecodecamp.org/images/vsigz7NjuUVcgaaPetiERCN1La5W8F5BoOFd" class="kg-image" alt="vsigz7NjuUVcgaaPetiERCN1La5W8F5BoOFd" width="733" height="92" loading="lazy"><figcaption>Figure-29: mensaje Commit para la función de saludo</figcaption></figure><p>Este commit solo cambiará los archivos en la rama simple-greeting local, no habiendo alterado aún la rama master local ni el repositorio remoto.</p><h3 id="enviando-la-rama-al-repositorio-remoto-luego-de-efectuar-una-confirmaci-n">Enviando la rama al repositorio remoto luego de efectuar una confirmación</h3><p>Ingresa el siguiente comando:</p><pre><code>git push -u origin simple-greeting</code></pre><p>donde origin es el nombre del respositorio y simple-greeting es la rama que le queremos enviar.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://cdn-media-1.freecodecamp.org/images/M3mB0GiO80v-Jk56yKQKuIgnUVaXQvDfGnM-" class="kg-image" alt="M3mB0GiO80v-Jk56yKQKuIgnUVaXQvDfGnM-" width="735" height="325" loading="lazy"><figcaption>Figure-30: Sube la rama al repositorio remoto</figcaption></figure><p>Ahora hemos enviado la rama simple-greeting al repositorio remoto. Si escribes:</p><pre><code>git branch -a</code></pre><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://cdn-media-1.freecodecamp.org/images/GrUXJqmZJmFgb3jHf8B3PlxT7yxVwOCncuIB" class="kg-image" alt="GrUXJqmZJmFgb3jHf8B3PlxT7yxVwOCncuIB" width="734" height="122" loading="lazy"><figcaption>Figure-31: Rama de simple-greeting en el repositorio remoto</figcaption></figure><p>Ahora vemos que en nuestro repositorio remoto tenemos la rama simple-greeting. ¿Porqué debemos enviar la rama al repositorio remoto? Porque en algunas empresas es allí donde ejecutan sus pruebas unitarias y en otras para asegurarse de que el código se ejecute bien antes de fusionarse con la rama maestra.</p><p>Dado que todas la prueban ha sido exitosas (no entraremos en detalles de eso aquí), ahora podemos fusionar la rama simple-greeting con la rama principal.</p><h3 id="fusionando-una-rama">Fusionando una rama</h3><p>Primero, debemos ubicarnos (checkout) en la rama maestra local</p><pre><code>git checkout master</code></pre><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://cdn-media-1.freecodecamp.org/images/OvI0f0CpYa3xrFvKv-HQ5LB20HxbgOEHxT9I" class="kg-image" alt="OvI0f0CpYa3xrFvKv-HQ5LB20HxbgOEHxT9I" width="733" height="75" loading="lazy"><figcaption>Figure-32: Navegar a la rama master</figcaption></figure><p>Extraemos todos los cambios de la rama maestra remota:</p><pre><code>git pull origin master</code></pre><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://cdn-media-1.freecodecamp.org/images/S1bz0eJjDY1avLSy4Gl7Et33gwDw2uGVeih3" class="kg-image" alt="S1bz0eJjDY1avLSy4Gl7Et33gwDw2uGVeih3" width="735" height="89" loading="lazy"><figcaption>Figure-33: Extraer cambios del repositorio remoto</figcaption></figure><p>Ahora veremos todas las ramas que hemos fusionado hasta ahora:</p><pre><code>git branch —-merged</code></pre><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://cdn-media-1.freecodecamp.org/images/v9PBL7dVbIsb3aIz61PRypR6qorrAcw6nahW" class="kg-image" alt="v9PBL7dVbIsb3aIz61PRypR6qorrAcw6nahW" width="734" height="56" loading="lazy"><figcaption>Figure-34: Mostrar ramas ligadas</figcaption></figure><p>la rama simple-greeting no figurará ya que aún no la hemos fusionado.</p><p>Para fusionar simple-greeting con la principal, ingresa:</p><pre><code>git merge simple-greeting</code></pre><p>(Ten en cuenta que ahora estamos en la rama maestra)</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://cdn-media-1.freecodecamp.org/images/4G84bB5YgbwdfH8XkDHUxUZwGfi8mMw0ZHKa" class="kg-image" alt="4G84bB5YgbwdfH8XkDHUxUZwGfi8mMw0ZHKa" width="726" height="109" loading="lazy"><figcaption>Figure-35: Ligar la rama simple-greeting</figcaption></figure><p>Ahora que ha sido fusionada, podemos enviar los cambios a la rama maestra del repositorio remoto.</p><pre><code>git push origin master</code></pre><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://cdn-media-1.freecodecamp.org/images/bQjuJUw584OprdvxUzmNs1yxOh8Ijd3WLQwK" class="kg-image" alt="bQjuJUw584OprdvxUzmNs1yxOh8Ijd3WLQwK" width="734" height="125" loading="lazy"><figcaption>Figure-36: Sube a la rama maestra remota</figcaption></figure><p>Ahora los cambios han sido enviados a la rama maestra del repositorio remoto. </p><h3 id="eliminando-una-rama">Eliminando una rama</h3><p>Dado que la función o la nueva prestación ya se ha implementado, podemos eliminar la rama simple-greeting. Para verificar la fusión realizada en la sección anterior, podemos ejecutar:</p><pre><code>git branch --merged</code></pre><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://cdn-media-1.freecodecamp.org/images/C-XMNUIumKsfPaPVDD5BFyvDBzo8rrJCTTEl" class="kg-image" alt="C-XMNUIumKsfPaPVDD5BFyvDBzo8rrJCTTEl" width="735" height="75" loading="lazy"><figcaption>Figure-37: Mostrar ramas ligadas</figcaption></figure><p>Si simple-greeting se muestra aquí, eso significa que hemos fusionado todos los cambios y que la rama ya puede ser descartada.</p><pre><code>git branch -d simple-greeting</code></pre><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://cdn-media-1.freecodecamp.org/images/hd10e8Mc246riKYeTEvv0hL1xz7k7b7njSHf" class="kg-image" alt="hd10e8Mc246riKYeTEvv0hL1xz7k7b7njSHf" width="733" height="53" loading="lazy"><figcaption>Figure-38: Eliminar rama local simple-greeting</figcaption></figure><p>Ahora la rama ha sido eliminada localmente.</p><p>Pero como la hemos enviado al repositorio remoto, aún continua ahí. Esto puede ser visto ejecutando:</p><pre><code>git branch -a</code></pre><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://cdn-media-1.freecodecamp.org/images/gHdlHkbjv1QhmID0PkoWM35qMagnJ9B-qIkx" class="kg-image" alt="gHdlHkbjv1QhmID0PkoWM35qMagnJ9B-qIkx" width="735" height="109" loading="lazy"><figcaption>Figure-39: Mostrar todas las ramas</figcaption></figure><p>Para eliminar la rama del repositorio remoto, escribe:</p><pre><code>git push origin --delete simple-greeting</code></pre><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://cdn-media-1.freecodecamp.org/images/5-equM6f4mL9prXhxNiet0JC4lqhn4uzn84v" class="kg-image" alt="5-equM6f4mL9prXhxNiet0JC4lqhn4uzn84v" width="735" height="108" loading="lazy"><figcaption>Figure-40: Eliminar rama remota simple-greeting</figcaption></figure><p>Si volvemos a ejecutar</p><pre><code>git branch -a</code></pre><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://cdn-media-1.freecodecamp.org/images/33hTj4HTBLKO5Eg345weOEBa4yNE2uXglp5Z" class="kg-image" alt="33hTj4HTBLKO5Eg345weOEBa4yNE2uXglp5Z" width="733" height="89" loading="lazy"><figcaption>Figure-41: Mostrar todas las ramas</figcaption></figure><p>Podemos ver que la rama ahora a sido eliminada también del repositorio remoto.</p><p>¡¡Felicitaciones!! ¡Ahora eres un maestro en los comandos básicos pero críticos de Git!</p><p>Para referencia o uso de este tutorial, aquí está el <a href="https://github.com/sanjulamadurapperuma/GitDemoMedium">enlace</a> del repositorio público de GitHub</p><p>Traducido del artículo de <a href="https://www.freecodecamp.org/news/author/sanjula/"><strong>Sanjula Madurapperuma</strong></a><strong><strong> </strong>- <a href="https://www.freecodecamp.org/news/the-essential-git-handbook-a1cf77ed11b5/">The Essential Git Handbook</a></strong></p> ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
