Categorías
Python

Unicode y carácter codificaciones en Python: una guía sin dolor

 

Tabla de Contenidos

  • ¿Cuáles son PNL y SPACY?
  • InstallationHow instalar spaCyHow para descargar modelos y datos
  • Cómo instalar SPACY
  • Cómo descargar modelos y datos
  • Usando spaCyHow leer un StringHow para leer un archivo de texto
  • Cómo leer una cadena
  • Cómo leer un archivo de texto
  • Sentencia Detección
  • Tokenization en sPACY
  • palabras vacías
  • lematización
  • Word Frequency
  • parte del discurso de etiquetado
  • Visualización: Uso de la coincidencia de funciones displaCy
  • preprocesamiento basado en normas
  • Usando sPACY
  • Dependencia analizar Usando sPACY
  • Navegación por el árbol y el subárbol
  • superficial ParsingNoun Frase DetectionVerb Frase Detección
  • frase nominal Detección
  • frase verbal Detección
  • Nombrado Entidad Reconocimiento
  • Conclusión
  • Cómo instalar sPACY
  • Cómo descargar modelos y datos
  • TG_01 9

    • Cómo leer una cadena
    • Cómo leer un archivo de texto
    • frase nominal Detección
    • frase verbal Detección

    SPACY es una biblioteca libre y de código abierto para Natural Language Processing ( PNL) en Python con una gran cantidad de capacidades incorporado. Se está convirtiendo cada vez más popular para el procesamiento y análisis de datos en la PNL. Pruebas de datos no estructurados se produce a gran escala, y es importante para el proceso y las ideas se derivan de los datos no estructurados. Para ello, es necesario representar los datos en un formato que pueda ser entendido por los ordenadores. PNL puede ayudarle a hacer eso.

    En este tutorial, aprenderá:

    • Lo que los términos y conceptos fundamentales de la PNL son
    • Cómo implementar esos conceptos en SPACY
    • Cómo personalizar y ampliar incorporado funcionalidades en SPACY
    • Cómo para realizar análisis estadísticos básicos sobre un texto
    • Cómo crear un gasoducto para procesar texto no estructurado
    • Cómo analizar una frase y extraer conocimiento con sentido de ella Bono

    gratuito: Haga clic aquí para obtener acceso a un capítulo de Python trucos: El libro que te muestra las mejores prácticas de Python con ejemplos sencillos puede aplicar instantáneamente a escribir código más bonito + Pythonic.

    ¿Cuáles son PNL y SPACY?

    PNL es un subcampo de la inteligencia artificial y se ocupa de las interacciones entre los ordenadores y los lenguajes humanos. PNL es el proceso de analizar, comprender y derivar significado del lenguaje humano para ordenadores.

    PNL ayuda a extraer ideas de texto no estructurado y tiene varios casos de uso, tales como:

    • resumen automático
    • entidad denominada reconocimiento
    • Respuesta automática a preguntas análisis de sentimientos

    SPACY es una biblioteca libre de código abierto de PNL en Python. Está escrito en Cython y está diseñado para sistemas de comprensión del lenguaje natural o extracción de información de construcción. Está construido para uso en producción y proporciona una API concisa y fácil de usar. Instalación

    En esta sección, vamos a instalar SPACY y luego descargar los datos y modelos para el idioma Inglés.

    Cómo instalar SPACY

    SPACY puede instalarse utilizando pip , un gestor de paquetes de Python. Puede utilizar un entorno virtual a no depender de los paquetes de todo el sistema. Para obtener más información sobre entorno virtual s y pip , echa un vistazo a ¿Qué es la pipa? Una guía para Nueva Pythonistas y Python entornos virtuales: Una cartilla.

    Crear un nuevo entorno virtual:

    $ python3 -m venv env

    Activar este entorno virtual e instalar SPACY:

    $ source ./env/bin/activate
    $ pip install spacy

    de cómo descargar los modelos y los datos

    SPACY tiene diferentes tipos de modelos. El modelo por defecto para el idioma Inglés es en_core_web_sm.

    Activar el entorno virtual creado en los anteriores modelos de paso y de descarga y los datos para el idioma Inglés:

    $ python -m spacy download en_core_web_sm

    Verificar si la descarga se ha realizado correctamente o no cargándolo:

    >>> import spacy
    >>> nlp = spacy.load('en_core_web_sm')

    Si se crea el objeto PNL, entonces significa que sPACY se instaló y que los modelos y los datos se ha descargado correctamente.

    Usando SPACY

    En esta sección, vamos a usar espaciosa para una cadena de entrada y un archivo de texto. Cargar la instancia modelo de lenguaje en SPACY:

    >>> import spacy
    >>> nlp = spacy.load('en_core_web_sm')

    Aquí, el objeto es una instancia de la PNL modelo de lenguaje. Se puede suponer que, a lo largo de este tutorial, la PNL se refiere al modelo de lenguaje cargado por en_core_web_sm. Ahora puede utilizar SPACY para leer una cadena o un archivo de texto.

    Cómo leer una cadena

    Usted puede utilizar SPACY para crear un objeto Doc procesado, que es un contenedor para acceder a las anotaciones lingüísticas, para una cadena de entrada:

    >>> introduction_text = ('This tutorial is about Natural'
    ... ' Language Processing in Spacy.')
    >>> introduction_doc = nlp(introduction_text)
    >>> # Extract tokens for the given doc
    >>> print ([token.text for token in introduction_doc])
    ['This', 'tutorial', 'is', 'about', 'Natural', 'Language',
    'Processing', 'in', 'Spacy', '.']

    En el ejemplo anterior, el aviso cómo el texto se convierte en un objeto que se entiende por sPACY. Puede utilizar este método para convertir cualquier texto en un objeto Doc procesados ​​y atributos deducir que será cubierto en las próximas secciones.

    Cómo leer un archivo de texto

    En esta sección, creará un objeto Doc procesada por un archivo de texto:

    >>> file_name = 'introduction.txt'
    >>> introduction_file_text = open(file_name).read()
    >>> introduction_file_doc = nlp(introduction_file_text)
    >>> # Extract tokens for the given doc
    >>> print ([token.text for token in introduction_file_doc])
    ['This', 'tutorial', 'is', 'about', 'Natural', 'Language',
    'Processing', 'in', 'Spacy', '.', '\n']

    Así es como se puede convertir un archivo de texto en un objeto Doc procesado.

    Nota:

    se puede asumir que:

    • Los nombres de variables que termina con el sufijo _TEXT son objetos de cadena Unicode.
    • Nombre de la variable que termina con el sufijo _doc son los objetos del modelo de lenguaje SPACY.

    Sentence Detección

    Sentence Detección es el proceso de localizar el inicio y el final de las oraciones en un texto dado. Esto le permite divide un texto en unidades lingüísticamente significativas. Vamos a usar estas unidades cuando se está procesando el texto para realizar tareas tales como etiquetado gramatical y extracción de entidades .

    En SPACY, la propiedad senta se utiliza para extraer frases. Así es como se extraería el número total de frases y las frases de un texto de entrada dado:

    >>> about_text = ('Gus Proto is a Python developer currently'
    ... ' working for a London-based Fintech'
    ... ' company. He is interested in learning'
    ... ' Natural Language Processing.')
    >>> about_doc = nlp(about_text)
    >>> sentences = list(about_doc.sents)
    >>> len(sentences)
    2
    >>> for sentence in sentences:
    ... print (sentence)
    ...
    'Gus Proto is a Python developer currently working for a
    London-based Fintech company.'
    'He is interested in learning Natural Language Processing.'

    En el ejemplo anterior, SPACY es correcta capaz de identificar frases en el idioma Inglés, con un punto como delimitador frase (.) . También puede personalizar la detección frase para detectar frases en delimitadores personalizados.

    He aquí un ejemplo, cuando se utiliza una elipsis (…) como delimitador:

    >>> def set_custom_boundaries(doc):
    ... # Adds support to use `...` as the delimiter for sentence detection
    ... for token in doc[:-1]:
    ... if token.text == '...':
    ... doc[token.i+1].is_sent_start = True
    ... return doc
    ...
    >>> ellipsis_text = ('Gus, can you, ... never mind, I forgot'
    ... ' what I was saying. So, do you think'
    ... ' we should ...')
    >>> # Load a new model instance
    >>> custom_nlp = spacy.load('en_core_web_sm')
    >>> custom_nlp.add_pipe(set_custom_boundaries, before='parser')
    >>> custom_ellipsis_doc = custom_nlp(ellipsis_text)
    >>> custom_ellipsis_sentences = list(custom_ellipsis_doc.sents)
    >>> for sentence in custom_ellipsis_sentences:
    ... print(sentence)
    ...
    Gus, can you, ...
    never mind, I forgot what I was saying.
    So, do you think we should ...
    >>> # Sentence Detection with no customization
    >>> ellipsis_doc = nlp(ellipsis_text)
    >>> ellipsis_sentences = list(ellipsis_doc.sents)
    >>> for sentence in ellipsis_sentences:
    ... print(sentence)
    ...
    Gus, can you, ... never mind, I forgot what I was saying.
    So, do you think we should ...

    Tenga en cuenta que custom_ellipsis_sentences contienen tres frases, mientras que ellipsis_sentences contiene dos frases. Estas frases todavía se obtienen a través del atributo senta, como se vio antes.

    Tokenization en SPACY

    Tokenization es el siguiente paso después de la detección frase. Se le permite identificar las unidades básicas en su texto. Estas unidades básicas se llaman fichas . Tokenization es útil porque rompe un texto en unidades significativas. Estas unidades se utilizan para el análisis adicional, como etiquetado gramatical.

    En SPACY, puede imprimir fichas iterando el objeto Doc:

    >>> for token in about_doc:
    ... print (token, token.idx)
    ...
    Gus 0
    Proto 4
    is 10
    a 13
    Python 15
    developer 22
    currently 32
    working 42
    for 50
    a 54
    London 56
    - 62
    based 63
    Fintech 69
    company 77
    . 84
    He 86
    is 89
    interested 92
    in 103
    learning 106
    Natural 115
    Language 123
    Processing 132
    . 142

    Nota cómo SPACY conserva la índice a partir de las fichas. Es útil para la sustitución de palabras en su lugar. SPACY proporciona varios atributos para la clase Token:

    >>> for token in about_doc:
    ... print (token, token.idx, token.text_with_ws,
    ... token.is_alpha, token.is_punct, token.is_space,
    ... token.shape_, token.is_stop)
    ...
    Gus 0 Gus True False False Xxx False
    Proto 4 Proto True False False Xxxxx False
    is 10 is True False False xx True
    a 13 a True False False x True
    Python 15 Python True False False Xxxxx False
    developer 22 developer True False False xxxx False
    currently 32 currently True False False xxxx False
    working 42 working True False False xxxx False
    for 50 for True False False xxx True
    a 54 a True False False x True
    London 56 London True False False Xxxxx False
    - 62 - False True False - False
    based 63 based True False False xxxx False
    Fintech 69 Fintech True False False Xxxxx False
    company 77 company True False False xxxx False
    . 84 . False True False . False
    He 86 He True False False Xx True
    is 89 is True False False xx True
    interested 92 interested True False False xxxx False
    in 103 in True False False xx True
    learning 106 learning True False False xxxx False
    Natural 115 Natural True False False Xxxxx False
    Language 123 Language True False False Xxxxx False
    Processing 132 Processing True False False Xxxxx False
    . 142 . False True False . False

    En este ejemplo, algunos de los atributos comúnmente requeridas se accede:

    • text_with_ws grabados texto contador de arrastre espacio (si está presente).
    • is_alpha detecta si el elemento está formada por caracteres alfabéticos o no.
    • detecta is_punct si el elemento es un símbolo de puntuacion o no.
    • is_space detecta si el token es un espacio o no.
    • shape_ imprime la forma de la palabra.
    • is_stop detecta si el elemento está parada una palabra o no.

    Nota: Vas a aprender más acerca de las palabras vacías en la siguiente sección.

    También puede personalizar el proceso de tokenización para detectar señales de caracteres personalizados. Esto a menudo se utiliza para las palabras con guiones, que son palabras unidas con un guión. Por ejemplo, “londinense” es una palabra con guión.

    SPACY le permite personalizar la tokenización mediante la actualización de la propiedad tokenizer en el objeto de la PNL:

    >>> import re
    >>> import spacy
    >>> from spacy.tokenizer import Tokenizer
    >>> custom_nlp = spacy.load('en_core_web_sm')
    >>> prefix_re = spacy.util.compile_prefix_regex(custom_nlp.Defaults.prefixes)
    >>> suffix_re = spacy.util.compile_suffix_regex(custom_nlp.Defaults.suffixes)
    >>> infix_re = re.compile(r'''[-~]''')
    >>> def customize_tokenizer(nlp):
    ... # Adds support to use `-` as the delimiter for tokenization
    ... return Tokenizer(nlp.vocab, prefix_search=prefix_re.search,
    ... suffix_search=suffix_re.search,
    ... infix_finditer=infix_re.finditer,
    ... token_match=None
    ... )
    ...

    >>> custom_nlp.tokenizer = customize_tokenizer(custom_nlp)
    >>> custom_tokenizer_about_doc = custom_nlp(about_text)
    >>> print([token.text for token in custom_tokenizer_about_doc])
    ['Gus', 'Proto', 'is', 'a', 'Python', 'developer', 'currently',
    'working', 'for', 'a', 'London', '-', 'based', 'Fintech',
    'company', '.', 'He', 'is', 'interested', 'in', 'learning',
    'Natural', 'Language', 'Processing', '.']

    Con el fin de personalizar, se puede pasar varios parámetros a la clase Tokenizer:

    • nlp.vocab es un recipiente de almacenamiento para especial casos y se utiliza para manejar casos como contracciones y emoticonos.
    • prefix_search es la función que se utiliza para manejar anterior puntuacion, como paréntesis de apertura.
    • infix_finditer es la función que se utiliza para manejar separadores no está en blanco, como guiones.
    • suffix_search es la función que se utiliza para manejar éxito puntuacion, como paréntesis de cierre.
    • token_match es una función booleana opcional que se utiliza para que coincida con cuerdas que nunca debe ser dividida. Se anula las reglas anteriores y es útil para entidades como URLs o números.

    Nota: SPACY ya se detecta palabras con guiones como fichas individuales. El código anterior es sólo un ejemplo para mostrar cómo se puede personalizar tokenización. Se puede utilizar para cualquier otro carácter. Palabras

    parada

    Detener palabras son las palabras más comunes en un idioma. En el idioma Inglés, algunos ejemplos de palabras de parada son los, son, sino, y ellos. La mayoría de las oraciones deben contener palabras vacías con el fin de ser frases completas que tengan sentido.

    En general, las palabras vacías se eliminan porque no son significativos y distorsionan el análisis de frecuencia de palabras. SPACY tiene una lista de palabras de parada para el idioma Inglés:

    >>> import spacy
    >>> spacy_stopwords = spacy.lang.en.stop_words.STOP_WORDS
    >>> len(spacy_stopwords)
    326
    >>> for stop_word in list(spacy_stopwords)[:10]:
    ... print(stop_word)
    ...
    using
    becomes
    had
    itself
    once
    often
    is
    herein
    who
    too

    Puede eliminar las palabras vacías a partir del texto de entrada:

    >>> for token in about_doc:
    ... if not token.is_stop:
    ... print (token)
    ...
    Gus
    Proto
    Python
    developer
    currently
    working
    London
    -
    based
    Fintech
    company
    .
    interested
    learning
    Natural
    Language
    Processing
    .

    Detener palabras como es, una, por, el, y en el que no se imprimen en la salida anterior. También puede crear una lista de testigos que no contengan palabras vacías:

    >>> about_no_stopword_doc = [token for token in about_doc if not token.is_stop]
    >>> print (about_no_stopword_doc)
    [Gus, Proto, Python, developer, currently, working, London,
    -, based, Fintech, company, ., interested, learning, Natural,
    Language, Processing, .]

    about_no_stopword_doc se puede unir con espacios para formar una oración sin palabras vacías.

    Lematización

    Lematización es el proceso de reducir las formas declinadas de una palabra sin dejar de asegurar que la forma reducida pertenece al lenguaje. Esta forma o raíz de la palabra reducida se denomina lema .

    Por ejemplo, organizan s , organizar d y organizar son todas las formas de organizan . Aquí, organizar es el lema. La inflexión de una palabra le permite expresar diferentes categorías gramaticales como tensa ( organizar d vs organizar ), número ( tren s vs tren ), y pronto. Lematización es necesario, ya que ayuda a reducir las formas declinadas de una palabra para que puedan ser analizados como un único elemento. También puede ayudar a normalizar el texto.

    SPACY tiene la lemma_ atributo en la clase de emergencia. Este atributo tiene la forma de un token lematizadas:

    >>> conference_help_text = ('Gus is helping organize a developer'
    ... 'conference on Applications of Natural Language'
    ... ' Processing. He keeps organizing local Python meetups'
    ... ' and several internal talks at his workplace.')
    >>> conference_help_doc = nlp(conference_help_text)
    >>> for token in conference_help_doc:
    ... print (token, token.lemma_)
    ...
    Gus Gus
    is be
    helping help
    organize organize
    a a
    developer developer
    conference conference
    on on
    Applications Applications
    of of
    Natural Natural
    Language Language
    Processing Processing
    . .
    He -PRON-
    keeps keep
    organizing organize
    local local
    Python Python
    meetups meetup
    and and
    several several
    internal internal
    talks talk
    at at
    his -PRON-
    workplace workplace
    . .

    En este ejemplo, la organización se reduce a su forma de organizar lema. Si no lemmatize el texto, a continuación, organizar y organizador será contado como diferentes fichas, a pesar de que ambos tienen un significado similar. Lematización le ayuda a evitar palabras duplicadas que tienen significados similares.

    Word Frequency

    Ahora puede convertir un texto dado en tokens y realizar análisis estadísticos sobre ella. Este análisis le puede dar diferentes puntos de vista sobre patrones de palabras, tales como palabras comunes o las palabras únicas en el texto:

    >>> from collections import Counter
    >>> complete_text = ('Gus Proto is a Python developer currently'
    ... 'working for a London-based Fintech company. He is'
    ... ' interested in learning Natural Language Processing.'
    ... ' There is a developer conference happening on 21 July'
    ... ' 2019 in London. It is titled "Applications of Natural'
    ... ' Language Processing". There is a helpline number '
    ... ' available at +1-1234567891. Gus is helping organize it.'
    ... ' He keeps organizing local Python meetups and several'
    ... ' internal talks at his workplace. Gus is also presenting'
    ... ' a talk. The talk will introduce the reader about "Use'
    ... ' cases of Natural Language Processing in Fintech".'
    ... ' Apart from his work, he is very passionate about music.'
    ... ' Gus is learning to play the Piano. He has enrolled '
    ... ' himself in the weekend batch of Great Piano Academy.'
    ... ' Great Piano Academy is situated in Mayfair or the City'
    ... ' of London and has world-class piano instructors.')
    ...
    >>> complete_doc = nlp(complete_text)
    >>> # Remove stop words and punctuation symbols
    >>> words = [token.text for token in complete_doc
    ... if not token.is_stop and not token.is_punct]
    >>> word_freq = Counter(words)
    >>> # 5 commonly occurring words with their frequencies
    >>> common_words = word_freq.most_common(5)
    >>> print (common_words)
    [('Gus', 4), ('London', 3), ('Natural', 3), ('Language', 3), ('Processing', 3)]
    >>> # Unique words
    >>> unique_words = [word for (word, freq) in word_freq.items() if freq == 1]
    >>> print (unique_words)
    ['Proto', 'currently', 'working', 'based', 'company',
    'interested', 'conference', 'happening', '21', 'July',
    '2019', 'titled', 'Applications', 'helpline', 'number',
    'available', '+1', '1234567891', 'helping', 'organize',
    'keeps', 'organizing', 'local', 'meetups', 'internal',
    'talks', 'workplace', 'presenting', 'introduce', 'reader',
    'Use', 'cases', 'Apart', 'work', 'passionate', 'music', 'play',
    'enrolled', 'weekend', 'batch', 'situated', 'Mayfair', 'City',
    'world', 'class', 'piano', 'instructors']

    Al observar las palabras comunes, se puede ver que el texto en su conjunto es probablemente alrededor de Gus, Londres o natural Procesamiento del lenguaje. De esta manera, se puede tomar cualquier texto estructurado y realizar análisis estadísticos para saber de qué se trata.

    Aquí hay otro ejemplo del mismo texto con las palabras vacías:

    >>> words_all = [token.text for token in complete_doc if not token.is_punct]
    >>> word_freq_all = Counter(words_all)
    >>> # 5 commonly occurring words with their frequencies
    >>> common_words_all = word_freq_all.most_common(5)
    >>> print (common_words_all)
    [('is', 10), ('a', 5), ('in', 5), ('Gus', 4), ('of', 4)]

    Cuatro de cada cinco de las palabras más comunes son palabras vacías, que no te dicen mucho sobre el texto. Si se tiene en cuenta las palabras de parada mientras se hace el análisis de frecuencia de palabras, entonces usted no será capaz de obtener conocimiento con sentido del texto de entrada. Esta es la razón por la eliminación de palabras vacías es tan importante.

    Parte del discurso Tagging

    Parte de la oración o POS es una función gramatical que explica cómo se usa una palabra en particular en una oración. Hay ocho partes del discurso:

    Parte de la oración etiquetado es el proceso de asignar una etiqueta POS a cada ficha, dependiendo de su uso en la frase. POS etiqueta s son útiles para la asignación de una categoría sintáctica como sustantivo, verbo o a cada palabra.

    En SPACY, etiquetas POS están disponibles como un atributo en el objeto simbólico:

    >>> for token in about_doc:
    ... print (token, token.tag_, token.pos_, spacy.explain(token.tag_))
    ...
    Gus NNP PROPN noun, proper singular
    Proto NNP PROPN noun, proper singular
    is VBZ VERB verb, 3rd person singular present
    a DT DET determiner
    Python NNP PROPN noun, proper singular
    developer NN NOUN noun, singular or mass
    currently RB ADV adverb
    working VBG VERB verb, gerund or present participle
    for IN ADP conjunction, subordinating or preposition
    a DT DET determiner
    London NNP PROPN noun, proper singular
    - HYPH PUNCT punctuation mark, hyphen
    based VBN VERB verb, past participle
    Fintech NNP PROPN noun, proper singular
    company NN NOUN noun, singular or mass
    . . PUNCT punctuation mark, sentence closer
    He PRP PRON pronoun, personal
    is VBZ VERB verb, 3rd person singular present
    interested JJ ADJ adjective
    in IN ADP conjunction, subordinating or preposition
    learning VBG VERB verb, gerund or present participle
    Natural NNP PROPN noun, proper singular
    Language NNP PROPN noun, proper singular
    Processing NNP PROPN noun, proper singular
    . . PUNCT punctuation mark, sentence closer

    Aquí, se accede a dos atributos de la clase de emergencia:

    spacy.explain da detalles descriptivos de un punto de venta etiqueta en particular. SPACY proporciona una lista de etiquetas completa junto con una explicación para cada etiqueta.

    El uso de identificadores de punto de venta, se puede extraer una categoría particular de las palabras:

    >>> nouns = []
    >>> adjectives = []
    >>> for token in about_doc:
    ... if token.pos_ == 'NOUN':
    ... nouns.append(token)
    ... if token.pos_ == 'ADJ':
    ... adjectives.append(token)
    ...
    >>> nouns
    [developer, company]
    >>> adjectives
    [interested]

    Usted puede usar esto para penetraciones Derivar, quitar los nombres más comunes, o ver qué adjetivos se utilizan para un sustantivo particular.

    Visualización: Usando displaCy

    SPACY viene con un built-in visualizador llamada displaCy . Se puede utilizar para visualizar una dependencia de análisis o entidades nombradas en un navegador o un cuaderno Jupyter.

    Puede utilizar displaCy para encontrar etiquetas de punto de venta para los tokens:

    >>> from spacy import displacy
    >>> about_interest_text = ('He is interested in learning'
    ... ' Natural Language Processing.')
    >>> about_interest_doc = nlp(about_interest_text)
    >>> displacy.serve(about_interest_doc, style='dep')

    El código anterior hará girar un simple servidor web. Se puede ver la visualización mediante la apertura de http://127.0.0.1:5000 en su navegador:

    En la imagen de arriba, cada símbolo se le asigna una etiqueta escrita POS justo debajo de la ficha.

    Nota: Así es como se puede utilizar displaCy en un cuaderno Jupyter: Funciones

    >>> displacy.render(about_interest_doc, style='dep', jupyter=True)

    preprocesamiento

    Puede crear una función preprocesamiento que toma el texto como entrada y aplica las siguientes operaciones:

    • minúsculas del texto
    • Lemmatizes cada ficha
    • Elimina los símbolos de puntuación palabras vacías
    • Elimina

    un convertidos función pre-procesamiento de texto a un formato analizable. Es necesario para la mayoría de las tareas de PNL. He aquí un ejemplo:

    >>> def is_token_allowed(token):
    ... '''
    ... Only allow valid tokens which are not stop words
    ... and punctuation symbols.
    ... '''
    ... if (not token or not token.string.strip() or
    ... token.is_stop or token.is_punct):
    ... return False
    ... return True
    ...
    >>> def preprocess_token(token):
    ... # Reduce token to its lowercase lemma form
    ... return token.lemma_.strip().lower()
    ...
    >>> complete_filtered_tokens = [preprocess_token(token)
    ... for token in complete_doc if is_token_allowed(token)]
    >>> complete_filtered_tokens
    ['gus', 'proto', 'python', 'developer', 'currently', 'work',
    'london', 'base', 'fintech', 'company', 'interested', 'learn',
    'natural', 'language', 'processing', 'developer', 'conference',
    'happen', '21', 'july', '2019', 'london', 'title',
    'applications', 'natural', 'language', 'processing', 'helpline',
    'number', 'available', '+1', '1234567891', 'gus', 'help',
    'organize', 'keep', 'organize', 'local', 'python', 'meetup',
    'internal', 'talk', 'workplace', 'gus', 'present', 'talk', 'talk',
    'introduce', 'reader', 'use', 'case', 'natural', 'language',
    'processing', 'fintech', 'apart', 'work', 'passionate', 'music',
    'gus', 'learn', 'play', 'piano', 'enrol', 'weekend', 'batch',
    'great', 'piano', 'academy', 'great', 'piano', 'academy',
    'situate', 'mayfair', 'city', 'london', 'world', 'class',
    'piano', 'instructor']

    Tenga en cuenta que los complete_filtered_tokens no contiene ninguna palabra de parada o signos de puntuación y consta de fichas minúsculas lematizadas. Matching

    basada en reglas Uso de concordancia basada en la Regla SPACY

    es uno de los pasos de extracción de información de texto no estructurado. Se utiliza para identificar y extracto de tokens y frases de acuerdo con los patrones (como en minúsculas) y funciones gramaticales (como parte de la oración). juego basado en reglas

    puede utilizar expresiones regulares para extraer entidades (tales como números de teléfono) de un texto no estructurado. Es diferente de la extracción de texto usando expresiones regulares sólo en el sentido de que las expresiones regulares no tienen en cuenta los atributos léxicos y gramaticales del texto. juego basado en reglas

    Con, puede extraer un nombre y un apellido, que son siempre nombres propios :

    >>> from spacy.matcher import Matcher
    >>> matcher = Matcher(nlp.vocab)
    >>> def extract_full_name(nlp_doc):
    ... pattern = [{'POS': 'PROPN'}, {'POS': 'PROPN'}]
    ... matcher.add('FULL_NAME', None, pattern)
    ... matches = matcher(nlp_doc)
    ... for match_id, start, end in matches:
    ... span = nlp_doc[start:end]
    ... return span.text
    ...
    >>> extract_full_name(about_doc)
    'Gus Proto'

    En este ejemplo, el patrón es una lista de objetos que define la combinación de fichas para ser igualada. Ambas etiquetas de punto de venta en que son PROPN (nombre propio). Así, el patrón se compone de dos objetos en los que las etiquetas de punto de venta para ambas fichas deben ser PROPN. A continuación se añade este patrón para Matcher usando FULL_NAME y el la match_id. Por último, los partidos se obtienen con sus índices de inicio y fin.

    También puede utilizar la concordancia basada en reglas a los números de teléfono de extracto:

    >>> from spacy.matcher import Matcher
    >>> matcher = Matcher(nlp.vocab)
    >>> conference_org_text = ('There is a developer conference'
    ... 'happening on 21 July 2019 in London. It is titled'
    ... ' "Applications of Natural Language Processing".'
    ... ' There is a helpline number available'
    ... ' at (123) 456-789')
    ...
    >>> def extract_phone_number(nlp_doc):
    ... pattern = [{'ORTH': '('}, {'SHAPE': 'ddd'},
    ... {'ORTH': ')'}, {'SHAPE': 'ddd'},
    ... {'ORTH': '-', 'OP': '?'},
    ... {'SHAPE': 'ddd'}]
    ... matcher.add('PHONE_NUMBER', None, pattern)
    ... matches = matcher(nlp_doc)
    ... for match_id, start, end in matches:
    ... span = nlp_doc[start:end]
    ... return span.text
    ...
    >>> conference_org_doc = nlp(conference_org_text)
    >>> extract_phone_number(conference_org_doc)
    '(123) 456-789'

    En este ejemplo, sólo el patrón se actualiza con el fin de igualar los números de teléfono del ejemplo anterior. Aquí, también se utilizan algunos de los atributos de la ficha:

    • ORTE da el texto exacto de la ficha.
    • FORMA transforma la cadena de contadores a mostrar características ortográficas.
    • OP define operadores. Utilizando ? como un medio de valor que el patrón es opcional, lo que significa que puede coincidir con 0 o 1 veces.

    Nota: Por simplicidad, los números de teléfono se supone que son de un formato en particular: (123) 456-789. Puede cambiar esto dependiendo de su caso de uso. juego basado en reglas

    ayuda a identificar y fichas y frases extracto según patrones léxicos (como en minúsculas) y las características gramaticales (como parte de la oración).

    Dependencia de análisis de uso de SPACY

    Dependencia de análisis es el proceso de extracción de la dependencia de análisis sintáctico de una oración para representar su estructura gramatical. Se define la relación de dependencia entre palabras claves y su los dependientes . El jefe de una sentencia no tiene ninguna dependencia y se llama la raíz de la sentencia . El verbo suele ser la cabeza de la frase. Todas las demás palabras están vinculados a la palabra principal.

    Las dependencias se pueden asignar en una representación en gráfico dirigido: Palabras

    • son los nodos.
    • Las relaciones gramaticales son los bordes.

    Dependencia de análisis ayuda a saber qué papel juega una palabra en el texto y lo diferente que las palabras se relacionan entre sí. También se usa en análisis sintáctico superficial y nombrada entidad reconocimiento.

    Así es como se puede utilizar análisis de dependencias para ver las relaciones entre las palabras:

    >>> piano_text = 'Gus is learning piano'
    >>> piano_doc = nlp(piano_text)
    >>> for token in piano_doc:
    ... print (token.text, token.tag_, token.head.text, token.dep_)
    ...
    Gus NNP learning nsubj
    is VBZ learning aux
    learning VBG learning ROOT
    piano NN learning dobj

    En este ejemplo, la frase contiene tres tipos de relaciones:

    Hay una lista detallada de las relaciones con las descripciones. Puede utilizar displaCy para visualizar el árbol de dependencias: Código

    >>> displacy.serve(piano_doc, style='dep')

    Esto producirá una visualización que se puede acceder mediante la apertura de http://127.0.0.1:5000 en su navegador:

    Esta imagen muestra que que el tema de la frase es el nombre propio Gus y que tiene una relación con aprender piano.

    Navegación por el árbol y el subárbol

    El árbol de dependencias de análisis tiene todas las propiedades de un árbol. Este árbol contiene información acerca de la estructura de oraciones y la gramática, y se puede recorrer en diferentes maneras de extraer las relaciones.

    SPACY proporciona atributos como los niños, izquierdas, derechos y sub-árbol para navegar por el árbol de análisis sintáctico:

    >>> one_line_about_text = ('Gus Proto is a Python developer'
    ... ' currently working for a London-based Fintech company')
    >>> one_line_about_doc = nlp(one_line_about_text)
    >>> # Extract children of `developer`
    >>> print([token.text for token in one_line_about_doc[5].children])
    ['a', 'Python', 'working']
    >>> # Extract previous neighboring node of `developer`
    >>> print (one_line_about_doc[5].nbor(-1))
    Python
    >>> # Extract next neighboring node of `developer`
    >>> print (one_line_about_doc[5].nbor())
    currently
    >>> # Extract all tokens on the left of `developer`
    >>> print([token.text for token in one_line_about_doc[5].lefts])
    ['a', 'Python']
    >>> # Extract tokens on the right of `developer`
    >>> print([token.text for token in one_line_about_doc[5].rights])
    ['working']
    >>> # Print subtree of `developer`
    >>> print (list(one_line_about_doc[5].subtree))
    [a, Python, developer, currently, working, for, a, London, -,
    based, Fintech, company]

    Es posible construir una función que toma un subárbol como argumento y devuelve una cadena mediante la fusión de las palabras en él:

    >>> def flatten_tree(tree):
    ... return ''.join([token.text_with_ws for token in list(tree)]).strip()
    ...
    >>> # Print flattened subtree of `developer`
    >>> print (flatten_tree(one_line_about_doc[5].subtree))
    a Python developer currently working for a London-based Fintech company

    Puede utilizar esta función para imprimir todas las fichas en un subárbol.

    superficial de análisis

    superficial análisis o fragmentación , es el proceso de extracción de frases de texto no estructurado. Fragmentar grupos fichas adyacentes en frases sobre la base de sus etiquetas POS. Hay algunos trozos convencionales bien conocidas frases tales como sustantivo, verbo frases y frases preposicionales.

    Noun Frase Detección

    Un sustantivo frase es una frase que tiene un sustantivo como su cabeza. También podría incluir otras clases de palabras, tales como adjetivos, determinantes, ordinales. frases nominales son útiles para explicar el contexto de la frase. Ellos le ayudan a inferir lo se está hablando en la frase.

    SPACY tiene las noun_chunks de propiedad en el objeto Doc. Se puede utilizar para extraer frases nominales:

    >>> conference_text = ('There is a developer conference'
    ... ' happening on 21 July 2019 in London.')
    >>> conference_doc = nlp(conference_text)
    >>> # Extract Noun Phrases
    >>> for chunk in conference_doc.noun_chunks:
    ... print (chunk)
    ...
    a developer conference
    21 July
    London

    Al observar las frases nominales, se puede obtener información acerca de su texto. Por ejemplo, una conferencia de desarrolladores indica que el texto menciona una conferencia, mientras que la Fecha 21 de julio de le permite saber que la conferencia está programada para el 21 de julio. Puede averiguar si la conferencia está en el pasado o en el futuro. Londres le dice que la conferencia está en Londres.

    frase verbal Detección

    A verbo frase es una unidad sintáctica compuesto de al menos un verbo. Este verbo puede ser seguido por otros trozos, como frases nominales. Verbo frases son útiles para la comprensión de las acciones que los sustantivos están involucrados en

    SPACY no se ha incorporado en la funcionalidad de extracto de verbo frases, por lo que tendrá una biblioteca llamada textacy:.

    Nota:

    Usted puede utilizar PIP instalar textacy:

    $ pip install textacy

    Ahora que ha instalado textacy, que se puede utilizar para extraer verbo frases sobre la base de reglas gramaticales:

    >>> import textacy
    >>> about_talk_text = ('The talk will introduce reader about Use'
    ... ' cases of Natural Language Processing in'
    ... ' Fintech')
    >>> pattern = r'(?*+)'
    >>> about_talk_doc = textacy.make_spacy_doc(about_talk_text,
    ... lang='en_core_web_sm')
    >>> verb_phrases = textacy.extract.pos_regex_matches(about_talk_doc, pattern)
    >>> # Print all Verb Phrase
    >>> for chunk in verb_phrases:
    ... print(chunk.text)
    ...
    will introduce
    >>> # Extract Noun Phrase to explain what nouns are involved
    >>> for chunk in about_talk_doc.noun_chunks:
    ... print (chunk)
    ...
    The talk
    reader
    Use cases
    Natural Language Processing
    Fintech

    en este ejemplo, la frase verbal introducir indica que algo va a ser introducido. Al observar las frases nominales, se puede ver que hay una charla que va a introducir al lector en los casos de uso del procesamiento del lenguaje natural o Fintech.

    El código anterior extrae todas las frases verbales utilizando un patrón de expresión regular de etiquetas POS. Se pueden ajustar el patrón de frases verbales, dependiendo de su caso de uso.

    Nota: En el ejemplo anterior, podría también haber hecho la dependencia de análisis para ver cuáles eran las relaciones entre las palabras.

    Nombrado Entidad Reconocimiento

    Nombrado Entidad Reconocimiento (NER) es el proceso de localización de entidades nombrados en texto estructurado y luego clasificándolos en categorías predefinidas, tales como nombres de personas, organizaciones, lugares, valores monetarios, porcentajes , expresiones de tiempo, y así sucesivamente.

    Puede utilizar NER saber más sobre el significado de su texto. Por ejemplo, se podría utilizar para rellenar las etiquetas de un conjunto de documentos con el fin de mejorar la búsqueda por palabra clave. También se podría utilizar para clasificar los tickets de soporte al cliente en categorías relevantes.

    SPACY tiene las entos de propiedad sobre los objetos Doc. Se puede utilizar para extraer entidades nombradas:

    >>> piano_class_text = ('Great Piano Academy is situated'
    ... ' in Mayfair or the City of London and has'
    ... ' world-class piano instructors.')
    >>> piano_class_doc = nlp(piano_class_text)
    >>> for ent in piano_class_doc.ents:
    ... print(ent.text, ent.start_char, ent.end_char,
    ... ent.label_, spacy.explain(ent.label_))
    ...
    Great Piano Academy 0 19 ORG Companies, agencies, institutions, etc.
    Mayfair 35 42 GPE Countries, cities, states
    the City of London 46 64 GPE Countries, cities, states

    En el ejemplo anterior, ent es un objeto Span con varios atributos: Texto

    • da la representación de texto Unicode de la entidad.
    • start_char denota el carácter de compensación para el inicio de la entidad.
    • end_char denota el carácter de compensación para el final de la entidad.
    • LABEL_ da la etiqueta de la entidad.

    da spacy.explain detalles descriptivos de una etiqueta de entidad. El modelo SPACY tiene una lista de pre-formados de las clases de entidad. Puede utilizar displaCy para visualizar estas entidades:

    >>> displacy.serve(piano_class_doc, style='ent')

    Si abre http://127.0.0.1:5000 en su navegador, a continuación se puede ver la visualización:

    puede utilizar NER nombres de las personas a redactar a partir de un texto. Por ejemplo, es posible que desee hacer esto con el fin de ocultar la información personal recopilada en una encuesta. Puede utilizar SPACY de hacer eso:

    >>> survey_text = ('Out of 5 people surveyed, James Robert,'
    ... ' Julie Fuller and Benjamin Brooks like'
    ... ' apples. Kelly Cox and Matthew Evans'
    ... ' like oranges.')
    ...
    >>> def replace_person_names(token):
    ... if token.ent_iob != 0 and token.ent_type_ == 'PERSON':
    ... return '[REDACTED] '
    ... return token.string
    ...
    >>> def redact_names(nlp_doc):
    ... for ent in nlp_doc.ents:
    ... ent.merge()
    ... tokens = map(replace_person_names, nlp_doc)
    ... return ''.join(tokens)
    ...
    >>> survey_doc = nlp(survey_text)
    >>> redact_names(survey_doc)
    'Out of 5 people surveyed, [REDACTED] , [REDACTED] and'
    ' [REDACTED] like apples. [REDACTED] and [REDACTED]'
    ' like oranges.'

    En este ejemplo, replace_person_names () utiliza ent_iob. Se da el código IOB de la etiqueta de entidad con nombre mediante el etiquetado dentro-fuera-de comenzar (IOB). En este caso, puede tener un valor distinto de cero, debido a cero significa que no hay etiqueta de entidad está establecida.

    Conclusión

    SPACY es una biblioteca potente y avanzado que está ganando gran popularidad para aplicaciones de PNL debido a su velocidad, facilidad de uso, precisión y extensibilidad. ¡Felicidades! Ahora ya sabe:

    • Lo que los términos y conceptos fundamentales de la PNL son
    • Cómo poner en práctica esos conceptos en SPACY
    • Cómo personalizar y ampliar incorporado funcionalidades en SPACY
    • cómo llevar a cabo el análisis estadístico básico en un texto
    • Cómo crear un gasoducto para procesar texto no estructurado
    • Cómo analizar una frase y extraer conocimiento con sentido de ella
Categorías
Python

Decoradores de Python 101

 

Tabla de Contenidos

  • limpieza
  • Ejemplo 1: EE.UU. Congreso DatasetThe “Hola, mundo!” de pandas GroupByPandas GroupBy vs SQLHow pandas GroupBy Obras
  • El “Hola, mundo!” de pandas GroupBy
  • pandas GroupBy vs SQL
  • Cómo pandas GroupBy Obras
  • Ejemplo 2: Calidad del aire en DatasetGrouping Derivado ArraysResampling
  • Agrupación de matrices Derivado
  • remuestreo
  • Ejemplo 3: Funciones agregador de noticias DatasetUsing Lambda en .groupby () Mejora del rendimiento del .groupby ()
  • Uso de las funciones Lambda en .groupby ()
  • mejorar el rendimiento de .groupby ()
  • pandas GroupBy: Poniendo todo junto
  • Conclusión
  • Más Recursos de pandas GroupBy
    El

  • “Hola, mundo!” de pandas GroupBy
  • pandas GroupBy vs SQL
  • Cómo pandas GroupBy Obras
  • Agrupación de matrices Derivado
  • remuestreo
  • Uso de las funciones Lambda en .groupby ()
  • mejorar el rendimiento de .groupby ()

Tanto si acabas de empezar a trabajar con las pandas y desea un maestro de sus instalaciones centrales, o usted está mirando para llenar algunas lagunas en su comprensión acerca de .groupby (), este tutorial le ayudará a romper hacia abajo y visualizar una operación pandas GroupBy de principio a fin.

Este tutorial está destinado a complementar la documentación oficial, donde puedes encontrar ejemplos, tamaño de un bocado autónomos. Aquí, sin embargo, usted se centran en tres paseos virtuales más complicados que utilizan conjuntos de datos del mundo real.

En este tutorial, usted cubrirá:

  • Cómo utilizar las operaciones de pandas GroupBy en los datos del mundo real
  • Cómo aplicar la escisión-combinar la cadena de operaciones funciona
  • cómo descomponer la fracción de apply- combinar la cadena en pasos
  • cómo los métodos de un objeto pandas GroupBy se pueden colocar en diferentes categorías en función de su intención y el resultado

Este tutorial asume que tienes alguna experiencia con ella misma pandas, incluyendo cómo leer archivos CSV en la memoria como objetos pandas con read_csv (). Si usted necesita un repaso, a continuación, echa un vistazo a la lectura CSVs Con pandas.

Puede descargar el código fuente de todos los ejemplos de este tutorial haciendo clic en el siguiente enlace:

descargar conjuntos de datos: Haga clic aquí para descargar los conjuntos de datos que utilizará para aprender acerca de las pandas’ GroupBy en este tutorial.

limpieza

Todo el código en este tutorial fue generada en un 3.7.2 shell CPython usando pandas 0.25.0. Antes de continuar, asegúrese de que usted tiene la última versión de pandas disponibles dentro de un nuevo entorno virtual:

$ python -m venv pandas-gb-tut
$ source ./pandas-gb-tut/bin/activate
$ python -m pip install pandas

Los ejemplos aquí también utilizan algunas opciones pandas pellizcadas para la salida amigable:

import pandas as pd

# Use 3 decimal places in output display
pd.set_option("display.precision", 3)

# Don't wrap repr(DataFrame) across additional lines
pd.set_option("display.expand_frame_repr", False)

# Set max rows displayed in output to 25
pd.set_option("display.max_rows", 25)

Usted puede añadir estos a un archivo de inicio de establecer de forma automática cada vez que se arranca el intérprete.

En este tutorial, se centran en tres conjuntos de datos:

Usted puede descargar el código fuente de todos los ejemplos de este tutorial haciendo clic en el siguiente enlace:

descargar conjuntos de datos: Haga clic aquí para descargar los conjuntos de datos que ‘ll utilizar para conocer las pandas’ GroupBy en este tutorial.

Una vez que haya descargado el .zip, puede descomprimirlo en el directorio actual:

$ unzip -q -d groupby-data groupby-data.zip

La opción -d le permite extraer el contenido a una nueva carpeta:

./

└── groupby-data/

├── legislators-historical.csv
├── airqual.csv
└── news.csv

Con que vayan a crear, ya está listo para ¡saltar!

Ejemplo 1: Congreso EE.UU. conjunto de datos

Vas a entrar de lleno en las cosas mediante la disección de un conjunto de datos históricos de los miembros del Congreso. Usted puede leer el archivo CSV en un pandas trama de datos con read_csv ():

import pandas as pd

dtypes = {
"first_name": "category",
"gender": "category",
"type": "category",
"state": "category",
"party": "category",
}
df = pd.read_csv(
"groupby-data/legislators-historical.csv",
dtype=dtypes,
usecols=list(dtypes) + ["birthday", "last_name"],
parse_dates=["birthday"]
)

El conjunto de datos contiene el nombre y apellido, fecha de nacimiento, sexo, tipo ( ‘representante’ para la Cámara de Representantes o ‘sen’ para el Senado) de los miembros, estado de Estados Unidos, y el partido político. Puede utilizar df.tail () para competir las últimas hileras del conjunto de datos:

>>> df.tail()
last_name first_name birthday gender type state party
11970 Garrett Thomas 1972-03-27 M rep VA Republican
11971 Handel Karen 1962-04-18 F rep GA Republican
11972 Jones Brenda 1959-10-24 F rep MI Democrat
11973 Marino Tom 1952-08-15 M rep PA Republican
11974 Jones Walter 1943-02-10 M rep NC Republican

La trama de datos utiliza categórica dtypes para la eficiencia del espacio:

>>> df.dtypes
last_name object
first_name category
birthday datetime64[ns]
gender category
type category
state category
party category
dtype: object

se puede ver que la mayoría de las columnas del conjunto de datos tienen la categoría de tipo, que reduce la carga de memoria en su máquina.

El “Hola, mundo!” de pandas GroupBy

Ahora que usted está familiarizado con el conjunto de datos, usted comenzará con un “Hola, Mundo!” para la operación de las pandas GroupBy. ¿Cuál es el recuento de los miembros del Congreso, sobre una base de estado por estado, en toda la historia del conjunto de datos? En SQL, se puede encontrar esta respuesta con una instrucción SELECT:

SELECT state, count(name)
FROM df
GROUP BY state
ORDER BY state;

Aquí está la casi equivalente en pandas:

>>> n_by_state = df.groupby("state")["last_name"].count()
>>> n_by_state.head(10)
state
AK 16
AL 206
AR 117
AS 2
AZ 48
CA 361
CO 90
CT 240
DC 2
DE 97
Name: last_name, dtype: int64

usted llama .groupby () y pasar el nombre de la columna que desea agrupar, que es el «estado «. A continuación, utilice [ «apellidos»] para especificar las columnas sobre las que se desea realizar la agregación real.

Puede pasar mucho más que un solo nombre de columna a .groupby () como primer argumento. También puede especificar cualquiera de los siguientes:

  • una lista de varios nombres de columna
  • un diccionario o matriz serie pandas
  • Un NumPy o el índice de pandas, o un array como iterable de éstos

Aquí está un ejemplo de agrupación conjuntamente en dos columnas, que encuentra la cuenta de los miembros del Congreso desglosados ​​por estado y luego por género:

>>> df.groupby(["state", "gender"])["last_name"].count()
state gender
AK M 16
AL F 3
M 203
AR F 5
M 112
...
WI M 196
WV F 1
M 119
WY F 2
M 38
Name: last_name, Length: 104, dtype: int64

la consulta SQL análoga se vería así:

SELECT state, gender, count(name)
FROM df
GROUP BY state, gender
ORDER BY state, gender;

como se verá a continuación, .groupby () y el comparables sentencias SQL son primos cercanos, pero a menudo no son funcionalmente idénticos.

Nota : Hay una diferencia más pequeña en la comparación de las pandas GroupBy vs SQL aquí: en la versión pandas, algunos estados sólo muestran uno de los géneros. Durante el desarrollo de este tutorial, nos encontramos con un pequeño pero complicado fallo en la fuente de pandas que no maneja el parámetro observado bien con ciertos tipos de datos. ¡Nunca temas! Hay algunas soluciones en este caso particular.

pandas GroupBy vs SQL

Este es un buen momento para introducir una diferencia importante entre la operación de pandas GroupBy y la consulta SQL anterior. El conjunto de resultados de la consulta SQL contiene tres columnas:

En la versión pandas, las luces agrupadas, en columnas son empujados a la MultiIndex de la serie resultante por defecto:

>>> n_by_state_gender = df.groupby(["state", "gender"])["last_name"].count()
>>> type(n_by_state_gender)

>>> n_by_state_gender.index[:5]
MultiIndex([('AK', 'M'),
('AL', 'F'),
('AL', 'M'),
('AR', 'F'),
('AR', 'M')],
names=['state', 'gender'])

para emular más de cerca el resultado de SQL y empuje el grouped- en las columnas de nuevo en columnas en el resultado, un as_index uso = False:

>>> df.groupby(["state", "gender"], as_index=False)["last_name"].count()
state gender last_name
0 AK F NaN
1 AK M 16.0
2 AL F 3.0
3 AL M 203.0
4 AR F 5.0
.. ... ... ...
111 WI M 196.0
112 WV F 1.0
113 WV M 119.0
114 WY F 2.0
115 WY M 38.0

[116 rows x 3 columns]

Esto produce una trama de datos con tres columnas y un RangeIndex, en lugar de una serie con un MultiIndex. En resumen, el uso de as_index = False hará que su resultado más estrechamente imitan la salida de SQL por defecto para una operación similar.

Nota : En df.groupby ([ «Estado», «género»]) [ «apellidos»] count (), también se puede utilizar .size () en lugar de .count (), ya lo sabes. no hay apellidos NaN. Usando .count () excluye valores NaN, mientras .size () incluye todo, NaN o no.

nota también de que las consultas SQL anterior utilizan explícitamente ORDER BY, mientras que .groupby () no lo hace. Esto se debe a .groupby () hace esto por defecto a través de su parámetro de clasificación, lo cual es cierto a menos que usted le indique lo contrario:

>>> # Don't sort results by the sort keys
>>> df.groupby("state", sort=False)["last_name"].count()
state
DE 97
VA 432
SC 251
MD 305
PA 1053
...
AK 16
PI 13
VI 4
GU 4
AS 2
Name: last_name, Length: 58, dtype: int64

A continuación, deberá sumergirse en el objeto que .groupby () produce realmente.

Cómo pandas GroupBy Obras

Antes de llegar más lejos en los detalles, tome un paso atrás para mirar a .groupby () sí:

>>> by_state = df.groupby("state")
>>> print(by_state)

¿Qué es esa cosa DataFrameGroupBy? Su .__ __ str () no le da mucha información sobre lo que realmente es o cómo funciona. La razón de que un objeto DataFrameGroupBy puede ser difícil de envolver su cabeza alrededor es que es perezosa en la naturaleza. En realidad, no hacer ninguna operación para producir un resultado útil hasta que usted lo dice.

Un término que se utiliza con frecuencia junto .groupby () es split-apply-combinan . Esto se refiere a una cadena de tres pasos:

Puede ser difícil para inspeccionar df.groupby ( «Estado»), ya que hace prácticamente ninguna de estas cosas hasta que haga algo con el objeto resultante. Una vez más, un objeto de pandas GroupBy es perezoso. Retrasa virtualmente cada parte del proceso a aplicar-se combinan dividida hasta que invocar un método en él.

Así que, ¿cómo se puede separar mentalmente la división, aplicar y combinar etapas si no puede ver cualquiera de ellos ocurre en el aislamiento? Una forma útil para inspeccionar un objeto pandas GroupBy y ver la división en acción es iterar sobre ella. Esto se implementa en DataFrameGroupBy .__ iter __ () y produce un iterador de ( grupo trama de datos) pares de tramas de datos:

>>> for state, frame in by_state:
... print(f"First 2 entries for {state!r}")
... print("------------------------")
... print(frame.head(2), end="\n\n")
...
First 2 entries for 'AK'
------------------------
last_name first_name birthday gender type state party
6619 Waskey Frank 1875-04-20 M rep AK Democrat
6647 Cale Thomas 1848-09-17 M rep AK Independent

First 2 entries for 'AL'
------------------------
last_name first_name birthday gender type state party
912 Crowell John 1780-09-18 M rep AL Republican
991 Walker John 1783-08-12 M sen AL Republican

Si está trabajando en un problema de agregación desafiante, a continuación, iterar sobre el objeto pandas GroupBy puede ser una gran manera de visualizar la divide parte de divide -Aplicar-combinan.

Hay algunos otros métodos y propiedades que permiten que usted mira en los grupos individuales y sus divisiones. El atributo .Grupos le dará un diccionario de {nombre del grupo: grupo de etiquetas} pares. Por ejemplo, by_state es un diccionario con los estados como llaves. Aquí está el valor de la clave «PA»:

>>> by_state.groups["PA"]
Int64Index([ 4, 19, 21, 27, 38, 57, 69, 76, 84,
88,
...
11842, 11866, 11875, 11877, 11887, 11891, 11932, 11945, 11959,
11973],
dtype='int64', length=1053)

Cada valor es una secuencia de los lugares de índice para las filas que pertenecen a ese grupo en particular. En la salida anterior, 4 , 19 , y 21 son los primeros índices en df en el que el estado es igual a “PA”.

También puede utilizar .get_group () como una forma de profundizar en la sub-tabla a partir de un solo grupo:

>>> by_state.get_group("PA")
last_name first_name birthday gender type state party
4 Clymer George 1739-03-16 M rep PA NaN
19 Maclay William 1737-07-20 M sen PA Anti-Administration
21 Morris Robert 1734-01-20 M sen PA Pro-Administration
27 Wynkoop Henry 1737-03-02 M rep PA NaN
38 Jacobs Israel 1726-06-09 M rep PA NaN
... ... ... ... ... ... ... ...
11891 Brady Robert 1945-04-07 M rep PA Democrat
11932 Shuster Bill 1961-01-10 M rep PA Republican
11945 Rothfus Keith 1962-04-25 M rep PA Republican
11959 Costello Ryan 1976-09-07 M rep PA Republican
11973 Marino Tom 1952-08-15 M rep PA Republican

Esto es prácticamente equivalente a usar .loc []. Usted podría conseguir el mismo resultado con algo como df.loc [df [ «estado»] == «PA»].

Nota : Yo uso el término genérico objeto pandas GroupBy para referirse tanto a un objeto o un objeto DataFrameGroupBy SeriesGroupBy, que tienen una gran cantidad de puntos en común entre ellos. También vale la pena mencionar de

Es que .groupby () hace hacer alguna , pero no todos, de los trabajos de división mediante la creación de una instancia de clase de agrupación para cada tecla que se pasa. Sin embargo, muchos de los métodos de la clase BaseGrouper que mantiene estas agrupaciones son llamados con pereza en lugar de en __init __ (), y muchos utilizan un diseño de la propiedad en caché.

A continuación, ¿qué pasa con la aplica parte? Se puede pensar en este paso del proceso, se aplica ing la misma operación (o exigible) para cada “sub-tabla” que se produce por la etapa de división. (No sé si “sub-tabla” es el término técnico, pero no he encontrado uno mejor ♂️)

Desde el objeto by_state pandas GroupBy, se puede agarrar el estado inicial de Estados Unidos y con la trama de datos próxima (). Al iterar sobre un objeto pandas GroupBy, obtendrá pares que se puede descomprimir en dos variables:

>>> state, frame = next(iter(by_state)) # First tuple from iterator
>>> state
'AK'
>>> frame.head(3)
last_name first_name birthday gender type state party
6619 Waskey Frank 1875-04-20 M rep AK Democrat
6647 Cale Thomas 1848-09-17 M rep AK Independent
7442 Grigsby George 1874-12-02 M rep AK NaN

Ahora, piense de nuevo a su original, la operación completa:

>>> df.groupby("state")["last_name"].count()
state
AK 16
AL 206
AR 117
AS 2
AZ 48
...

El aplicar etapa , cuando se aplica a un solo , con subjuegos trama de datos, se vería así:

>>> frame["last_name"].count() # Count for state == 'AK'
16

Se puede ver que el resultado, 16, coincide con el valor de AK en el resultado combinado.

El último paso, combinan , es el más fáciles de entender. Simplemente toma los resultados de todas las operaciones que apliquen en todas las sub-tablas y combinan s de nuevo juntos de una manera intuitiva.

Ejemplo 2: Calidad del Aire de conjunto de datos

El conjunto de datos de calidad del aire contiene lecturas por hora a partir de un dispositivo sensor de gas en Italia. Los valores perdidos se denotan con -200 en el archivo CSV. Puede utilizar read_csv () para combinar dos columnas en una marca de tiempo mientras se utiliza un subconjunto de las otras columnas:

import pandas as pd

df = pd.read_csv(
"groupby-data/airqual.csv",
parse_dates=[["Date", "Time"]],
na_values=[-200],
usecols=["Date", "Time", "CO(GT)", "T", "RH", "AH"]
).rename(
columns={
"CO(GT)": "co",
"Date_Time": "tstamp",
"T": "temp_c",
"RH": "rel_hum",
"AH": "abs_hum",
}
).set_index("tstamp")

Esto produce una trama de datos con un DatetimeIndex y cuatro columnas de flotación:

>>> df.head()
co temp_c rel_hum abs_hum
tstamp
2004-03-10 18:00:00 2.6 13.6 48.9 0.758
2004-03-10 19:00:00 2.0 13.3 47.7 0.726
2004-03-10 20:00:00 2.2 11.9 54.0 0.750
2004-03-10 21:00:00 2.2 11.0 60.0 0.787
2004-03-10 22:00:00 1.6 11.2 59.6 0.789

Aquí, co es una lectura promedio de monóxido de carbono de esa hora , mientras temp_c, rel_hum, y abs_hum son la temperatura media en grados Celsius, humedad relativa, y la humedad absoluta sobre esa hora, respectivamente. Las observaciones correr a partir de marzo de 2004 hasta Abril de 2005:

>>> df.index.min()
Timestamp('2004-03-10 18:00:00')
>>> df.index.max()
Timestamp('2005-04-04 14:00:00')

Hasta ahora, usted ha agrupados en columnas especificando sus nombres como str, como df.groupby ( «Estado»). Pero .groupby () es mucho más flexible que esto! Verá cómo siguiente.

Agrupación de matrices Derivado

Anteriormente se vio que el primer parámetro a .groupby () puede aceptar varios argumentos diferentes: la columna

  • A o lista de columnas
  • un diccionario o matriz serie pandas
  • Un NumPy o el índice de pandas , o una matriz similar a iterable de éstos

Usted puede tomar ventaja de la última opción para agrupar por el día de la semana. Puede utilizar .day_name del índice () para producir un índice de pandas de cadenas. Aquí están las diez primeras observaciones:

>>> day_names = df.index.day_name()
>>> type(day_names)

>>> day_names[:10]
Index(['Wednesday', 'Wednesday', 'Wednesday', 'Wednesday', 'Wednesday',
'Wednesday', 'Thursday', 'Thursday', 'Thursday', 'Thursday'],
dtype='object', name='tstamp')

A continuación, puede tomar este objeto y utilizarlo como la clave .groupby (). En pandas-hablar, day_names es array-como . Es una secuencia unidimensional de etiquetas.

Nota : Para una serie pandas, en lugar de un índice, necesitará el descriptor de acceso .dt para obtener acceso a métodos como .day_name (). Si Ser es tu serie, entonces se necesitaría ser.dt.day_name ().

Ahora, pasar ese objeto para .groupby () para encontrar el monóxido de carbono promedio () co) lectura por día de la semana:

>>> df.groupby(day_names)["co"].mean()
tstamp
Friday 2.543
Monday 2.017
Saturday 1.861
Sunday 1.438
Thursday 2.456
Tuesday 2.382
Wednesday 2.401
Name: co, dtype: float64

La fracción de aplicar-se comporta combinar procesos en gran medida el mismo que antes, excepto que el desdoblamiento esta vez se hace sobre una columna creada artificialmente. Esta columna no existe en la propia trama de datos, sino más bien se deriva de ella.

Lo que si se quería grupo no sólo por los días de la semana, sino por la hora del día? Ese resultado debería tener 7 * 24 = 168 observaciones. Para lograr esto, puede pasar una lista de objetos de matriz similar. En este caso, pasará pandas Int64Index objetos:

>>> hr = df.index.hour
>>> df.groupby([day_names, hr])["co"].mean().rename_axis(["dow", "hr"])
dow hr
Friday 0 1.936
1 1.609
2 1.172
3 0.887
4 0.823
...
Wednesday 19 4.147
20 3.845
21 2.898
22 2.102
23 1.938
Name: co, Length: 168, dtype: float64

Aquí está uno de los casos más similares que los usos .cut () a bin los valores de temperatura en intervalos discretos:

>>> bins = pd.cut(df["temp_c"], bins=3, labels=("cool", "warm", "hot"))
>>> df[["rel_hum", "abs_hum"]].groupby(bins).agg(["mean", "median"])
rel_hum abs_hum
mean median mean median
temp_c
cool 57.651 59.2 0.666 0.658
warm 49.383 49.3 1.183 1.145
hot 24.994 24.1 1.293 1.274

En este caso, los contenedores es en realidad una Serie:

>>> type(bins)

>>> bins.head()
tstamp
2004-03-10 18:00:00 cool
2004-03-10 19:00:00 cool
2004-03-10 20:00:00 cool
2004-03-10 21:00:00 cool
2004-03-10 22:00:00 cool
Name: temp_c, dtype: category
Categories (3, object): [cool < warm < hot]

Ya se trate de una matriz serie, NumPy o lista no importa. Lo que es importante es que los contenedores todavía sirve como una secuencia de etiquetas, una de fría, caliente o caliente. Si realmente quería, entonces también se podría utilizar una matriz categórica o incluso una lista simple de edad: Lista

  • nativo Python: df.groupby (bins.tolist ())
  • pandas categóricas matriz: df.groupby (contenedores .values)

Como se puede ver, .groupby () es inteligente y puede manejar una gran cantidad de diferentes tipos de entrada. Cualquiera de estos sería producir el mismo resultado porque todos ellos funcionan como una secuencia de etiquetas en el que realizar la agrupación y división.

remuestreo

vez agrupados df por el día de la semana con df.groupby (day_names) [ "co"]. Media (). Consideremos ahora algo diferente. ¿Y si quisiera agrupar por año y trimestre de una observación? He aquí una manera de lograr eso:

>>> # See an easier alternative below
>>> df.groupby([df.index.year, df.index.quarter])["co"].agg(
... ["max", "min"]
... ).rename_axis(["year", "quarter"])
max min
year quarter
2004 1 8.1 0.3
2 7.3 0.1
3 7.5 0.1
4 11.9 0.1
2005 1 8.7 0.1
2 5.0 0.3

Toda esta operación puede, alternativamente, ser expresada a través remuestreo . Uno de los usos de remuestreo es como GroupBy basado en el tiempo. Todo lo que necesita hacer es pasar una cadena de frecuencia, tales como "Q" de "trimestral", y pandas hará el resto:

>>> df.resample("Q")["co"].agg(["max", "min"])
max min
tstamp
2004-03-31 8.1 0.3
2004-06-30 7.3 0.1
2004-09-30 7.5 0.1
2004-12-31 11.9 0.1
2005-03-31 8.7 0.1
2005-06-30 5.0 0.3

A menudo, cuando se utiliza .resample () se puede expresar operaciones basadas en el tiempo en la agrupación de manera mucho más sucinta. El resultado puede ser un poco diferente pequeña que la más prolija .groupby () equivalente, pero a menudo encontrará que .resample () le da exactamente lo que estás buscando.

Ejemplo 3: agregador de noticias del conjunto de datos

Ahora se va a trabajar con el tercer y último conjunto de datos, que contiene los metadatos de varios cientos de miles de artículos de prensa y los agrupa en grupos de temas:

import datetime as dt
import pandas as pd

def parse_millisecond_timestamp(ts: int) -> dt.datetime:
"""Convert ms since Unix epoch to UTC datetime instance."""
return dt.datetime.fromtimestamp(ts / 1000, tz=dt.timezone.utc)

df = pd.read_csv(
"groupby-data
ews.csv",
sep="\t",
header=None,
index_col=0,
names=["title", "url", "outlet", "category", "cluster", "host", "tstamp"],
parse_dates=["tstamp"],
date_parser=parse_millisecond_timestamp,
dtype={
"outlet": "category",
"category": "category",
"cluster": "category",
"host": "category",
},
)

Para leer en la memoria con los dyptes adecuados , necesita una función de ayuda para analizar la columna de marca de tiempo. Esto es porque se expresa como el número de milisegundos desde la época Unix, en lugar de fracciones de segundo, que es la convención. Similar a lo que lo hacía antes, se puede utilizar el dtype categóricos para codificar eficientemente columnas que tienen un número relativamente pequeño de valores únicos en relación con la longitud de la columna.

Cada fila del conjunto de datos contiene el título, URL, nombre de la publicación de toma de corriente y de dominio, así como la fecha y hora de publicación. clúster es un ID aleatorio para el clúster tema al que pertenece un artículo. categoría es la categoría de noticias y contiene las siguientes opciones:

  • b por negocios
  • t para la ciencia y la tecnología
  • correo para el entretenimiento
  • m de la salud

He aquí la primera fila:

>>> df.iloc[0]
title Fed official says wea...
url http://www.latimes.co...
outlet Los Angeles Times
category b
cluster ddUyU0VZz0BRneMioxUPQ...
host www.latimes.com
tstamp 2014-03-10 16:52:50.6...
Name: 1, dtype: object

Ahora que ha tenía una visión de los datos, se puede empezar a hacer preguntas más complejas sobre ella.

Uso de las funciones Lambda en .groupby ()

invita este conjunto de datos mucho más potencialmente cuestiones involucradas. Voy a tirar al azar pero significativo por ahí: lo que los enchufes hablar más acerca de la Reserva Federal? Supongamos por simplicidad que esto conlleva en busca de mayúsculas y minúsculas menciones de "Fed". Tenga en cuenta que esto puede generar algunos falsos positivos con términos como “Gobierno Federal”. Para recuento

menciona por su salida, puede llamar .groupby () en la salida, y luego literalmente .apply () una función en cada grupo: la ruptura de

>>> df.groupby("outlet", sort=False)["title"].apply(
... lambda ser: ser.str.contains("Fed").sum()
... ).nlargest(10)
outlet
Reuters 161
NASDAQ 103
Businessweek 93
Investing.com 66
Wall Street Journal \(blog\) 61
MarketWatch 56
Moneynews 55
Bloomberg 53
GlobalPost 51
Economic Times 44
Name: title, dtype: int64

dejar que esta abajo, ya que hay varias llamadas a métodos realizados en sucesión. Al igual que antes, se puede sacar el primer grupo y su correspondiente objeto pandas tomando la primera tupla de los pandas GroupBy iterador:

>>> title, ser = next(iter(df.groupby("outlet", sort=False)["title"]))
>>> title
'Los Angeles Times'
>>> ser.head()
1 Fed official says weak data caused by weather,...
486 Stocks fall on discouraging news from Asia
1124 Clues to Genghis Khan's rise, written in the r...
1146 Elephants distinguish human voices by sex, age...
1237 Honda splits Acura into its own division to re...
Name: title, dtype: object

En este caso, ser una serie pandas en lugar de una trama de datos. Esto se debe a que siguió a la llamada .groupby () con [ "título"]. Esto selecciona eficazmente que una sola columna de cada sub-tabla.

Luego viene .str.contains ( "Fed"). Esto devuelve una serie booleano que es verdadera cuando un título del artículo registra una coincidencia en la búsqueda. Efectivamente, la primera fila comienza con "funcionario de la Fed dice que los datos débiles causados ​​por el clima, ..." y se ilumina como verdadera:

>>> ser.str.contains("Fed")
1 True
486 False
1124 False
1146 False
1237 False
...
421547 False
421584 False
421972 False
422226 False
422905 False
Name: title, Length: 1976, dtype: bool

El siguiente paso es .sum () esta serie. Desde bool es técnicamente sólo un tipo especializado de int, puede sumar una serie de verdadero y falso del mismo modo que resumir una secuencia de 1 y 0:

>>> ser.str.contains("Fed").sum()
17

El resultado es el número de menciones de "Fed" por el Los Angeles Times en el conjunto de datos. La misma rutina se aplica para Reuters, NASDAQ, Business Week, y el resto del lote.

mejorar el rendimiento de .groupby () de retroceso

Vamos de nuevo a .groupby (...). Apply () para ver por qué este patrón puede ser subóptima. Para obtener alguna información de fondo, echa un vistazo a Cómo acelerar su pandas Proyectos. Lo que puede ocurrir con .apply () es que va a realizar con eficacia un bucle Python sobre cada grupo. Mientras que el .groupby (...). Aplicar () patrón puede proporcionar una cierta flexibilidad, que puede también inhiben pandas de usar de otro modo sus optimizaciones basadas en Cython.

Todo lo que quiere decir que cada vez que se encuentra pensando en el uso de .apply (), preguntarse si hay una manera de expresar la operación de una forma vectorizada. En ese caso, se puede aprovechar el hecho de que .groupby () acepta no sólo uno o más nombres de columna, pero también muchos gama-como las estructuras :

  • A 1-dimensional array NumPy
  • Una lista
  • una serie pandas o índice

también tenga en cuenta que .groupby () es un método de instancia válida para una serie, no sólo una trama de datos, de modo que pueda esencialmente inversa a la lógica de dividir. Con esto en mente, primero puede construir una serie de booleanos que indican si el título contiene "Fed":

>>> mentions_fed = df["title"].str.contains("Fed")
>>> type(mentions_fed)

Ahora, .groupby () es también un método de la serie, por lo que puede agrupar una serie en otra:

>>> import numpy as np
>>> mentions_fed.groupby(
... df["outlet"], sort=False
... ).sum().nlargest(10).astype(np.uintc)
outlet
Reuters 161
NASDAQ 103
Businessweek 93
Investing.com 66
Wall Street Journal \(blog\) 61
MarketWatch 56
Moneynews 55
Bloomberg 53
GlobalPost 51
Economic Times 44
Name: title, dtype: uint32

las dos series no tienen que ser las columnas de un mismo objeto trama de datos. Sólo tienen que ser de la misma forma:

>>> mentions_fed.shape
(422419,)
>>> df["outlet"].shape
(422419,)

Por último, se puede emitir el resultado de vuelta a un entero sin signo con np.uintc si usted está decidido a obtener el resultado más compacto posible. He aquí una comparación cabeza a cabeza de las dos versiones que producirán el mismo resultado:

# Version 1: using `.apply()`
df.groupby("outlet", sort=False)["title"].apply(
lambda ser: ser.str.contains("Fed").sum()
).nlargest(10)

# Version 2: using vectorization
mentions_fed.groupby(
df["outlet"], sort=False
).sum().nlargest(10).astype(np.uintc)

En mi portátil, Versión 1 toma 4.01 segundos, mientras que la versión 2 tarda sólo 292 milisegundos. Se trata de una impresionante diferencia 14x en tiempo de CPU para un par de cientos de miles de filas. Tenga en cuenta cómo dramática la diferencia se hace cuando el conjunto de datos crece a unos pocos millones de filas!

Nota : Este ejemplo esmaltes sobre algunos detalles en los datos en aras de la simplicidad. A saber, el término de búsqueda "Fed" también puede encontrar menciones de cosas como “Gobierno Federal”.

Series.str.contains () también toma una expresión regular compilada como un argumento si se desea conseguir la suposición y el uso de una expresión que implica una búsqueda negativa hacia delante.

También puede querer contar no sólo el número de menciones en bruto, pero la proporción de menciones en relación con todos los artículos que produce un medio de comunicación.

pandas GroupBy: Poniendo todo junto

Si llama dir () en un objeto pandas GroupBy, entonces usted verá suficientes métodos allí para hacer girar su cabeza! Puede ser difícil hacer un seguimiento de toda la funcionalidad de un objeto pandas GroupBy. Una forma de despejar la niebla es compartimentar los diferentes métodos en lo que hacen y cómo se comportan.

En términos generales, los métodos de una caída objeto pandas GroupBy en un puñado de categorías: métodos

agregación (también llamado métodos de reducción ) “Smush” muchos puntos de datos en una estadística agregada acerca de esos puntos de datos. Un ejemplo es tomar la suma, la media o mediana de 10 números, donde el resultado es un solo número. Filtrar métodos

vienen de nuevo a usted con un subconjunto de la trama de datos originales. Esto significa más comúnmente usando .Filter () para soltar grupos enteros basado en alguna estadística comparativa sobre ese grupo y su sub-tabla. También tiene sentido para incluir en esta definición un número de métodos que excluyen filas específicas de cada grupo. Los métodos de transformación

devuelven una trama de datos con la misma forma y los índices como el original, pero con diferentes valores. Con ambos métodos de agregación y el filtro, la trama de datos resultante será comúnmente ser más pequeña en tamaño que la trama de datos de entrada. Esto no es cierto de una transformación, que transforma los valores individuales a sí mismos, pero conserva la forma de la trama de datos originales. métodos

Meta están menos preocupados con el objeto original en el que se ha llamado .groupby (), y más enfocado en darle información de alto nivel, tales como el número de grupos e índices de esos grupos. métodos

Trazado imitan la API de planear para una serie pandas o trama de datos, pero normalmente romper la salida en múltiples subtramas.

La documentación oficial tiene su propia explicación de estas categorías. Son, en cierto grado, abierto a la interpretación, y esto divergen fuerza tutorial en formas leves en la clasificación de qué método se cae dónde.

Nota: También hay otra tabla separada en la documentación pandas con su propio sistema de clasificación. Recoger lo que funciona para usted y parece más intuitivo!

Puede echar un vistazo a un desglose más detallado de cada categoría y los diversos métodos de .groupby () que se incluyen en ellos:

métodos de agregación y Propiedades mostrar / ocultar métodos

agregación (también llamados métodos de reducción de ) “Smush” muchos puntos de datos en una estadística agregada sobre los puntos de datos. Un ejemplo es tomar la suma, la media o mediana de 10 números, donde el resultado es un solo número. Aquí están algunos métodos de agregación:

  • .agg ()
  • .aggregate ()
  • .all ()
  • .any ()
  • .apply ()
  • .corr ()
  • .corrwith ()
  • .count ()
  • .cov ()
  • .cumcount ()
  • .cummax ()
  • .cummin ()
  • .cumprod ()
  • .cumsum ()
  • • Describir ()
  • . idxmax ()
  • .idxmin ()
  • .mad ()
  • .max ()
  • .mean ()
  • .median ()
  • .min ()
  • .nunique ()
  • .prod ( )
  • .sem ()
  • .size ()
  • .skew ()
  • .std ()
  • .sum ()
  • .var ()

Filtro Métodos y propiedades Mostrar / Ocultar

métodos de filtro volver a usted con un subconjunto de la trama de datos originales. Esto significa más comúnmente usando .Filter () para soltar grupos enteros basado en alguna estadística comparativa sobre ese grupo y su sub-tabla. También tiene sentido para incluir en esta definición un número de métodos que excluyen filas específicas de cada grupo. Aquí están algunos métodos de filtro:

  • .Filter ()
  • .First ()
  • .head ()
  • .last ()
  • .nth ()
  • .tail ()
  • .take ()

métodos de transformación y propiedades mostrar / ocultar

los métodos de transformación devuelve una trama de datos con la misma forma y los índices como el original, pero con diferentes valores. Con ambos métodos de agregación y el filtro, la trama de datos resultante será comúnmente ser más pequeña en tamaño que la trama de datos de entrada. Esto no es cierto de una transformación, que transforma los valores individuales a sí mismos, pero conserva la forma de la trama de datos originales. Aquí están algunos métodos de transformadores:

  • .bfill ()
  • .diff ()
  • .ffill ()
  • .fillna ()
  • .pct_change ()
  • .quantile ()
  • .rank ()
  • .shift ()
  • .transform ()
  • .tshift ()

métodos Meta y Propiedades Mostrar / Ocultar métodos

Meta tienen menos que ver con el objeto original en el que se ha llamado .groupby (), y más centrado en darle información de alto nivel, tales como el número de grupos e índices de esos grupos. Éstos son algunos métodos meta:

  • .__ __ (iter)
  • .get_group ()
  • .Grupos
  • .indices
  • .ndim
  • .ngroup

Métodos Trazado ()

  • .ngroups
  • .dtypes
  • Mostrar / Ocultar métodos

    trazado imitan la API de planear para una serie pandas o trama de datos, pero normalmente rompen la salida en múltiples subtramas. Aquí están algunos métodos de trazado:

    • .hist ()
    • .ohlc ()
    • .boxplot ()
    • .PLOT ()

    Odds and Ends Mostrar / Ocultar

    Hay algunos métodos de pandas GroupBy objetos que no están muy bien en las categorías anteriores. Estos métodos generalmente producen un objeto intermedio que es no una trama de datos o serie. . Por ejemplo, df.groupby (...) rodando (...) produce un objeto RollingGroupby, que se puede métodos de agregación, el filtro o de transformación continuación de compra sobre: ​​

    • .expanding ()
    • .pipe ()
    • .resample ()
    • .rolling ()

    Conclusión

    en este tutorial, que ha cubierto un montón de tierra en .groupby) (, incluyendo su diseño, su API, y la forma de la cadena de métodos en conjunto para obtener los datos en una salida que se adapte a su propósito.

    Usted ha aprendido:

    • Cómo utilizar las operaciones de pandas GroupBy en los datos del mundo real
    • Cómo aplicar la escisión-combinar la cadena de obras de operaciones y cómo se puede descomponer en pasos
    • cómo los métodos de una pandas GroupBy se puede colocar en diferentes categorías en función de su intención y el resultado

    Hay mucho más a .groupby () que se puede cubrir en un tutorial. Echa un vistazo a los siguientes recursos y el uso de los conjuntos de datos de ejemplo aquí como un punto de partida para una exploración más profunda!

    Puede descargar el código fuente de todos los ejemplos de este tutorial haciendo clic en el siguiente enlace:

    descargar conjuntos de datos: Haga clic aquí para descargar los conjuntos de datos que utilizará para aprender acerca de las pandas' GroupBy en este tutorial.

    Más recursos sobre guías de documentación pandas GroupBy

    pandas son fáciles de usar paseos virtuales a diferentes aspectos de las pandas. Aquí hay algunas partes de la documentación que se pueden extraer para aprender más acerca de las pandas GroupBy:

    • las pandas GroupBy guía del usuario
    • La Agrupación libro de cocina

    La documentación de la API es una referencia técnica más completa de métodos y objetos:

    • DataFrame.groupby ()
    • DataFrame.resample ()
    • pandas.Grouper
    Categorías
    Python

    Aplicaciones Web con el frasco Python – Parte II

     

    Tabla de Contenidos

    • limpieza
    • Ejemplo 1: EE.UU. Congreso DatasetThe “Hola, mundo!” de pandas GroupByPandas GroupBy vs SQLHow pandas GroupBy Obras
    • El “Hola, mundo!” de pandas GroupBy
    • pandas GroupBy vs SQL
    • Cómo pandas GroupBy Obras
    • Ejemplo 2: Calidad del aire en DatasetGrouping Derivado ArraysResampling
    • Agrupación de matrices Derivado
    • remuestreo
    • Ejemplo 3: Funciones agregador de noticias DatasetUsing Lambda en .groupby () Mejora del rendimiento del .groupby ()
    • Uso de las funciones Lambda en .groupby ()
    • mejorar el rendimiento de .groupby ()
    • pandas GroupBy: Poniendo todo junto
    • Conclusión
    • Más Recursos de pandas GroupBy
      El

    • “Hola, mundo!” de pandas GroupBy
    • pandas GroupBy vs SQL
    • Cómo pandas GroupBy Obras
    • Agrupación de matrices Derivado
    • remuestreo
    • Uso de las funciones Lambda en .groupby ()
    • mejorar el rendimiento de .groupby ()

    Tanto si acabas de empezar a trabajar con las pandas y desea un maestro de sus instalaciones centrales, o usted está mirando para llenar algunas lagunas en su comprensión acerca de .groupby (), este tutorial le ayudará a romper hacia abajo y visualizar una operación pandas GroupBy de principio a fin.

    Este tutorial está destinado a complementar la documentación oficial, donde puedes encontrar ejemplos, tamaño de un bocado autónomos. Aquí, sin embargo, usted se centran en tres paseos virtuales más complicados que utilizan conjuntos de datos del mundo real.

    En este tutorial, usted cubrirá:

    • Cómo utilizar las operaciones de pandas GroupBy en los datos del mundo real
    • Cómo aplicar la escisión-combinar la cadena de operaciones funciona
    • cómo descomponer la fracción de apply- combinar la cadena en pasos
    • cómo los métodos de un objeto pandas GroupBy se pueden colocar en diferentes categorías en función de su intención y el resultado

    Este tutorial asume que tienes alguna experiencia con ella misma pandas, incluyendo cómo leer archivos CSV en la memoria como objetos pandas con read_csv (). Si usted necesita un repaso, a continuación, echa un vistazo a la lectura CSVs Con pandas.

    Puede descargar el código fuente de todos los ejemplos de este tutorial haciendo clic en el siguiente enlace:

    descargar conjuntos de datos: Haga clic aquí para descargar los conjuntos de datos que utilizará para aprender acerca de las pandas’ GroupBy en este tutorial.

    limpieza

    Todo el código en este tutorial fue generada en un 3.7.2 shell CPython usando pandas 0.25.0. Antes de continuar, asegúrese de que usted tiene la última versión de pandas disponibles dentro de un nuevo entorno virtual:

    $ python -m venv pandas-gb-tut
    $ source ./pandas-gb-tut/bin/activate
    $ python -m pip install pandas

    Los ejemplos aquí también utilizan algunas opciones pandas pellizcadas para la salida amigable:

    import pandas as pd

    # Use 3 decimal places in output display
    pd.set_option("display.precision", 3)

    # Don't wrap repr(DataFrame) across additional lines
    pd.set_option("display.expand_frame_repr", False)

    # Set max rows displayed in output to 25
    pd.set_option("display.max_rows", 25)

    Usted puede añadir estos a un archivo de inicio de establecer de forma automática cada vez que se arranca el intérprete.

    En este tutorial, se centran en tres conjuntos de datos:

    Usted puede descargar el código fuente de todos los ejemplos de este tutorial haciendo clic en el siguiente enlace:

    descargar conjuntos de datos: Haga clic aquí para descargar los conjuntos de datos que ‘ll utilizar para conocer las pandas’ GroupBy en este tutorial.

    Una vez que haya descargado el .zip, puede descomprimirlo en el directorio actual:

    $ unzip -q -d groupby-data groupby-data.zip

    La opción -d le permite extraer el contenido a una nueva carpeta:

    ./

    └── groupby-data/

    ├── legislators-historical.csv
    ├── airqual.csv
    └── news.csv

    Con que vayan a crear, ya está listo para ¡saltar!

    Ejemplo 1: Congreso EE.UU. conjunto de datos

    Vas a entrar de lleno en las cosas mediante la disección de un conjunto de datos históricos de los miembros del Congreso. Usted puede leer el archivo CSV en un pandas trama de datos con read_csv ():

    import pandas as pd

    dtypes = {
    "first_name": "category",
    "gender": "category",
    "type": "category",
    "state": "category",
    "party": "category",
    }
    df = pd.read_csv(
    "groupby-data/legislators-historical.csv",
    dtype=dtypes,
    usecols=list(dtypes) + ["birthday", "last_name"],
    parse_dates=["birthday"]
    )

    El conjunto de datos contiene el nombre y apellido, fecha de nacimiento, sexo, tipo ( ‘representante’ para la Cámara de Representantes o ‘sen’ para el Senado) de los miembros, estado de Estados Unidos, y el partido político. Puede utilizar df.tail () para competir las últimas hileras del conjunto de datos:

    >>> df.tail()
    last_name first_name birthday gender type state party
    11970 Garrett Thomas 1972-03-27 M rep VA Republican
    11971 Handel Karen 1962-04-18 F rep GA Republican
    11972 Jones Brenda 1959-10-24 F rep MI Democrat
    11973 Marino Tom 1952-08-15 M rep PA Republican
    11974 Jones Walter 1943-02-10 M rep NC Republican

    La trama de datos utiliza categórica dtypes para la eficiencia del espacio:

    >>> df.dtypes
    last_name object
    first_name category
    birthday datetime64[ns]
    gender category
    type category
    state category
    party category
    dtype: object

    se puede ver que la mayoría de las columnas del conjunto de datos tienen la categoría de tipo, que reduce la carga de memoria en su máquina.

    El “Hola, mundo!” de pandas GroupBy

    Ahora que usted está familiarizado con el conjunto de datos, usted comenzará con un “Hola, Mundo!” para la operación de las pandas GroupBy. ¿Cuál es el recuento de los miembros del Congreso, sobre una base de estado por estado, en toda la historia del conjunto de datos? En SQL, se puede encontrar esta respuesta con una instrucción SELECT:

    SELECT state, count(name)
    FROM df
    GROUP BY state
    ORDER BY state;

    Aquí está la casi equivalente en pandas:

    >>> n_by_state = df.groupby("state")["last_name"].count()
    >>> n_by_state.head(10)
    state
    AK 16
    AL 206
    AR 117
    AS 2
    AZ 48
    CA 361
    CO 90
    CT 240
    DC 2
    DE 97
    Name: last_name, dtype: int64

    usted llama .groupby () y pasar el nombre de la columna que desea agrupar, que es el «estado «. A continuación, utilice [ «apellidos»] para especificar las columnas sobre las que se desea realizar la agregación real.

    Puede pasar mucho más que un solo nombre de columna a .groupby () como primer argumento. También puede especificar cualquiera de los siguientes:

    • una lista de varios nombres de columna
    • un diccionario o matriz serie pandas
    • Un NumPy o el índice de pandas, o un array como iterable de éstos

    Aquí está un ejemplo de agrupación conjuntamente en dos columnas, que encuentra la cuenta de los miembros del Congreso desglosados ​​por estado y luego por género:

    >>> df.groupby(["state", "gender"])["last_name"].count()
    state gender
    AK M 16
    AL F 3
    M 203
    AR F 5
    M 112
    ...
    WI M 196
    WV F 1
    M 119
    WY F 2
    M 38
    Name: last_name, Length: 104, dtype: int64

    la consulta SQL análoga se vería así:

    SELECT state, gender, count(name)
    FROM df
    GROUP BY state, gender
    ORDER BY state, gender;

    como se verá a continuación, .groupby () y el comparables sentencias SQL son primos cercanos, pero a menudo no son funcionalmente idénticos.

    Nota : Hay una diferencia más pequeña en la comparación de las pandas GroupBy vs SQL aquí: en la versión pandas, algunos estados sólo muestran uno de los géneros. Durante el desarrollo de este tutorial, nos encontramos con un pequeño pero complicado fallo en la fuente de pandas que no maneja el parámetro observado bien con ciertos tipos de datos. ¡Nunca temas! Hay algunas soluciones en este caso particular.

    pandas GroupBy vs SQL

    Este es un buen momento para introducir una diferencia importante entre la operación de pandas GroupBy y la consulta SQL anterior. El conjunto de resultados de la consulta SQL contiene tres columnas:

    En la versión pandas, las luces agrupadas, en columnas son empujados a la MultiIndex de la serie resultante por defecto:

    >>> n_by_state_gender = df.groupby(["state", "gender"])["last_name"].count()
    >>> type(n_by_state_gender)

    >>> n_by_state_gender.index[:5]
    MultiIndex([('AK', 'M'),
    ('AL', 'F'),
    ('AL', 'M'),
    ('AR', 'F'),
    ('AR', 'M')],
    names=['state', 'gender'])

    para emular más de cerca el resultado de SQL y empuje el grouped- en las columnas de nuevo en columnas en el resultado, un as_index uso = False:

    >>> df.groupby(["state", "gender"], as_index=False)["last_name"].count()
    state gender last_name
    0 AK F NaN
    1 AK M 16.0
    2 AL F 3.0
    3 AL M 203.0
    4 AR F 5.0
    .. ... ... ...
    111 WI M 196.0
    112 WV F 1.0
    113 WV M 119.0
    114 WY F 2.0
    115 WY M 38.0

    [116 rows x 3 columns]

    Esto produce una trama de datos con tres columnas y un RangeIndex, en lugar de una serie con un MultiIndex. En resumen, el uso de as_index = False hará que su resultado más estrechamente imitan la salida de SQL por defecto para una operación similar.

    Nota : En df.groupby ([ «Estado», «género»]) [ «apellidos»] count (), también se puede utilizar .size () en lugar de .count (), ya lo sabes. no hay apellidos NaN. Usando .count () excluye valores NaN, mientras .size () incluye todo, NaN o no.

    nota también de que las consultas SQL anterior utilizan explícitamente ORDER BY, mientras que .groupby () no lo hace. Esto se debe a .groupby () hace esto por defecto a través de su parámetro de clasificación, lo cual es cierto a menos que usted le indique lo contrario:

    >>> # Don't sort results by the sort keys
    >>> df.groupby("state", sort=False)["last_name"].count()
    state
    DE 97
    VA 432
    SC 251
    MD 305
    PA 1053
    ...
    AK 16
    PI 13
    VI 4
    GU 4
    AS 2
    Name: last_name, Length: 58, dtype: int64

    A continuación, deberá sumergirse en el objeto que .groupby () produce realmente.

    Cómo pandas GroupBy Obras

    Antes de llegar más lejos en los detalles, tome un paso atrás para mirar a .groupby () sí:

    >>> by_state = df.groupby("state")
    >>> print(by_state)

    ¿Qué es esa cosa DataFrameGroupBy? Su .__ __ str () no le da mucha información sobre lo que realmente es o cómo funciona. La razón de que un objeto DataFrameGroupBy puede ser difícil de envolver su cabeza alrededor es que es perezosa en la naturaleza. En realidad, no hacer ninguna operación para producir un resultado útil hasta que usted lo dice.

    Un término que se utiliza con frecuencia junto .groupby () es split-apply-combinan . Esto se refiere a una cadena de tres pasos:

    Puede ser difícil para inspeccionar df.groupby ( «Estado»), ya que hace prácticamente ninguna de estas cosas hasta que haga algo con el objeto resultante. Una vez más, un objeto de pandas GroupBy es perezoso. Retrasa virtualmente cada parte del proceso a aplicar-se combinan dividida hasta que invocar un método en él.

    Así que, ¿cómo se puede separar mentalmente la división, aplicar y combinar etapas si no puede ver cualquiera de ellos ocurre en el aislamiento? Una forma útil para inspeccionar un objeto pandas GroupBy y ver la división en acción es iterar sobre ella. Esto se implementa en DataFrameGroupBy .__ iter __ () y produce un iterador de ( grupo trama de datos) pares de tramas de datos:

    >>> for state, frame in by_state:
    ... print(f"First 2 entries for {state!r}")
    ... print("------------------------")
    ... print(frame.head(2), end="\n\n")
    ...
    First 2 entries for 'AK'
    ------------------------
    last_name first_name birthday gender type state party
    6619 Waskey Frank 1875-04-20 M rep AK Democrat
    6647 Cale Thomas 1848-09-17 M rep AK Independent

    First 2 entries for 'AL'
    ------------------------
    last_name first_name birthday gender type state party
    912 Crowell John 1780-09-18 M rep AL Republican
    991 Walker John 1783-08-12 M sen AL Republican

    Si está trabajando en un problema de agregación desafiante, a continuación, iterar sobre el objeto pandas GroupBy puede ser una gran manera de visualizar la divide parte de divide -Aplicar-combinan.

    Hay algunos otros métodos y propiedades que permiten que usted mira en los grupos individuales y sus divisiones. El atributo .Grupos le dará un diccionario de {nombre del grupo: grupo de etiquetas} pares. Por ejemplo, by_state es un diccionario con los estados como llaves. Aquí está el valor de la clave «PA»:

    >>> by_state.groups["PA"]
    Int64Index([ 4, 19, 21, 27, 38, 57, 69, 76, 84,
    88,
    ...
    11842, 11866, 11875, 11877, 11887, 11891, 11932, 11945, 11959,
    11973],
    dtype='int64', length=1053)

    Cada valor es una secuencia de los lugares de índice para las filas que pertenecen a ese grupo en particular. En la salida anterior, 4 , 19 , y 21 son los primeros índices en df en el que el estado es igual a “PA”.

    También puede utilizar .get_group () como una forma de profundizar en la sub-tabla a partir de un solo grupo:

    >>> by_state.get_group("PA")
    last_name first_name birthday gender type state party
    4 Clymer George 1739-03-16 M rep PA NaN
    19 Maclay William 1737-07-20 M sen PA Anti-Administration
    21 Morris Robert 1734-01-20 M sen PA Pro-Administration
    27 Wynkoop Henry 1737-03-02 M rep PA NaN
    38 Jacobs Israel 1726-06-09 M rep PA NaN
    ... ... ... ... ... ... ... ...
    11891 Brady Robert 1945-04-07 M rep PA Democrat
    11932 Shuster Bill 1961-01-10 M rep PA Republican
    11945 Rothfus Keith 1962-04-25 M rep PA Republican
    11959 Costello Ryan 1976-09-07 M rep PA Republican
    11973 Marino Tom 1952-08-15 M rep PA Republican

    Esto es prácticamente equivalente a usar .loc []. Usted podría conseguir el mismo resultado con algo como df.loc [df [ «estado»] == «PA»].

    Nota : Yo uso el término genérico objeto pandas GroupBy para referirse tanto a un objeto o un objeto DataFrameGroupBy SeriesGroupBy, que tienen una gran cantidad de puntos en común entre ellos. También vale la pena mencionar de

    Es que .groupby () hace hacer alguna , pero no todos, de los trabajos de división mediante la creación de una instancia de clase de agrupación para cada tecla que se pasa. Sin embargo, muchos de los métodos de la clase BaseGrouper que mantiene estas agrupaciones son llamados con pereza en lugar de en __init __ (), y muchos utilizan un diseño de la propiedad en caché.

    A continuación, ¿qué pasa con la aplica parte? Se puede pensar en este paso del proceso, se aplica ing la misma operación (o exigible) para cada “sub-tabla” que se produce por la etapa de división. (No sé si “sub-tabla” es el término técnico, pero no he encontrado uno mejor ♂️)

    Desde el objeto by_state pandas GroupBy, se puede agarrar el estado inicial de Estados Unidos y con la trama de datos próxima (). Al iterar sobre un objeto pandas GroupBy, obtendrá pares que se puede descomprimir en dos variables:

    >>> state, frame = next(iter(by_state)) # First tuple from iterator
    >>> state
    'AK'
    >>> frame.head(3)
    last_name first_name birthday gender type state party
    6619 Waskey Frank 1875-04-20 M rep AK Democrat
    6647 Cale Thomas 1848-09-17 M rep AK Independent
    7442 Grigsby George 1874-12-02 M rep AK NaN

    Ahora, piense de nuevo a su original, la operación completa:

    >>> df.groupby("state")["last_name"].count()
    state
    AK 16
    AL 206
    AR 117
    AS 2
    AZ 48
    ...

    El aplicar etapa , cuando se aplica a un solo , con subjuegos trama de datos, se vería así:

    >>> frame["last_name"].count() # Count for state == 'AK'
    16

    Se puede ver que el resultado, 16, coincide con el valor de AK en el resultado combinado.

    El último paso, combinan , es el más fáciles de entender. Simplemente toma los resultados de todas las operaciones que apliquen en todas las sub-tablas y combinan s de nuevo juntos de una manera intuitiva.

    Ejemplo 2: Calidad del Aire de conjunto de datos

    El conjunto de datos de calidad del aire contiene lecturas por hora a partir de un dispositivo sensor de gas en Italia. Los valores perdidos se denotan con -200 en el archivo CSV. Puede utilizar read_csv () para combinar dos columnas en una marca de tiempo mientras se utiliza un subconjunto de las otras columnas:

    import pandas as pd

    df = pd.read_csv(
    "groupby-data/airqual.csv",
    parse_dates=[["Date", "Time"]],
    na_values=[-200],
    usecols=["Date", "Time", "CO(GT)", "T", "RH", "AH"]
    ).rename(
    columns={
    "CO(GT)": "co",
    "Date_Time": "tstamp",
    "T": "temp_c",
    "RH": "rel_hum",
    "AH": "abs_hum",
    }
    ).set_index("tstamp")

    Esto produce una trama de datos con un DatetimeIndex y cuatro columnas de flotación:

    >>> df.head()
    co temp_c rel_hum abs_hum
    tstamp
    2004-03-10 18:00:00 2.6 13.6 48.9 0.758
    2004-03-10 19:00:00 2.0 13.3 47.7 0.726
    2004-03-10 20:00:00 2.2 11.9 54.0 0.750
    2004-03-10 21:00:00 2.2 11.0 60.0 0.787
    2004-03-10 22:00:00 1.6 11.2 59.6 0.789

    Aquí, co es una lectura promedio de monóxido de carbono de esa hora , mientras temp_c, rel_hum, y abs_hum son la temperatura media en grados Celsius, humedad relativa, y la humedad absoluta sobre esa hora, respectivamente. Las observaciones correr a partir de marzo de 2004 hasta Abril de 2005:

    >>> df.index.min()
    Timestamp('2004-03-10 18:00:00')
    >>> df.index.max()
    Timestamp('2005-04-04 14:00:00')

    Hasta ahora, usted ha agrupados en columnas especificando sus nombres como str, como df.groupby ( «Estado»). Pero .groupby () es mucho más flexible que esto! Verá cómo siguiente.

    Agrupación de matrices Derivado

    Anteriormente se vio que el primer parámetro a .groupby () puede aceptar varios argumentos diferentes: la columna

    • A o lista de columnas
    • un diccionario o matriz serie pandas
    • Un NumPy o el índice de pandas , o una matriz similar a iterable de éstos

    Usted puede tomar ventaja de la última opción para agrupar por el día de la semana. Puede utilizar .day_name del índice () para producir un índice de pandas de cadenas. Aquí están las diez primeras observaciones:

    >>> day_names = df.index.day_name()
    >>> type(day_names)

    >>> day_names[:10]
    Index(['Wednesday', 'Wednesday', 'Wednesday', 'Wednesday', 'Wednesday',
    'Wednesday', 'Thursday', 'Thursday', 'Thursday', 'Thursday'],
    dtype='object', name='tstamp')

    A continuación, puede tomar este objeto y utilizarlo como la clave .groupby (). En pandas-hablar, day_names es array-como . Es una secuencia unidimensional de etiquetas.

    Nota : Para una serie pandas, en lugar de un índice, necesitará el descriptor de acceso .dt para obtener acceso a métodos como .day_name (). Si Ser es tu serie, entonces se necesitaría ser.dt.day_name ().

    Ahora, pasar ese objeto para .groupby () para encontrar el monóxido de carbono promedio () co) lectura por día de la semana:

    >>> df.groupby(day_names)["co"].mean()
    tstamp
    Friday 2.543
    Monday 2.017
    Saturday 1.861
    Sunday 1.438
    Thursday 2.456
    Tuesday 2.382
    Wednesday 2.401
    Name: co, dtype: float64

    La fracción de aplicar-se comporta combinar procesos en gran medida el mismo que antes, excepto que el desdoblamiento esta vez se hace sobre una columna creada artificialmente. Esta columna no existe en la propia trama de datos, sino más bien se deriva de ella.

    Lo que si se quería grupo no sólo por los días de la semana, sino por la hora del día? Ese resultado debería tener 7 * 24 = 168 observaciones. Para lograr esto, puede pasar una lista de objetos de matriz similar. En este caso, pasará pandas Int64Index objetos:

    >>> hr = df.index.hour
    >>> df.groupby([day_names, hr])["co"].mean().rename_axis(["dow", "hr"])
    dow hr
    Friday 0 1.936
    1 1.609
    2 1.172
    3 0.887
    4 0.823
    ...
    Wednesday 19 4.147
    20 3.845
    21 2.898
    22 2.102
    23 1.938
    Name: co, Length: 168, dtype: float64

    Aquí está uno de los casos más similares que los usos .cut () a bin los valores de temperatura en intervalos discretos:

    >>> bins = pd.cut(df["temp_c"], bins=3, labels=("cool", "warm", "hot"))
    >>> df[["rel_hum", "abs_hum"]].groupby(bins).agg(["mean", "median"])
    rel_hum abs_hum
    mean median mean median
    temp_c
    cool 57.651 59.2 0.666 0.658
    warm 49.383 49.3 1.183 1.145
    hot 24.994 24.1 1.293 1.274

    En este caso, los contenedores es en realidad una Serie:

    >>> type(bins)

    >>> bins.head()
    tstamp
    2004-03-10 18:00:00 cool
    2004-03-10 19:00:00 cool
    2004-03-10 20:00:00 cool
    2004-03-10 21:00:00 cool
    2004-03-10 22:00:00 cool
    Name: temp_c, dtype: category
    Categories (3, object): [cool < warm < hot]

    Ya se trate de una matriz serie, NumPy o lista no importa. Lo que es importante es que los contenedores todavía sirve como una secuencia de etiquetas, una de fría, caliente o caliente. Si realmente quería, entonces también se podría utilizar una matriz categórica o incluso una lista simple de edad: Lista

    • nativo Python: df.groupby (bins.tolist ())
    • pandas categóricas matriz: df.groupby (contenedores .values)

    Como se puede ver, .groupby () es inteligente y puede manejar una gran cantidad de diferentes tipos de entrada. Cualquiera de estos sería producir el mismo resultado porque todos ellos funcionan como una secuencia de etiquetas en el que realizar la agrupación y división.

    remuestreo

    vez agrupados df por el día de la semana con df.groupby (day_names) [ "co"]. Media (). Consideremos ahora algo diferente. ¿Y si quisiera agrupar por año y trimestre de una observación? He aquí una manera de lograr eso:

    >>> # See an easier alternative below
    >>> df.groupby([df.index.year, df.index.quarter])["co"].agg(
    ... ["max", "min"]
    ... ).rename_axis(["year", "quarter"])
    max min
    year quarter
    2004 1 8.1 0.3
    2 7.3 0.1
    3 7.5 0.1
    4 11.9 0.1
    2005 1 8.7 0.1
    2 5.0 0.3

    Toda esta operación puede, alternativamente, ser expresada a través remuestreo . Uno de los usos de remuestreo es como GroupBy basado en el tiempo. Todo lo que necesita hacer es pasar una cadena de frecuencia, tales como "Q" de "trimestral", y pandas hará el resto:

    >>> df.resample("Q")["co"].agg(["max", "min"])
    max min
    tstamp
    2004-03-31 8.1 0.3
    2004-06-30 7.3 0.1
    2004-09-30 7.5 0.1
    2004-12-31 11.9 0.1
    2005-03-31 8.7 0.1
    2005-06-30 5.0 0.3

    A menudo, cuando se utiliza .resample () se puede expresar operaciones basadas en el tiempo en la agrupación de manera mucho más sucinta. El resultado puede ser un poco diferente pequeña que la más prolija .groupby () equivalente, pero a menudo encontrará que .resample () le da exactamente lo que estás buscando.

    Ejemplo 3: agregador de noticias del conjunto de datos

    Ahora se va a trabajar con el tercer y último conjunto de datos, que contiene los metadatos de varios cientos de miles de artículos de prensa y los agrupa en grupos de temas:

    import datetime as dt
    import pandas as pd

    def parse_millisecond_timestamp(ts: int) -> dt.datetime:
    """Convert ms since Unix epoch to UTC datetime instance."""
    return dt.datetime.fromtimestamp(ts / 1000, tz=dt.timezone.utc)

    df = pd.read_csv(
    "groupby-data
    ews.csv",
    sep="\t",
    header=None,
    index_col=0,
    names=["title", "url", "outlet", "category", "cluster", "host", "tstamp"],
    parse_dates=["tstamp"],
    date_parser=parse_millisecond_timestamp,
    dtype={
    "outlet": "category",
    "category": "category",
    "cluster": "category",
    "host": "category",
    },
    )

    Para leer en la memoria con los dyptes adecuados , necesita una función de ayuda para analizar la columna de marca de tiempo. Esto es porque se expresa como el número de milisegundos desde la época Unix, en lugar de fracciones de segundo, que es la convención. Similar a lo que lo hacía antes, se puede utilizar el dtype categóricos para codificar eficientemente columnas que tienen un número relativamente pequeño de valores únicos en relación con la longitud de la columna.

    Cada fila del conjunto de datos contiene el título, URL, nombre de la publicación de toma de corriente y de dominio, así como la fecha y hora de publicación. clúster es un ID aleatorio para el clúster tema al que pertenece un artículo. categoría es la categoría de noticias y contiene las siguientes opciones:

    • b por negocios
    • t para la ciencia y la tecnología
    • correo para el entretenimiento
    • m de la salud

    He aquí la primera fila:

    >>> df.iloc[0]
    title Fed official says wea...
    url http://www.latimes.co...
    outlet Los Angeles Times
    category b
    cluster ddUyU0VZz0BRneMioxUPQ...
    host www.latimes.com
    tstamp 2014-03-10 16:52:50.6...
    Name: 1, dtype: object

    Ahora que ha tenía una visión de los datos, se puede empezar a hacer preguntas más complejas sobre ella.

    Uso de las funciones Lambda en .groupby ()

    invita este conjunto de datos mucho más potencialmente cuestiones involucradas. Voy a tirar al azar pero significativo por ahí: lo que los enchufes hablar más acerca de la Reserva Federal? Supongamos por simplicidad que esto conlleva en busca de mayúsculas y minúsculas menciones de "Fed". Tenga en cuenta que esto puede generar algunos falsos positivos con términos como “Gobierno Federal”. Para recuento

    menciona por su salida, puede llamar .groupby () en la salida, y luego literalmente .apply () una función en cada grupo: la ruptura de

    >>> df.groupby("outlet", sort=False)["title"].apply(
    ... lambda ser: ser.str.contains("Fed").sum()
    ... ).nlargest(10)
    outlet
    Reuters 161
    NASDAQ 103
    Businessweek 93
    Investing.com 66
    Wall Street Journal \(blog\) 61
    MarketWatch 56
    Moneynews 55
    Bloomberg 53
    GlobalPost 51
    Economic Times 44
    Name: title, dtype: int64

    dejar que esta abajo, ya que hay varias llamadas a métodos realizados en sucesión. Al igual que antes, se puede sacar el primer grupo y su correspondiente objeto pandas tomando la primera tupla de los pandas GroupBy iterador:

    >>> title, ser = next(iter(df.groupby("outlet", sort=False)["title"]))
    >>> title
    'Los Angeles Times'
    >>> ser.head()
    1 Fed official says weak data caused by weather,...
    486 Stocks fall on discouraging news from Asia
    1124 Clues to Genghis Khan's rise, written in the r...
    1146 Elephants distinguish human voices by sex, age...
    1237 Honda splits Acura into its own division to re...
    Name: title, dtype: object

    En este caso, ser una serie pandas en lugar de una trama de datos. Esto se debe a que siguió a la llamada .groupby () con [ "título"]. Esto selecciona eficazmente que una sola columna de cada sub-tabla.

    Luego viene .str.contains ( "Fed"). Esto devuelve una serie booleano que es verdadera cuando un título del artículo registra una coincidencia en la búsqueda. Efectivamente, la primera fila comienza con "funcionario de la Fed dice que los datos débiles causados ​​por el clima, ..." y se ilumina como verdadera:

    >>> ser.str.contains("Fed")
    1 True
    486 False
    1124 False
    1146 False
    1237 False
    ...
    421547 False
    421584 False
    421972 False
    422226 False
    422905 False
    Name: title, Length: 1976, dtype: bool

    El siguiente paso es .sum () esta serie. Desde bool es técnicamente sólo un tipo especializado de int, puede sumar una serie de verdadero y falso del mismo modo que resumir una secuencia de 1 y 0:

    >>> ser.str.contains("Fed").sum()
    17

    El resultado es el número de menciones de "Fed" por el Los Angeles Times en el conjunto de datos. La misma rutina se aplica para Reuters, NASDAQ, Business Week, y el resto del lote.

    mejorar el rendimiento de .groupby () de retroceso

    Vamos de nuevo a .groupby (...). Apply () para ver por qué este patrón puede ser subóptima. Para obtener alguna información de fondo, echa un vistazo a Cómo acelerar su pandas Proyectos. Lo que puede ocurrir con .apply () es que va a realizar con eficacia un bucle Python sobre cada grupo. Mientras que el .groupby (...). Aplicar () patrón puede proporcionar una cierta flexibilidad, que puede también inhiben pandas de usar de otro modo sus optimizaciones basadas en Cython.

    Todo lo que quiere decir que cada vez que se encuentra pensando en el uso de .apply (), preguntarse si hay una manera de expresar la operación de una forma vectorizada. En ese caso, se puede aprovechar el hecho de que .groupby () acepta no sólo uno o más nombres de columna, pero también muchos gama-como las estructuras :

    • A 1-dimensional array NumPy
    • Una lista
    • una serie pandas o índice

    también tenga en cuenta que .groupby () es un método de instancia válida para una serie, no sólo una trama de datos, de modo que pueda esencialmente inversa a la lógica de dividir. Con esto en mente, primero puede construir una serie de booleanos que indican si el título contiene "Fed":

    >>> mentions_fed = df["title"].str.contains("Fed")
    >>> type(mentions_fed)

    Ahora, .groupby () es también un método de la serie, por lo que puede agrupar una serie en otra:

    >>> import numpy as np
    >>> mentions_fed.groupby(
    ... df["outlet"], sort=False
    ... ).sum().nlargest(10).astype(np.uintc)
    outlet
    Reuters 161
    NASDAQ 103
    Businessweek 93
    Investing.com 66
    Wall Street Journal \(blog\) 61
    MarketWatch 56
    Moneynews 55
    Bloomberg 53
    GlobalPost 51
    Economic Times 44
    Name: title, dtype: uint32

    las dos series no tienen que ser las columnas de un mismo objeto trama de datos. Sólo tienen que ser de la misma forma:

    >>> mentions_fed.shape
    (422419,)
    >>> df["outlet"].shape
    (422419,)

    Por último, se puede emitir el resultado de vuelta a un entero sin signo con np.uintc si usted está decidido a obtener el resultado más compacto posible. He aquí una comparación cabeza a cabeza de las dos versiones que producirán el mismo resultado:

    # Version 1: using `.apply()`
    df.groupby("outlet", sort=False)["title"].apply(
    lambda ser: ser.str.contains("Fed").sum()
    ).nlargest(10)

    # Version 2: using vectorization
    mentions_fed.groupby(
    df["outlet"], sort=False
    ).sum().nlargest(10).astype(np.uintc)

    En mi portátil, Versión 1 toma 4.01 segundos, mientras que la versión 2 tarda sólo 292 milisegundos. Se trata de una impresionante diferencia 14x en tiempo de CPU para un par de cientos de miles de filas. Tenga en cuenta cómo dramática la diferencia se hace cuando el conjunto de datos crece a unos pocos millones de filas!

    Nota : Este ejemplo esmaltes sobre algunos detalles en los datos en aras de la simplicidad. A saber, el término de búsqueda "Fed" también puede encontrar menciones de cosas como “Gobierno Federal”.

    Series.str.contains () también toma una expresión regular compilada como un argumento si se desea conseguir la suposición y el uso de una expresión que implica una búsqueda negativa hacia delante.

    También puede querer contar no sólo el número de menciones en bruto, pero la proporción de menciones en relación con todos los artículos que produce un medio de comunicación.

    pandas GroupBy: Poniendo todo junto

    Si llama dir () en un objeto pandas GroupBy, entonces usted verá suficientes métodos allí para hacer girar su cabeza! Puede ser difícil hacer un seguimiento de toda la funcionalidad de un objeto pandas GroupBy. Una forma de despejar la niebla es compartimentar los diferentes métodos en lo que hacen y cómo se comportan.

    En términos generales, los métodos de una caída objeto pandas GroupBy en un puñado de categorías: métodos

    agregación (también llamado métodos de reducción ) “Smush” muchos puntos de datos en una estadística agregada acerca de esos puntos de datos. Un ejemplo es tomar la suma, la media o mediana de 10 números, donde el resultado es un solo número. Filtrar métodos

    vienen de nuevo a usted con un subconjunto de la trama de datos originales. Esto significa más comúnmente usando .Filter () para soltar grupos enteros basado en alguna estadística comparativa sobre ese grupo y su sub-tabla. También tiene sentido para incluir en esta definición un número de métodos que excluyen filas específicas de cada grupo. Los métodos de transformación

    devuelven una trama de datos con la misma forma y los índices como el original, pero con diferentes valores. Con ambos métodos de agregación y el filtro, la trama de datos resultante será comúnmente ser más pequeña en tamaño que la trama de datos de entrada. Esto no es cierto de una transformación, que transforma los valores individuales a sí mismos, pero conserva la forma de la trama de datos originales. métodos

    Meta están menos preocupados con el objeto original en el que se ha llamado .groupby (), y más enfocado en darle información de alto nivel, tales como el número de grupos e índices de esos grupos. métodos

    Trazado imitan la API de planear para una serie pandas o trama de datos, pero normalmente romper la salida en múltiples subtramas.

    La documentación oficial tiene su propia explicación de estas categorías. Son, en cierto grado, abierto a la interpretación, y esto divergen fuerza tutorial en formas leves en la clasificación de qué método se cae dónde.

    Nota: También hay otra tabla separada en la documentación pandas con su propio sistema de clasificación. Recoger lo que funciona para usted y parece más intuitivo!

    Puede echar un vistazo a un desglose más detallado de cada categoría y los diversos métodos de .groupby () que se incluyen en ellos:

    métodos de agregación y Propiedades mostrar / ocultar métodos

    agregación (también llamados métodos de reducción de ) “Smush” muchos puntos de datos en una estadística agregada sobre los puntos de datos. Un ejemplo es tomar la suma, la media o mediana de 10 números, donde el resultado es un solo número. Aquí están algunos métodos de agregación:

    • .agg ()
    • .aggregate ()
    • .all ()
    • .any ()
    • .apply ()
    • .corr ()
    • .corrwith ()
    • .count ()
    • .cov ()
    • .cumcount ()
    • .cummax ()
    • .cummin ()
    • .cumprod ()
    • .cumsum ()
    • • Describir ()
    • . idxmax ()
    • .idxmin ()
    • .mad ()
    • .max ()
    • .mean ()
    • .median ()
    • .min ()
    • .nunique ()
    • .prod ( )
    • .sem ()
    • .size ()
    • .skew ()
    • .std ()
    • .sum ()
    • .var ()

    Filtro Métodos y propiedades Mostrar / Ocultar

    métodos de filtro volver a usted con un subconjunto de la trama de datos originales. Esto significa más comúnmente usando .Filter () para soltar grupos enteros basado en alguna estadística comparativa sobre ese grupo y su sub-tabla. También tiene sentido para incluir en esta definición un número de métodos que excluyen filas específicas de cada grupo. Aquí están algunos métodos de filtro:

    • .Filter ()
    • .First ()
    • .head ()
    • .last ()
    • .nth ()
    • .tail ()
    • .take ()

    métodos de transformación y propiedades mostrar / ocultar

    los métodos de transformación devuelve una trama de datos con la misma forma y los índices como el original, pero con diferentes valores. Con ambos métodos de agregación y el filtro, la trama de datos resultante será comúnmente ser más pequeña en tamaño que la trama de datos de entrada. Esto no es cierto de una transformación, que transforma los valores individuales a sí mismos, pero conserva la forma de la trama de datos originales. Aquí están algunos métodos de transformadores:

    • .bfill ()
    • .diff ()
    • .ffill ()
    • .fillna ()
    • .pct_change ()
    • .quantile ()
    • .rank ()
    • .shift ()
    • .transform ()
    • .tshift ()

    métodos Meta y Propiedades Mostrar / Ocultar métodos

    Meta tienen menos que ver con el objeto original en el que se ha llamado .groupby (), y más centrado en darle información de alto nivel, tales como el número de grupos e índices de esos grupos. Éstos son algunos métodos meta:

    • .__ __ (iter)
    • .get_group ()
    • .Grupos
    • .indices
    • .ndim
    • .ngroup

    Métodos Trazado ()

  • .ngroups
  • .dtypes
  • Mostrar / Ocultar métodos

    trazado imitan la API de planear para una serie pandas o trama de datos, pero normalmente rompen la salida en múltiples subtramas. Aquí están algunos métodos de trazado:

    • .hist ()
    • .ohlc ()
    • .boxplot ()
    • .PLOT ()

    Odds and Ends Mostrar / Ocultar

    Hay algunos métodos de pandas GroupBy objetos que no están muy bien en las categorías anteriores. Estos métodos generalmente producen un objeto intermedio que es no una trama de datos o serie. . Por ejemplo, df.groupby (...) rodando (...) produce un objeto RollingGroupby, que se puede métodos de agregación, el filtro o de transformación continuación de compra sobre: ​​

    • .expanding ()
    • .pipe ()
    • .resample ()
    • .rolling ()

    Conclusión

    en este tutorial, que ha cubierto un montón de tierra en .groupby) (, incluyendo su diseño, su API, y la forma de la cadena de métodos en conjunto para obtener los datos en una salida que se adapte a su propósito.

    Usted ha aprendido:

    • Cómo utilizar las operaciones de pandas GroupBy en los datos del mundo real
    • Cómo aplicar la escisión-combinar la cadena de obras de operaciones y cómo se puede descomponer en pasos
    • cómo los métodos de una pandas GroupBy se puede colocar en diferentes categorías en función de su intención y el resultado

    Hay mucho más a .groupby () que se puede cubrir en un tutorial. Echa un vistazo a los siguientes recursos y el uso de los conjuntos de datos de ejemplo aquí como un punto de partida para una exploración más profunda!

    Puede descargar el código fuente de todos los ejemplos de este tutorial haciendo clic en el siguiente enlace:

    descargar conjuntos de datos: Haga clic aquí para descargar los conjuntos de datos que utilizará para aprender acerca de las pandas' GroupBy en este tutorial.

    Más recursos sobre guías de documentación pandas GroupBy

    pandas son fáciles de usar paseos virtuales a diferentes aspectos de las pandas. Aquí hay algunas partes de la documentación que se pueden extraer para aprender más acerca de las pandas GroupBy:

    • las pandas GroupBy guía del usuario
    • La Agrupación libro de cocina

    La documentación de la API es una referencia técnica más completa de métodos y objetos:

    • DataFrame.groupby ()
    • DataFrame.resample ()
    • pandas.Grouper
    Categorías
    Python

    Pandas tramas de datos 101

     

    Tabla de Contenidos

    • Lo que se burla?
    • El pitón Mock Biblioteca
    • El Mock ObjectLazy Atributos y MethodsAssertions y InspectionManaging una de Mock Volver ValueManaging lateral de una maqueta EffectsConfiguring Su Mock
    • Lazy atributos y métodos
    • Las afirmaciones e inspección
    • La gestión de un simulacro de valor devuelto
    • Gestión lateral de una maqueta efectos
    • Configuración del parche Mock
    • () parche () como un Decoratorpatch () como un Contexto ManagerPatching AttributesWhere de un objeto al parche Patch
    • () como un parche decorador
    • () como un Contexto Gestor
    • aplicar un parche de objetos atributos
    • Dónde Patch
    • comunes ProblemsChanges Burlándose a Objeto Interfaces y MisspellingsChanges a las dependencias
    • cambios externos a Objeto Interfaces y faltas de ortografía
    • cambios a External dependencias
    • evitar problemas más comunes gracias Especificaciones
    • Conclusión

    T G_7

  • Lazy atributos y métodos
  • Las afirmaciones e inspección
  • La gestión de un simulacro de valor devuelto
  • La gestión de un simulacro de efectos secundarios
  • Configuración del parche Mock
    • () como un parche decorador
    • () como un Contexto Gestor
    • Parches de un objeto Atributos
    • Dónde Patch
    • cambios a objetos Interfaces y faltas de ortografía
    • cambios a External dependencias

    Cuando se está escribiendo código robusto, las pruebas son esenciales para la verificación de que su lógica de la aplicación es correcta, fiable y eficiente. Sin embargo, el valor de las pruebas depende de lo bien que demuestran estos criterios. Obstáculos tales como la lógica compleja y dependencias impredecibles hacen que escribir pruebas valiosas difícil. La biblioteca de objetos simulacro de Python, unittest.mock, puede ayudar a superar estos obstáculos.

    Al final de este artículo, usted será capaz de:

    • Crear Python objetos simulados utilizando Mock
    • Afirmar que está utilizando objetos como se pretendía
    • Inspeccionar los datos de uso almacenados en su Python burla
    • Configurar ciertos aspectos de su maqueta de objetos de Python
    • sustituya su burla para los objetos reales utilizando parche () Evitar problemas
    • comunes inherentes en Python burlarse

    Vamos a empezar por ver lo que es de burla y cómo va a mejorar sus ensayos. Bono

    gratuito: 5 pensamientos sobre Python Maestría, un curso gratuito para los desarrolladores de Python que muestra la hoja de ruta y la mentalidad que necesita para tomar sus habilidades de Python al siguiente nivel.

    Lo que se burla?

    un objeto simulacro de sustitutos e imita un objeto real dentro de un entorno de prueba. Es una herramienta versátil y poderosa para mejorar la calidad de las pruebas.

    Una de las razones para utilizar Python objetos simulados es controlar el comportamiento de su código durante la prueba.

    Por ejemplo, si su código hace peticiones HTTP a servicios externos, a continuación, ejecutar sus pruebas previsiblemente sólo en tanto que los servicios se están comportando como se esperaba. A veces, un cambio temporal en el comportamiento de estos servicios externos puede causar fallos intermitentes dentro de su serie de pruebas.

    Debido a esto, sería mejor para poner a prueba su código en un entorno controlado. Sustitución de la solicitud real con un objeto de burla le permitirá simular interrupciones de servicios externos y las respuestas exitosas de una manera predecible.

    A veces, es difícil de probar ciertas áreas de su código base. Tales áreas incluyen excepto bloques y si las declaraciones que son difíciles de satisfacer. El uso de objetos simulados Python puede ayudar a controlar la ruta de ejecución de su código para llegar a esas zonas y mejorar su cobertura de código.

    Otra razón para utilizar los objetos de imitación es entender mejor cómo se está usando sus homólogos reales en el código. Una pitón objeto de burla contiene datos sobre su uso que puede inspeccionar tales como:

    • Si llamó un método
    • Cómo llamó al método
    • ¿Con qué frecuencia se llamó al método

    La comprensión de lo que hace un objeto de burla es el primer paso para aprender a usar una.

    Ahora, verá cómo utilizar Python objetos simulados. librería de objetos mock

    El pitón Mock Biblioteca

    El Python es unittest.mock. Se proporciona una manera fácil de introducir burla en sus pruebas.

    Nota: La biblioteca estándar incluye unittest.mock en Python 3.3 y posteriores. Si está utilizando una versión anterior de Python, tendrá que instalar el backport oficial de la biblioteca. Para ello, instale simulacro de PyPI:

    $ pip install mock

    unittest.mock proporciona una clase llamada simulados que se va a utilizar para imitar a los objetos reales en su código base. ofertas simuladas increíble flexibilidad y datos interesantes. Esto, junto con sus subclases, se reunirá la mayoría de las necesidades de Python burlones que se enfrentará en sus pruebas.

    La biblioteca también proporciona una función, llamada parche (), que sustituye a los objetos reales en el código con casos Mock. Puede usar el parche () ya sea como un decorador o un gestor de contexto, que le permite controlar el alcance en el cual puede ser burlado el objeto. Una vez que las salidas de alcance designados, parche () va a limpiar su código mediante la sustitución de los objetos imitó con sus contrapartes originales.

    Por último, unittest.mock proporciona soluciones para algunos de los problemas inherentes a burlarse de los objetos.

    Ahora, usted tiene una mejor comprensión de lo que es burla y la biblioteca que va a utilizar para hacerlo. buceo de entrar y explorar qué características y funcionalidades unittest.mock ofertas.

    El Mock objeto

    ofertas unittest.mock una clase base para burlarse de objetos llamados Mock. Los casos de uso para Mock son prácticamente ilimitadas, ya Mock es tan flexible.

    Comience por crear una nueva instancia Mock:

    >>> from unittest.mock import Mock
    >>> mock = Mock()
    >>> mock

    Ahora, usted es capaz de sustituir un objeto en el código con su nuevo Mock. Puede hacer esto pasando como argumento a una función o mediante la redefinición de otro objeto:

    # Pass mock as an argument to do_something()
    do_something(mock)

    # Patch the json library
    json = mock

    Al sustituir un objeto en su código, la maqueta debe parecerse al objeto real que está reemplazando. De lo contrario, su código no será capaz de utilizar el Mock en lugar del objeto original.

    Por ejemplo, si usted está burlando de la biblioteca JSON y su programa llama a vertederos (), entonces su objeto de burla Python también debe contener vertederos ().

    A continuación, veremos cómo Mock se ocupa de este problema.

    Lazy atributos y métodos

    una maqueta debe simular cualquier objeto al que reemplaza. Para lograr esta flexibilidad, se crea sus atributos cuando se accede a ellos:

    >>> mock.some_attribute

    >>> mock.do_something()

    Desde Mock puede crear atributos arbitrarios sobre la marcha, es adecuado para sustituir cualquier objeto.

    Mediante un ejemplo de antes, si estás burlando de la biblioteca JSON y le llamaremos vertederos (), el objeto de burla Python creará el método de modo que su interfaz puede coincidir con la interfaz de la biblioteca:

    >>> json = Mock()
    >>> json.dumps()

    Aviso dos características clave de este versión burlado de los vertederos ():

    a diferencia de los vertederos de reales (), este método requiere burlado sin argumentos. De hecho, se aceptará cualquier argumento que se pasa a ella.

    El valor de retorno de los vertederos () es también un simulacro. La capacidad de Mock para definir recursivamente otros burla permite para su uso en situaciones complejas burla:

    >>> json = Mock()
    >>> json.loads('{"k": "v"}').get('k')

    Debido a que el valor de retorno de cada método burlado es también un Mock, usted puede utilizar su burla en una multitud de formas.

    Mocks son flexibles, pero también son informativos. A continuación, usted aprenderá cómo se pueden utilizar los simulacros de entender su código mejor.

    casos

    afirmaciones e Inspección

    Mock almacenar datos en la forma que los utilizó. Por ejemplo, se puede ver si se llama a un método, cómo se llama el método, y así sucesivamente. Hay dos formas principales de usar esta información.

    En primer lugar, se puede afirmar que su programa utiliza un objeto como se esperaba:

    >>> from unittest.mock import Mock

    >>> # Create a mock object
    ... json = Mock()

    >>> json.loads('{"key": "value"}')

    >>> # You know that you called loads() so you can
    >>> # make assertions to test that expectation
    ... json.loads.assert_called()
    >>> json.loads.assert_called_once()
    >>> json.loads.assert_called_with('{"key": "value"}')
    >>> json.loads.assert_called_once_with('{"key": "value"}')

    >>> json.loads('{"key": "value"}')

    >>> # If an assertion fails, the mock will raise an AssertionError
    ... json.loads.assert_called_once()
    Traceback (most recent call last):
    File "", line 1, in
    File "/usr/local/Cellar/python/3.6.5/Frameworks/Python.framework/Versions/3.6/lib/python3.6/unittest/mock.py", line 795, in assert_called_once
    raise AssertionError(msg)
    AssertionError: Expected 'loads' to have been called once. Called 2 times.

    >>> json.loads.assert_called_once_with('{"key": "value"}')
    Traceback (most recent call last):
    File "", line 1, in
    File "/usr/local/Cellar/python/3.6.5/Frameworks/Python.framework/Versions/3.6/lib/python3.6/unittest/mock.py", line 824, in assert_called_once_with
    raise AssertionError(msg)
    AssertionError: Expected 'loads' to be called once. Called 2 times.

    >>> json.loads.assert_not_called()
    Traceback (most recent call last):
    File "", line 1, in
    File "/usr/local/Cellar/python/3.6.5/Frameworks/Python.framework/Versions/3.6/lib/python3.6/unittest/mock.py", line 777, in assert_not_called
    raise AssertionError(msg)
    AssertionError: Expected 'loads' to not have been called. Called 2 times.

    .assert_called () asegura que llamó al método burlado mientras .assert_called_once () comprueba que llamó al método exactamente una vez.

    funciones Ambas variantes tienen afirmación que le permiten inspeccionar los argumentos que se pasan al método burlado:

    • .assert_called_with (* args, ** kwargs)
    • .assert_called_once_with (* args, ** kwargs)

    Para pasar estos afirmaciones, debe llamar al método burlado con los mismos argumentos que se pasa al método real:

    >>> json = Mock()
    >>> json.loads(s='{"key": "value"}')
    >>> json.loads.assert_called_with('{"key": "value"}')
    Traceback (most recent call last):
    File "", line 1, in
    File "/usr/local/Cellar/python/3.6.5/Frameworks/Python.framework/Versions/3.6/lib/python3.6/unittest/mock.py", line 814, in assert_called_with
    raise AssertionError(_error_message()) from cause
    AssertionError: Expected call: loads('{"key": "value"}')
    Actual call: loads(s='{"key": "value"}')
    >>> json.loads.assert_called_with(s='{"key": "value"}')

    json.loads.assert_called_with ( ‘{ ‘clave’: ‘valor’}’) levantó una AssertionError, ya que le espera a la llamada (cargas) con un argumento posicional, pero en realidad se llama con un argumento de palabra clave. json.loads.assert_called_with (s = ‘{ «clave»: «valor»}’) se pone esta afirmación correcta.

    segundo lugar, usted puede ver los atributos especiales para entender cómo su aplicación utiliza un objeto:

    >>> from unittest.mock import Mock

    >>> # Create a mock object
    ... json = Mock()
    >>> json.loads('{"key": "value"}')

    >>> # Number of times you called loads():
    ... json.loads.call_count
    1
    >>> # The last loads() call:
    ... json.loads.call_args
    call('{"key": "value"}')
    >>> # List of loads() calls:
    ... json.loads.call_args_list
    [call('{"key": "value"}')]
    >>> # List of calls to json's methods (recursively):
    ... json.method_calls
    [call.loads('{"key": "value"}')]

    Usted puede escribir pruebas que utilizan estos atributos para asegurarse de que sus objetos se comportan como se pretendía.

    Ahora, puede crear burla e inspeccionar sus datos de uso. A continuación, verá cómo personalizar los métodos burlado de modo que sean más útiles en el entorno de prueba.

    La gestión de una de Mock y valor devuelto

    Una razón para utilizar burla es controlar el comportamiento de su código durante las pruebas. Una forma de hacer esto es especificar el valor devuelto por una función. Usemos un ejemplo para ver cómo funciona esto.

    En primer lugar, crear un archivo llamado my_calendar.py. Añadir is_weekday (), una función de fecha y hora que utiliza la biblioteca de Python para determinar si es o no hoy es un día de la semana. Por último, escribir una prueba que afirma que la función funciona como se esperaba:

    from datetime import datetime

    def is_weekday():
    today = datetime.today()
    # Python's datetime library treats Monday as 0 and Sunday as 6
    return (0 <= today.weekday() < 5) # Test if today is a weekday assert is_weekday()

    Desde que está probando si hoy es un día laborable, el resultado depende del día se ejecuta la prueba:

    $ python my_calendar.py

    Si este comando no produce ninguna salida, la afirmación se ha realizado correctamente. Por desgracia, si ejecuta el comando en un fin de semana, obtendrá un AssertionError:

    $ python my_calendar.py
    Traceback (most recent call last):
    File "test.py", line 9, in
    assert is_weekday()
    AssertionError

    Al escribir pruebas, es importante asegurarse de que los resultados son predecibles. Puede usar Mock para eliminar la incertidumbre de su código durante la prueba. En este caso, puede burlarse de fecha y hora y establecer el .return_value para .HOY () para un día que le conviene más:

    import datetime
    from unittest.mock import Mock

    # Save a couple of test days
    tuesday = datetime.datetime(year=2019, month=1, day=1)
    saturday = datetime.datetime(year=2019, month=1, day=5)

    # Mock datetime to control today's date
    datetime = Mock()

    def is_weekday():
    today = datetime.datetime.today()
    # Python's datetime library treats Monday as 0 and Sunday as 6
    return (0 <= today.weekday() < 5) # Mock .today() to return Tuesday datetime.datetime.today.return_value = tuesday # Test Tuesday is a weekday assert is_weekday() # Mock .today() to return Saturday datetime.datetime.today.return_value = saturday # Test Saturday is not a weekday assert not is_weekday()

    En el ejemplo, .HOY () es un método burlado. Que haya eliminado la incompatibilidad mediante la asignación de un día específico para .return_value de la maqueta. De esta manera, cuando se llama .HOY (), que devuelve la fecha y hora que especificó.

    En la primera prueba, se asegura el martes es un día laborable. En la segunda prueba, verificar que el sábado no es un día laborable. Ahora, no importa qué día se ejecuta sus pruebas de porque se ha burlado de fecha y hora y tener control sobre el comportamiento del objeto.

    Lectura adicional: Aunque burlarse de fecha y hora como esto es un ejemplo de buenas prácticas para el uso de Mock, una biblioteca fantástica ya existe por burlarse de fecha y hora llamada freezegun.

    Cuando la construcción de sus pruebas, es probable que se encontrará con casos en los que burlaban valor de retorno de una función no será suficiente. Esto se debe a que las funciones son a menudo más complicado que un simple flujo unidireccional de la lógica.

    A veces, tendrá que hacer funciones devuelven valores diferentes cuando se les llama más de una vez o incluso excepciones aumento. Esto se puede hacer usando .side_effect.

    La gestión de un simulacro de efectos secundarios

    Se puede controlar el comportamiento de su código mediante la especificación de los efectos secundarios de una función burlado. A define .side_effect lo que sucede cuando se llama a la función burlado.

    para probar cómo funciona este, añadir una nueva función a my_calendar.py: get_holidays

    import requests

    def get_holidays():
    r = requests.get('http://localhost/api/holidays')
    if r.status_code == 200:
    return r.json()
    return None

    () hace una petición al servidor localhost para un conjunto de días festivos. Si el servidor responde con éxito, get_holidays () devuelve un diccionario. De lo contrario, el método devolverá None.

    Puede probar cómo get_holidays () responderán a un tiempo de espera de conexión mediante el establecimiento de requests.get.side_effect.

    Para este ejemplo, sólo se verá el código relevante de my_calendar.py. Usted va a construir un caso de prueba usando la biblioteca de Python unittest: .assertRaises uso

    import unittest
    from requests.exceptions import Timeout
    from unittest.mock import Mock

    # Mock requests to control its behavior
    requests = Mock()

    def get_holidays():
    r = requests.get('http://localhost/api/holidays')
    if r.status_code == 200:
    return r.json()
    return None

    class TestCalendar(unittest.TestCase):
    def test_get_holidays_timeout(self):
    # Test a connection timeout
    requests.get.side_effect = Timeout
    with self.assertRaises(Timeout):
    get_holidays()

    if __name__ == '__main__':
    unittest.main()

    usted () para verificar que los get_holidays () lanza una excepción dado el nuevo efecto secundario de get ().

    ejecutar esta prueba para ver el resultado de su prueba:

    $ python my_calendar.py
    .
    -------------------------------------------------------
    Ran 1 test in 0.000s

    OK

    Si quieres ser un poco más dinámico, se puede establecer .side_effect a una función que Mock invocará cuando se llama a su método de burla. Las acciones simuladas el valor argumentos y retorno de la función .side_effect:

    import requests
    import unittest
    from unittest.mock import Mock

    # Mock requests to control its behavior
    requests = Mock()

    def get_holidays():
    r = requests.get('http://localhost/api/holidays')
    if r.status_code == 200:
    return r.json()
    return None

    class TestCalendar(unittest.TestCase):
    def log_request(self, url):
    # Log a fake request for test output purposes
    print(f'Making a request to {url}.')
    print('Request received!')

    # Create a new Mock to imitate a Response
    response_mock = Mock()
    response_mock.status_code = 200
    response_mock.json.return_value = {
    '12/25': 'Christmas',
    '7/4': 'Independence Day',
    }
    return response_mock

    def test_get_holidays_logging(self):
    # Test a successful, logged request
    requests.get.side_effect = self.log_request
    assert get_holidays()['12/25'] == 'Christmas'

    if __name__ == '__main__':
    unittest.main()

    En primer lugar, se creó .log_request (), que toma una dirección URL, registra determinada impresión de salida utilizando (), a continuación, devuelve una respuesta falsa. A continuación, se ajusta el .side_effect de get () para .log_request (), que va a utilizar cuando se llama get_holidays (). Cuando se ejecuta la prueba, verá que get () hacia delante sus argumentos a .log_request () acepta entonces el valor de retorno y la devuelve así:

    $ python my_calendar.py
    Making a request to http://localhost/api/holidays.
    Request received!
    .
    -------------------------------------------------------
    Ran 1 test in 0.000s

    OK

    Gran! Las declaraciones de impresión () registra los valores correctos. Además, get_holidays () devuelven el diccionario de las vacaciones.

    .side_effect también puede ser un iterable. El iterable debe consistir en valores de retorno, excepciones, o una mezcla de ambos. El iterables producirá su siguiente valor cada vez que se llama a su método de burla. Por ejemplo, se puede probar que un reintento después de un tiempo de espera devuelve una respuesta exitosa:

    import unittest
    from requests.exceptions import Timeout
    from unittest.mock import Mock

    # Mock requests to control its behavior
    requests = Mock()

    def get_holidays():
    r = requests.get('http://localhost/api/holidays')
    if r.status_code == 200:
    return r.json()
    return None

    class TestCalendar(unittest.TestCase):
    def test_get_holidays_retry(self):
    # Create a new Mock to imitate a Response
    response_mock = Mock()
    response_mock.status_code = 200
    response_mock.json.return_value = {
    '12/25': 'Christmas',
    '7/4': 'Independence Day',
    }
    # Set the side effect of .get()
    requests.get.side_effect = [Timeout, response_mock]
    # Test that the first request raises a Timeout
    with self.assertRaises(Timeout):
    get_holidays()
    # Now retry, expecting a successful response
    assert get_holidays()['12/25'] == 'Christmas'
    # Finally, assert .get() was called twice
    assert requests.get.call_count == 2

    if __name__ == '__main__':
    unittest.main()

    La primera vez que llame get_holidays (), get () plantea un tiempo de espera. La segunda vez, el método devuelve un diccionario vacaciones válidos. Estos efectos secundarios coinciden con el orden en que aparecen en la lista aprobada a .side_effect.

    Puede establecer .return_value y .side_effect en un simulacro de forma directa. Sin embargo, debido a que un objeto de burla Python tiene que ser flexible en la creación de sus atributos, hay una mejor manera de configurar estos y otros ajustes.

    la configuración de su Mock

    Se puede configurar un simulacro de configurar algunos de los comportamientos del objeto. Algunos miembros configurables incluyen .side_effect, .return_value, y .name. Configura un Mock cuando se crea uno o cuando se utiliza .configure_mock ().

    Se puede configurar un Mock especificando ciertos atributos al inicializar un objeto:

    >>> mock = Mock(side_effect=Exception)
    >>> mock()
    Traceback (most recent call last):
    File "", line 1, in
    File "/usr/local/Cellar/python/3.6.5/Frameworks/Python.framework/Versions/3.6/lib/python3.6/unittest/mock.py", line 939, in __call__
    return _mock_self._mock_call(*args, **kwargs)
    File "/usr/local/Cellar/python/3.6.5/Frameworks/Python.framework/Versions/3.6/lib/python3.6/unittest/mock.py", line 995, in _mock_call
    raise effect
    Exception

    >>> mock = Mock(name='Real Python Mock')
    >>> mock

    >>> mock = Mock(return_value=True)
    >>> mock()
    True

    Mientras .side_effect y .return_value se pueden establecer en la instancia Mock, en sí, otros atributos como .name sólo se puede establecer a través .__ init __ () o .configure_mock (). Si se intenta establecer la .name del Mock en la instancia, se obtiene un resultado diferente:

    >>> mock = Mock(name='Real Python Mock')
    >>> mock.name

    >>> mock = Mock()
    >>> mock.name = 'Real Python Mock'
    >>> mock.name
    'Real Python Mock'

    .name es un atributo común para los objetos a su uso. Así, Mock no le permite establecer dicho valor en la instancia de la misma manera que con .return_value o .side_effect. Si accede a mock.name va a crear un atributo .name en lugar de la configuración de su maqueta.

    Puede configurar un simulacro usando .configure_mock existente ():

    >>> mock = Mock()
    >>> mock.configure_mock(return_value=True)
    >>> mock()
    True

    Por desempaquetar un diccionario en cualquiera .configure_mock () o Mock .__ init __ (), incluso se puede configurar atributos de su maqueta de Python de objetos. El uso de configuraciones Mock, podría simplificar un ejemplo anterior:

    # Verbose, old Mock
    response_mock = Mock()
    response_mock.json.return_value = {
    '12/25': 'Christmas',
    '7/4': 'Independence Day',
    }

    # Shiny, new .configure_mock()
    holidays = {'12/25': 'Christmas', '7/4': 'Independence Day'}
    response_mock = Mock(**{'json.return_value': holidays})

    Ahora, puede crear y configurar Python objetos simulados. También puede utilizar burla para controlar el comportamiento de su aplicación. Hasta ahora, usted ha utilizado burla como argumentos a las funciones u objetos de parches en el mismo módulo que sus pruebas.

    A continuación, usted aprenderá cómo sustituir sus burla para los objetos reales en otros módulos. parche

    ()

    unittest.mock proporciona un poderoso mecanismo para objetos de burla, llamada parche (), que busca un objeto en un determinado módulo y sustituye al objeto con una maqueta.

    Por lo general, se utiliza el parche () como un decorador o un gestor de contexto para proporcionar un ámbito en el que va a burlarse del objeto de destino.

    parche

    () como un decorador

    Si quiere burlarse de un objeto para la duración de su función de prueba de todo, se puede usar el parche () como decorador función.

    Para ver cómo funciona esto, reorganizan su archivo my_calendar.py poniendo la lógica y las pruebas en archivos separados:

    import requests
    from datetime import datetime

    def is_weekday():
    today = datetime.today()
    # Python's datetime library treats Monday as 0 and Sunday as 6
    return (0 <= today.weekday() < 5) def get_holidays(): r = requests.get('http://localhost/api/holidays') if r.status_code == 200: return r.json() return None

    Estas funciones se encuentran ahora en su propio archivo, separarse de sus pruebas. A continuación, deberá volver a crear sus pruebas en un archivo llamado tests.py.

    Hasta este punto, hemos parcheado mono objetos en el archivo en el que existen. parches Monkey es la sustitución de un objeto con otro en tiempo de ejecución. Ahora, vamos a usar el parche () para reemplazar los objetos en my_calendar.py:

    import unittest
    from my_calendar import get_holidays
    from requests.exceptions import Timeout
    from unittest.mock import patch

    class TestCalendar(unittest.TestCase):
    @patch('my_calendar.requests')
    def test_get_holidays_timeout(self, mock_requests):
    mock_requests.get.side_effect = Timeout
    with self.assertRaises(Timeout):
    get_holidays()
    mock_requests.get.assert_called_once()

    if __name__ == '__main__':
    unittest.main()

    Originalmente, se creó una maqueta y parcheado solicitudes en el ámbito local. Ahora, es necesario para acceder a la biblioteca de solicitudes en my_calendar.py de tests.py.

    Para este caso, se utiliza el parche () como decorador y se pasa la ruta del objeto de destino. La ruta de destino era 'my_calendar.requests' que consiste en el nombre del módulo y el objeto.

    También definido un nuevo parámetro para la función de prueba. patch () utiliza este parámetro para pasar el objeto burlado en su prueba. A partir de ahí, se puede modificar la maqueta o hacer afirmaciones como sea necesario.

    Puede ejecutar este módulo de prueba para asegurarse de que está funcionando como se esperaba: Detalle

    $ python tests.py
    .
    -------------------------------------------------------
    Ran 1 test in 0.001s

    OK

    técnico: parche () devuelve una instancia de MagicMock, que es una subclase Mock. MagicMock es útil ya que implementa métodos más magia para usted, como .__ __ len (), str .__ __ (), y .__ __ iter (), con valores por defecto razonables.

    Uso de parche () como un decorador funcionó bien en este ejemplo. En algunos casos, es más fácil de leer, más eficaz, o más fácil el uso del parche () como un gestor de contexto.

    parche

    () como un Contexto Gestor

    A veces, tendrá que utilizar el parche () como un gestor de contexto en lugar de un decorador. Algunas de las razones por las que podría preferir un gestor de contexto incluyen los siguientes:

    • Usted sólo quiere burlarse de un objeto para una parte del volumen de prueba.
    • Usted ya está usando demasiados decoradores o parámetros, lo que perjudica la legibilidad de su prueba.

    Para el uso del parche () como un gestor de contexto, se utiliza Python con la declaración:

    import unittest
    from my_calendar import get_holidays
    from requests.exceptions import Timeout
    from unittest.mock import patch

    class TestCalendar(unittest.TestCase):
    def test_get_holidays_timeout(self):
    with patch('my_calendar.requests') as mock_requests:
    mock_requests.get.side_effect = Timeout
    with self.assertRaises(Timeout):
    get_holidays()
    mock_requests.get.assert_called_once()

    if __name__ == '__main__':
    unittest.main()

    Cuando la prueba sale de la sentencia with, parche () reemplaza el objeto burlado con el original.

    Hasta ahora, has burlado objetos completos, pero a veces sólo se va a querer burlarse de una parte de un objeto.

    Parches un Objeto de Atributos ejemplo de

    permiten sólo quieren burlarse de un método de un objeto en lugar de todo el objeto. Puede hacerlo utilizando patch.object ().

    Por ejemplo, .test_get_holidays_timeout () en realidad sólo necesita requests.get maqueta () y establezca su .side_effect a Tiempo de espera:

    import unittest
    from my_calendar import requests, get_holidays
    from unittest.mock import patch

    class TestCalendar(unittest.TestCase):
    @patch.object(requests, 'get', side_effect=requests.exceptions.Timeout)
    def test_get_holidays_timeout(self, mock_requests):
    with self.assertRaises(requests.exceptions.Timeout):
    get_holidays()

    if __name__ == '__main__':
    unittest.main()

    En este ejemplo, se ha burlado solamente get () en lugar de todas las solicitudes. Cada otro atributo permanece igual.

    objeto () toma los mismos parámetros de configuración que patch () hace. Pero en lugar de pasar el camino del objetivo, se proporciona el objeto de destino, en sí, como el primer parámetro. El segundo parámetro es el atributo del objeto de destino que usted está tratando de burlarse. También puede utilizar el objeto () como un gestor de contexto como el parche ().

    Lectura adicional: Además de objetos y atributos, también se puede parchear los diccionarios () con patch.dict ().

    Aprender a usar el parche () es crítica para burlarse de objetos en otros módulos. Sin embargo, a veces no es obvio lo que el trazado del objeto objetivo.

    Dónde Patch

    saber dónde decirle parche () para buscar el objeto que desea burlado es importante porque si se elige la ubicación de destino equivocado, el resultado de parche () podría ser algo que no esperaba. digamos de

    permiten están burlando de is_weekday () en my_calendar.py usando parche ():

    >>> import my_calendar
    >>> from unittest.mock import patch

    >>> with patch('my_calendar.is_weekday'):
    ... my_calendar.is_weekday()
    ...

    En primer lugar, se importa my_calendar.py. A continuación, aplicar un parche is_weekday (), reemplazándolo con una maqueta. ¡Excelente! Esto funciona como se esperaba.

    Ahora, vamos a cambiar este ejemplo ligeramente y se importan directamente a la función:

    >>> from my_calendar import is_weekday
    >>> from unittest.mock import patch

    >>> with patch('my_calendar.is_weekday'):
    ... is_weekday()
    ...
    False

    Nota: Dependiendo de qué día usted está leyendo este tutorial, su salida de la consola puede leer Verdadero o Falso. Lo importante es que la salida no es un simulacro como antes.

    en cuenta que a pesar de que la ubicación de destino que ha pasado a parche () no cambia, el resultado de llamar is_weekday () es diferente. La diferencia se debe al cambio en la forma en que ha importado la función.

    de my_calendar is_weekday importación se une a la función real del ámbito local. Así, a pesar de que Patch () la función más tarde, se ignora el simulacro porque ya tiene una referencia local a la función anti-burlado.

    Una regla de oro es bien de parchear () del objeto en el que se busca.

    En el primer ejemplo, burlándose 'my_calendar.is_weekday ()' obras, ya que mirar hacia arriba la función en el módulo my_calendar. En el segundo ejemplo, usted tiene una referencia local a is_weekday (). Dado que se utiliza la función que se encuentra en el ámbito local, debe burlarse de la función local:

    >>> from unittest.mock import patch
    >>> from my_calendar import is_weekday

    >>> with patch('__main__.is_weekday'):
    ... is_weekday()
    ...

    Ahora, usted tiene un control firme sobre el poder de parche (). Usted ha visto cómo parchar () objetos y atributos, así como donde parchear ellos.

    A continuación, verá algunos problemas comunes inherentes a burla objeto y las soluciones que ofrece unittest.mock. Los problemas que imita objetos

    Común

    Burlándose pueden introducir varios problemas en sus pruebas. Algunos problemas son inherentes a la burla, mientras que otros son específicos de unittest.mock. Hay que tener en cuenta que existen otros problemas con burla que no se mencionan en este tutorial.

    Los cubiertos aquí son similares entre sí en que el problema que causan es fundamentalmente el mismo. En cada caso, las afirmaciones de las pruebas son irrelevantes. A pesar de la intención de cada maqueta es válida, las mismas no son burla.

    cambios a clases de objetos Interfaces y faltas de ortografía

    y definiciones de funciones cambian todo el tiempo. Cuando la interfaz de un objeto cambia, las pruebas que dependen de una maqueta de ese objeto pueden llegar a ser irrelevante.

    Por ejemplo, puede cambiar el nombre de un método, pero hay que olvidar que una burla de prueba que invoca el método y .assert_not_called (). Después del cambio, .assert_not_called () sigue siendo cierto. La afirmación no es útil, sin embargo, porque el método ya no existe. pruebas irrelevantes

    puede no parecer crítico, pero si son sus únicas pruebas y asumen que funcionan correctamente, la situación podría ser desastroso para su aplicación.

    Un problema específico de Mock es una falta de ortografía que puede romper una prueba. Recordemos que un Mock crea su interfaz cuando accede a sus miembros. Por lo tanto, se le inadvertidamente crear un nuevo atributo si se escribe incorrectamente su nombre.

    Si llama .asert_called () en lugar de .assert_called (), su prueba no plantear una AssertionError. Esto se debe a que ha creado un nuevo método en el objeto simulacro de Python llamado .asert_called () en lugar de evaluar una afirmación real. Detalle

    técnico: Curiosamente, assret es una falta de ortografía especial de aserción. Si se intenta acceder a un atributo que se inicia con assret (o afirman), Mock elevará automáticamente una AttributeError.

    Estos problemas se producen cuando se burlan de los objetos dentro de su propio código base. Un problema diferente se plantea cuando te burlas objetos que interactúan con bases de código externos.

    Los cambios en las dependencias externas

    Imagínese una vez más que el código hace una petición a una API externa. En este caso, la dependencia externa es la API que es susceptible a cambios sin su consentimiento. aislado

    Por un lado, la prueba de las pruebas unitarias componentes de código. Así, burlando el código que hace la solicitud ayuda a poner a prueba sus componentes aislados bajo condiciones controladas. Sin embargo, también presenta un problema potencial.

    Si una dependencia externa cambia su interfaz, sus objetos simulados Python no será válida. Si esto sucede (y el cambio de interfaz es una ruptura), sus pruebas pasarán porque sus objetos simulados han enmascarado el cambio, pero el código de producción se producirá un error.

    Por desgracia, esto no es un problema que unittest.mock proporciona una solución para. Debe ejercer un juicio cuando se burla dependencias externas.

    Los tres de estos problemas puede causar la irrelevancia de prueba y problemas potencialmente costosos ya que amenazan la integridad de los simulacros. unittest.mock le da algunas herramientas para hacer frente a estos problemas.

    evitar problemas más comunes gracias Especificaciones

    Como se mencionó antes, si se cambia una definición de clase o función o atributo se escribe incorrectamente una maqueta del objeto Python, puede causar problemas con sus pruebas.

    Estos problemas se deben a Mock crea atributos y métodos, cuando se accede a ellos. La respuesta a estas cuestiones es prevenir Mock desde la creación de atributos que no se ajusten al objeto que está tratando de burlarse.

    Al configurar una maqueta, se puede pasar un objeto a la especificación del parámetro de especificación. El parámetro spec acepta una lista de nombres o otro objeto y define la interfaz de la maqueta. Si se intenta acceder a un atributo que no pertenece a la especificación, Mock lanzará una AttributeError:

    >>> from unittest.mock import Mock
    >>> calendar = Mock(spec=['is_weekday', 'get_holidays'])

    >>> calendar.is_weekday()

    >>> calendar.create_event()
    Traceback (most recent call last):
    File "", line 1, in
    File "/usr/local/Cellar/python/3.6.5/Frameworks/Python.framework/Versions/3.6/lib/python3.6/unittest/mock.py", line 582, in __getattr__
    raise AttributeError("Mock object has no attribute %r" % name)
    AttributeError: Mock object has no attribute 'create_event'

    Aquí, usted ha especificado que el calendario tiene métodos llamados .is_weekday (.get_holidays) y (). Cuando se accede a .is_weekday (), devuelve un Mock. Cuando se accede a .create_event (), un método que no coincide con la especificación, Mock plantea una AttributeError.

    especificaciones funcionan de la misma manera si se configura el Mock con un objeto: .is_weekday

    >>> import my_calendar
    >>> from unittest.mock import Mock

    >>> calendar = Mock(spec=my_calendar)
    >>> calendar.is_weekday()

    >>> calendar.create_event()
    Traceback (most recent call last):
    File "", line 1, in
    File "/usr/local/Cellar/python/3.6.5/Frameworks/Python.framework/Versions/3.6/lib/python3.6/unittest/mock.py", line 582, in __getattr__
    raise AttributeError("Mock object has no attribute %r" % name)
    AttributeError: Mock object has no attribute 'create_event'

    () está disponible al calendario porque se ha configurado el calendario para que coincida con la interfaz del módulo de my_calendar.

    Además, unittest.mock proporciona métodos convenientes de especificar automáticamente la interfaz de un ejemplo Mock.

    Una forma de implementar las especificaciones automáticos es create_autospec:

    >>> import my_calendar
    >>> from unittest.mock import create_autospec

    >>> calendar = create_autospec(my_calendar)
    >>> calendar.is_weekday()

    >>> calendar.create_event()
    Traceback (most recent call last):
    File "", line 1, in
    File "/usr/local/Cellar/python/3.6.5/Frameworks/Python.framework/Versions/3.6/lib/python3.6/unittest/mock.py", line 582, in __getattr__
    raise AttributeError("Mock object has no attribute %r" % name)
    AttributeError: Mock object has no attribute 'create_event'

    Al igual que antes, el calendario es una instancia Mock cuya interfaz partidos my_calendar. Si estás usando el parche (), puede enviar un argumento para el parámetro Autospec para lograr el mismo resultado:

    >>> import my_calendar
    >>> from unittest.mock import patch

    >>> with patch('__main__.my_calendar', autospec=True) as calendar:
    ... calendar.is_weekday()
    ... calendar.create_event()
    ...

    Traceback (most recent call last):
    File "", line 1, in
    File "/usr/local/Cellar/python/3.6.5/Frameworks/Python.framework/Versions/3.6/lib/python3.6/unittest/mock.py", line 582, in __getattr__
    raise AttributeError("Mock object has no attribute %r" % name)
    AttributeError: Mock object has no attribute 'create_event'

    Conclusión

    Usted ha aprendido mucho acerca de burlarse de los objetos utilizando unittest.mock!

    Ahora, usted es capaz de:

    • Uso Mock a objetos imitarlo en sus pruebas
    • Comprobar los datos de uso para entender cómo usar sus objetos
    • Personalizar valores de retorno y los efectos secundarios parche
    • sus simulacros de objetos () objetos a través de su código base
    • Sede y problemas de evitar con el uso de Python simulacro de objetos

    usted ha construido una base de entender que le ayudará a construir mejores pruebas. Puede utilizar burla a hacerse una idea de su código que usted no habría sido capaz de conseguir de otra manera.

    Os dejo con una exención de responsabilidad final. Cuidado con el uso excesivo de los objetos de imitación!

    Es fácil aprovechar el poder de los objetos de imitación de Python y se burlan tanto que en realidad se reduce el valor de las pruebas.

    Si usted está interesado en aprender más sobre unittest.mock, os animo a leer su excelente documentación.

    Categorías
    Python

    Introducción a las excepciones Python

     

    Tabla de Contenidos

    • ponerse en forma: Introducción a NumPy matrices
    • ¿Cuál es vectorización conteo:? Tan fácil como 1, 2, 3 … Comprar barato, vender caro
    • conteo: Tan fácil como 1, 2, 3 …
    • Comprar barato, vender caro
    • Intermezzo: Comprensión ejes notación
    • Radiodifusión
    • Programación matriz en Acción: Tablas ExamplesClustering AlgorithmsAmortization TablesImage extracción de características
    • la agrupación algoritmos
    • amortización
    • imagen de extracción de características
    • un pensamiento de despedida: no más de -Optimizar
    • Más Recursos
    • conteo: tan fácil como 1, 2, 3 …
    • Comprar barato, vender Tablas alta
    • La agrupación algoritmos
    • amortización
    • imagen de extracción de características

    A veces se dice que Python, en comparación con los lenguajes de bajo nivel como C ++, mejora el tiempo de desarrollo a expensas de tiempo de ejecución. Afortunadamente, hay un puñado de formas de acelerar el tiempo de ejecución de la operación en Python sin sacrificar la facilidad de uso. Una opción adecuada para operaciones numéricas rápidas es NumPy, que merecidamente se anuncia como el paquete fundamental para la computación científica con Python.

    Por supuesto, algunas personas categorizaría algo que tarda 50 microsegundos (cincuenta millonésimas de segundo) como “lento”. Sin embargo, los ordenadores pueden discrepar. El tiempo de ejecución de una operación de tomar 50 microsegundos (50 microsiemens) cae bajo el ámbito de la microperformance , que libremente se puede definir como operaciones con un tiempo de ejecución entre 1 microsegundo y 1 milisegundo.

    ¿Por qué importa la velocidad? La razón por la que vale la pena microperformance monitoreo es que las pequeñas diferencias en el tiempo de ejecución se vuelven amplificados con repetidas llamadas a funciones: una incrementales 50 mu s de sobrecarga, que se repiten más de 1 millón de llamadas de función, se traduce a 50 segundos de tiempo de ejecución gradual.

    Cuando se trata de la computación, en realidad hay tres conceptos que se prestan NumPy su poder:

    • vectorización
    • Radiodifusión
    • Indexación

    En este tutorial, verá paso a paso cómo tomar ventaja de vectorización y la difusión de , por lo que se puede utilizar NumPy a su plena capacidad. Mientras que va a utilizar alguna de indexación en la práctica aquí, los esquemas de indexación completos de NumPy, que se extienden sintaxis de rebanado de Python, son su propia bestia. Si usted está buscando para leer más sobre NumPy indexación, agarrar un poco de café y la cabeza a la sección de indexación de los documentos NumPy. Bono

    gratuito: Haga clic aquí para obtener acceso a una Guía de Recursos libre NumPy que señala al los mejores tutoriales, videos y libros para mejorar sus habilidades NumPy.

    ponerse en forma: Introducción a NumPy Arrays

    El objeto fundamental de NumPy es su ndarray (o numpy.array), un n-dimensional array que también está presente en alguna forma en lenguajes orientados de matriz, tales como Fortran 90 , R, y MATLAB, así como predecesores APL y cosas de inicio de J.

    dejar fuera mediante la formación de una matriz de 3 dimensiones con 36 elementos:

    >>> import numpy as np

    >>> arr = np.arange(36).reshape(3, 4, 3)
    >>> arr
    array([[[ 0, 1, 2],
    [ 3, 4, 5],
    [ 6, 7, 8],
    [ 9, 10, 11]],

    [[12, 13, 14],
    [15, 16, 17],
    [18, 19, 20],
    [21, 22, 23]],

    [[24, 25, 26],
    [27, 28, 29],
    [30, 31, 32],
    [33, 34, 35]]])

    picturing arrays de alta dimensión en dos dimensiones puede ser difícil. Una forma intuitiva de pensar en la forma de una matriz es simplemente “leer de izquierda a derecha.” arr es un de 3 por 4 por 3 matriz:

    >>> arr.shape
    (3, 4, 3)

    Visualmente, arr podría ser pensado como un contenedor de tres 4×3 cuadrículas (o un prisma rectangular) y se vería así:

    dimensiones superiores matrices pueden ser más difíciles de imagen, pero todavía seguirá este “conjuntos dentro de una matriz” patrón.

    ¿Dónde podría ver los datos con más de dos dimensiones? datos

      Panel

    • pueden ser representados en tres dimensiones. Los datos que los atributos pistas de una cohorte (grupo) de los individuos en el tiempo podrían ser estructurados como (los encuestados, fechas, atributos). El 1979 Encuesta Nacional Longitudinal de la Juventud sigue 12.686 encuestados mayores de 27 años. Asumiendo que usted tiene ~ 500 puntos de datos directamente o derivados formuladas por persona y por año, estos datos tendría forma (12686, 27, 500) para un total de 177,604,000 puntos de datos. datos
    • de imágenes en color de varias imágenes se almacenan normalmente en cuatro dimensiones. Cada imagen es una matriz tridimensional de los valores de azul (RGB) (altura, anchura, canales), donde los canales son generalmente de color rojo, verde, y. Una colección de imágenes es entonces sólo (image_number, altura, anchura, canales). Mil 256×256 imágenes RGB tendrían forma (1000, 256, 256, 3). (Un extendió representación es RGBA, donde la A-alfa-denota el nivel de opacidad.)

    Para más detalle en ejemplos del mundo real de datos de alta dimensión, véase el capítulo 2 de profundo de aprendizaje de François Chollet con Python .

    ¿Cuál es vectorización?

    vectorización es una habilidad poderosa dentro NumPy para expresar las operaciones que ocurren en las matrices enteras en lugar de sus elementos individuales. He aquí una definición concisa de Wes McKinney:

    Esta práctica de sustituir los bucles explícitas con expresiones de matriz se conoce comúnmente como la vectorización. En general, las operaciones de matriz vectorizado serán a menudo uno o dos (o más) órdenes de magnitud más rápido que sus equivalentes de Python, con el mayor impacto [visto] en cualquier tipo de cálculos numéricos. [Fuente]

    Cuando bucle sobre una matriz o cualquier estructura de datos en Python, hay una gran cantidad de sobrecarga implicada. operaciones vectorizadas en NumPy delegan el bucle interno a las funciones altamente optimizados C y Fortran, lo que para más limpios y código Python más rápido.

    conteo: Tan fácil como 1, 2, 3 …

    A modo de ejemplo, considere un vector 1-dimensional de verdadero y falso para el que desea contar el número de “Falso a Verdadero” transiciones en la secuencia:

    >>> np.random.seed(444)

    >>> x = np.random.choice([False, True], size=100000)
    >>> x
    array([ True, False, True, ..., True, False, True])

    con un pitón de bucle, una manera de hacer esto sería evaluar, de dos en dos, el valor de verdad de cada elemento en la secuencia junto con el elemento que viene justo después de que:

    >>> def count_transitions(x) -> int:
    ... count = 0
    ... for i, j in zip(x[:-1], x[1:]):
    ... if j and not i:
    ... count += 1
    ... return count
    ...
    >>> count_transitions(x)
    24984

    en vectorizado forma, no hay explícita para -loop o referencia directa a los elementos individuales:

    >>> np.count_nonzero(x[:-1] < x[1:]) 24984

    ¿Cómo estas dos funciones equivalentes comparan en términos de rendimiento? En este caso particular, la llamada NumPy vectorizado gana por un factor de alrededor de 70 veces:

    >>> from timeit import timeit
    >>> setup = 'from __main__ import count_transitions, x; import numpy as np'
    >>> num = 1000
    >>> t1 = timeit('count_transitions(x)', setup=setup, number=num)
    >>> t2 = timeit('np.count_nonzero(x[:-1] < x[1:])', setup=setup, number=num) >>> print('Speed difference: {:0.1f}x'.format(t1 / t2))
    Speed difference: 71.0x

    Detalle técnico : Otro término es el procesador vectorial , que está relacionado con el hardware de un ordenador. Cuando hablo de vectorización aquí, me refiero al concepto de sustitución explícita para bucles con expresiones de matriz, que en este caso, entonces se pueden calcular internamente con un lenguaje de bajo nivel.

    Comprar barato, vender caro

    He aquí otro ejemplo para abrir el apetito. Consideremos el siguiente problema entrevista técnica clásica:

    Dada la historia precio de una acción como una secuencia, y suponiendo que sólo se le permite hacer una compra y una venta, ¿cuál es el beneficio máximo que se puede obtener? Por ejemplo, los precios dados = (20, 18, 14, 17, 20, 21, 15), el beneficio máximo serían 7, a partir de la compra y venta a los 14 a los 21

    (A todos ustedes Finanzas: no, no se permite la venta a corto plazo.)

    Hay una solución a la complejidad de tiempo n-cuadrado que consiste en tomar todas las combinaciones de dos precios en el segundo precio “viene después de” la primera y la determinación de la diferencia máxima.

    Sin embargo, existe también una solución de O (n), que consiste en iterar a través de la secuencia de una sola vez y la búsqueda de la diferencia entre cada precio y un mínimo funcionamiento . Es algo parecido a esto:

    >>> def profit(prices):
    ... max_px = 0
    ... min_px = prices[0]
    ... for px in prices[1:]:
    ... min_px = min(min_px, px)
    ... max_px = max(px - min_px, max_px)
    ... return max_px

    >>> prices = (20, 18, 14, 17, 20, 21, 15)
    >>> profit(prices)
    7

    se puede hacer esto en NumPy? Usted apuesta. Pero primero, vamos a construir un ejemplo cuasi-realista:

    # Create mostly NaN array with a few 'turning points' (local min/max).
    >>> prices = np.full(100, fill_value=np.nan)
    >>> prices[[0, 25, 60, -1]] = [80., 30., 75., 50.]

    # Linearly interpolate the missing values and add some noise.
    >>> x = np.arange(len(prices))
    >>> is_valid = ~np.isnan(prices)
    >>> prices = np.interp(x=x, xp=x[is_valid], fp=prices[is_valid])
    >>> prices += np.random.randn(len(prices)) * 2

    Aquí está el aspecto que tiene con matplotlib. El dicho es comprar barato (verde) y vender caro (rojo):

    >>> import matplotlib.pyplot as plt

    # Warning! This isn't a fully correct solution, but it works for now.
    # If the absolute min came after the absolute max, you'd have trouble.
    >>> mn = np.argmin(prices)
    >>> mx = mn + np.argmax(prices[mn:])
    >>> kwargs = {'markersize': 12, 'linestyle': ''}

    >>> fig, ax = plt.subplots()
    >>> ax.plot(prices)
    >>> ax.set_title('Price History')
    >>> ax.set_xlabel('Time')
    >>> ax.set_ylabel('Price')
    >>> ax.plot(mn, prices[mn], color='green', **kwargs)
    >>> ax.plot(mx, prices[mx], color='red', **kwargs)

    en que se ve como aplicación NumPy? Si bien no hay np.cummin () “directamente” funciones universales de NumPy (ufuncs) tienen un método acumulan () que hace lo que su nombre indica:

    >>> cummin = np.minimum.accumulate

    La extensión de la lógica del puro ejemplo en Python, se puede encontrar la diferencia entre cada precio y un mínimo en funcionamiento (elemento a elemento) , y luego tomar el máximo de esta secuencia:

    >>> def profit_with_numpy(prices):
    ... """Price minus cumulative minimum price, element-wise."""
    ... prices = np.asarray(prices)
    ... return np.max(prices - cummin(prices))

    >>> profit_with_numpy(prices)
    44.2487532293278
    >>> np.allclose(profit_with_numpy(prices), profit(prices))
    True

    ¿Cómo estas dos operaciones, que tienen la misma tiempo teórico complejidad , se comparan en tiempo de ejecución real? En primer lugar, vamos a echar una secuencia más larga. (Esto no necesariamente tiene que ser una serie temporal de precios de las acciones en este punto.)

    >>> seq = np.random.randint(0, 100, size=100000)
    >>> seq
    array([ 3, 23, 8, 67, 52, 12, 54, 72, 41, 10, ..., 46, 8, 90, 95, 93,
    28, 24, 88, 24, 49])

    Ahora, para una comparación algo injusto:

    >>> setup = ('from __main__ import profit_with_numpy, profit, seq;'
    ... ' import numpy as np')
    >>> num = 250
    >>> pytime = timeit('profit(seq)', setup=setup, number=num)
    >>> nptime = timeit('profit_with_numpy(seq)', setup=setup, number=num)
    >>> print('Speed difference: {:0.1f}x'.format(pytime / nptime))
    Speed difference: 76.0x

    Por encima, el tratamiento profit_with_numpy () como pseudocódigo (sin tener en cuenta la mecánica subyacente de NumPy), en realidad hay tres pasadas a través de una secuencia: comino

    • (precios) tiene O (n) tiempo de complejidad precios
    • - comino (precios) es O (n)
    • max (...) es O (n)

    Esto reduce a O ( n ), porque O (3 n ) se reduce a apenas O ates ( n ) -el n “domi n ”como n enfoques i n fi n dad.

    Por lo tanto, estas dos funciones tienen equivalente a tiempo peor caso . (Aunque, como nota al margen, la función NumPy viene con un número significativamente mayor complejidad espacial.) Pero eso es probablemente la comida para llevar menos importante aquí. Una lección es que, si bien la complejidad teórica de tiempo es una consideración importante, la mecánica de ejecución también pueden jugar un papel importante. No sólo puede delegar en numpy C, pero con algunas operaciones elemento a elemento y álgebra lineal, sino que también puede tomar ventaja de la informática dentro de varios subprocesos. Pero hay un montón de factores en juego aquí, incluyendo la biblioteca subyacente utilizado (BLAS / LAPACK / Atlas), y esos datos son para un conjunto ‘tro artículo completo.

    Intermezzo: Understanding Ejes Notación

    En NumPy, un eje refiere a una sola dimensión de una matriz multidimensional:

    >>> arr = np.array([[1, 2, 3],
    ... [10, 20, 30]])
    >>> arr.sum(axis=0)
    array([11, 22, 33])
    >>> arr.sum(axis=1)
    array([ 6, 60])

    La terminología alrededor de ejes y la manera en la que se describen puede ser un poco poco intuitivo. En la documentación de las pandas (una biblioteca construida en la cima de NumPy), es posible que con frecuencia ver algo como:

    eje: { 'índice' (0), 'columnas' (1)}

    Se podría argumentar que, a partir de esta descripción, los resultados anteriores deben ser “invertido”. Sin embargo, la clave es que el eje se refiere al eje largo de la cual una función se llama. Esto está bien articulado por Jake Vanderplas:

    La forma en que se especifique el eje aquí puede ser confuso para los usuarios procedentes de otros idiomas. La palabra clave eje especifica la dimensión de la matriz que se colapsó, en lugar de la dimensión que será devuelto. Así, especificando eje = 0 significa que el primer eje se derrumbó: para matrices bidimensionales, esto significa que se agregarán valores dentro de cada columna. [SOURCE]

    En otras palabras, la suma de una matriz para el eje = 0 colapsa las filas de la matriz con una columna en cuanto a cálculo .

    Con esta distinción en mente, el movimiento de let a explorar el concepto de radiodifusión.

    Radiodifusión

    Radiodifusión es otra abstracción NumPy importante. Ya hemos visto que las operaciones entre dos matrices NumPy (de igual tamaño) operan elemento a elemento :

    >>> a = np.array([1.5, 2.5, 3.5])
    >>> b = np.array([10., 5., 1.])
    >>> a / b
    array([0.15, 0.5 , 3.5 ])

    Pero, ¿qué pasa con las matrices de tamaño desigual? Aquí es donde entra en juego la radiodifusión:

    El término radiodifusión describe cómo trata a NumPy matrices con diferentes formas durante las operaciones aritméticas. Sujeto a ciertas restricciones, la matriz es más pequeña “emisión” a través de la matriz más grande para que tengan formas compatibles. Difusión proporciona un medio de vectorización de las operaciones de la matriz de modo que se produce en bucle C en vez de Python. [Fuente]

    La forma en que se implementa de radiodifusión puede llegar a ser tedioso cuando se trabaja con más de dos matrices. Sin embargo, si sólo hay dos arrays, entonces su capacidad de ser emitidos puede ser descrito con dos reglas cortos:

    Cuando se opera en dos matrices, NumPy compara sus formas elemento a elemento. Se inicia con la dimensiones arrastran y se abre camino a seguir. Dos dimensiones son compatibles cuando:

    Eso es todo lo que hay que hacer.

    Tomemos un caso donde queremos restar cada medio por columnas de una matriz, elemento a elemento:

    >>> sample = np.random.normal(loc=[2., 20.], scale=[1., 3.5],
    ... size=(3, 2))
    >>> sample
    array([[ 1.816 , 23.703 ],
    [ 2.8395, 12.2607],
    [ 3.5901, 24.2115]])

    En la jerga estadística, muestra consta de dos muestras (las columnas) dibujados de forma independiente de dos poblaciones con medio de 2 y 20, respectivamente. Los medios de columna-sabia debe aproximarse los medios de población (aunque más o menos, porque la muestra es pequeño):

    >>> mu = sample.mean(axis=0)
    >>> mu
    array([ 2.7486, 20.0584])

    Ahora, restando los medios de columna-sabia es sencillo porque las normas de radiodifusión visita:

    >>> print('sample:', sample.shape, '| means:', mu.shape)
    sample: (3, 2) | means: (2,)

    >>> sample - mu
    array([[-0.9325, 3.6446],
    [ 0.091 , -7.7977],
    [ 0.8416, 4.1531]])

    Aquí está un ejemplo de restar columna medios -wise, donde una matriz más pequeña se “estira” de modo que se resta de cada fila de la matriz más grande:

    Detalle técnica : la matriz de menor tamaño o escalar no se estira literalmente en la memoria: es el cálculo en sí que se repite.

    Esto se extiende a la normalización de cada columna, así, haciendo que cada celda de una puntuación z en relación con su respectiva columna:

    >>> (sample - sample.mean(axis=0)) / sample.std(axis=0)
    array([[-1.2825, 0.6605],
    [ 0.1251, -1.4132],
    [ 1.1574, 0.7527]])

    Sin embargo, lo que si se quiere restar, por alguna razón, los mínimos de modo de fila? Se encontrará con un poco de problemas:

    >>> sample - sample.min(axis=1)
    ValueError: operands could not be broadcast together with shapes (3,2) (3,)

    El problema aquí es que la matriz más pequeña, en su forma actual, no se puede “estirar” para estar con muestra de forma compatible. Que realmente necesita para ampliar su dimensionalidad para cumplir con las normas de radiodifusión por encima de:

    >>> sample.min(axis=1)[:, None] # 3 minimums across 3 rows
    array([[1.816 ],
    [2.8395],
    [3.5901]])

    >>> sample - sample.min(axis=1)[:, None]
    array([[ 0. , 21.887 ],
    [ 0. , 9.4212],
    [ 0. , 20.6214]])

    Nota : [:, Ninguno] es un medio por el cual para expandir la dimensionalidad de una matriz, para crear un eje de longitud uno. np.newaxis es un alias para Ninguno.

    hay algunos casos significativamente más complejos, también. He aquí una definición más rigurosa de cuando cualquier número arbitrario de matrices de cualquier forma NumPy puede transmitirse juntos:

    Un conjunto de matrices se llama “broadcastable” de la misma forma NumPy si las siguientes reglas producen un resultado válido, es decir, una de la siguiente es cierto :

    las matrices todos tienen exactamente la misma forma.

    Los arrays todos tienen el mismo número de dimensiones, y la longitud de cada dimensión es o bien una longitud común o 1.

    Las matrices que tienen muy pocas dimensiones pueden tener su NumPy shapes antepone con una dimensión de longitud 1 para satisfacer propiedad # 2.

    [fuente]

    Esto es más fácil caminar paso a paso. Digamos que usted tiene los siguientes cuatro matrices:

    >>> a = np.sin(np.arange(10)[:, None])
    >>> b = np.random.randn(1, 10)
    >>> c = np.full_like(a, 10)
    >>> d = 8

    Antes de formas de cheques, NumPy primeros convertidos a escalares matrices con un elemento:

    >>> arrays = [np.atleast_1d(arr) for arr in (a, b, c, d)]
    >>> for arr in arrays:
    ... print(arr.shape)
    ...
    (10, 1)
    (1, 10)
    (10, 1)
    (1,)

    Ahora podemos comprobar criterio # 1. Si todos los arrays tienen la misma forma, un conjunto de sus formas se condensará abajo a un elemento, porque el conjunto () constructor gotas efectivamente elementos duplicados de su entrada. Este criterio claramente no se cumple:

    >>> len(set(arr.shape for arr in arrays)) == 1
    False

    La primera parte del criterio # 2 también falla, es decir, todo el criterio de falla:

    >>> len(set((arr.ndim) for arr in arrays)) == 1
    False

    El criterio final es un poco más complicado:

    Las matrices que tienen muy pocas dimensiones pueden tener su shapes antepuesto con una dimensión de longitud 1 para satisfacer propiedad # 2.

    Para codificar esto, se puede determinar en primer lugar la dimensionalidad de la matriz de mayor dimensión y luego anteponer los a cada forma tupla NumPy hasta que todos tienen la misma dimensión:

    >>> maxdim = max(arr.ndim for arr in arrays) # Maximum dimensionality
    >>> shapes = np.array([(1,) * (maxdim - arr.ndim) + arr.shape
    ... for arr in arrays])
    >>> shapes
    array([[10, 1],
    [ 1, 10],
    [10, 1],
    [ 1, 1]])

    Por último, es necesario prueba que la longitud de cada dimensión o bien está (extraída de) una longitud común, o 1 . Un truco para hacer esto es para enmascarar primero la matriz de NumPy “forma-tuplas” en lugares donde igual a uno. A continuación, se puede comprobar si las diferencias en cuanto a las columnas de pico a pico (np.ptp ()) son todos cero:

    >>> masked = np.ma.masked_where(shapes == 1, shapes)
    >>> np.all(masked.ptp(axis=0) == 0) # ptp: max - min
    True

    encapsulado en una sola función, esta lógica es similar al siguiente:

    >>> def can_broadcast(*arrays) -> bool:
    ... arrays = [np.atleast_1d(arr) for arr in arrays]
    ... if len(set(arr.shape for arr in arrays)) == 1:
    ... return True
    ... if len(set((arr.ndim) for arr in arrays)) == 1:
    ... return True
    ... maxdim = max(arr.ndim for arr in arrays)
    ... shapes = np.array([(1,) * (maxdim - arr.ndim) + arr.shape
    ... for arr in arrays])
    ... masked = np.ma.masked_where(shapes == 1, shapes)
    ... return np.all(masked.ptp(axis=0) == 0)
    ...
    >>> can_broadcast(a, b, c, d)
    True

    Por suerte, se puede tomar un acceso directo y el uso np.broadcast () para este cordura-cheque, aunque no está explícitamente diseñado para este propósito:

    >>> def can_broadcast(*arrays) -> bool:
    ... try:
    ... np.broadcast(*arrays)
    ... return True
    ... except ValueError:
    ... return False
    ...
    >>> can_broadcast(a, b, c, d)
    True

    para los interesados ​​en excavar un poco más profundo, PyArray_Broadcast es la función subyacente C que encapsula la difusión de normas.

    Programación matriz en Acción: Ejemplos

    En los 3 ejemplos siguientes, se le puso la vectorización y la difusión de trabajar con algunas aplicaciones del mundo real. La agrupación de aprendizaje

    Algoritmos

    Máquina es un dominio que puede tomar ventaja de vectorización frecuencia y la radiodifusión. Digamos que usted tiene los vértices de un triángulo (cada fila es un X, Y de coordenadas):

    >>> tri = np.array([[1, 1],
    ... [3, 1],
    ... [2, 3]])

    el centro de gravedad de este “grupo” es un (x, y) coordenada que es la media aritmética de cada uno columna:

    >>> centroid = tri.mean(axis=0)
    >>> centroid
    array([2. , 1.6667])

    Es útil para visualizar esto:

    >>> trishape = plt.Polygon(tri, edgecolor='r', alpha=0.2, lw=5)
    >>> _, ax = plt.subplots(figsize=(4, 4))
    >>> ax.add_patch(trishape)
    >>> ax.set_ylim([.5, 3.5])
    >>> ax.set_xlim([.5, 3.5])
    >>> ax.scatter(*centroid, color='g', marker='D', s=70)
    >>> ax.scatter(*tri.T, color='b', s=70)

    Muchos algoritmos de agrupamiento hacen uso de las distancias euclidianas de una colección de puntos, ya sea al origen o en relación con sus centroides. coordenadas

    En cartesianas, la distancia euclídea entre p UNTOS p y q es:

    [Fuente: Wikipedia]

    Así que para el conjunto de coordenadas en tres de arriba, la distancia euclídea de cada punto desde el origen (0, 0) sería:

    >>> np.sum(tri**2, axis=1) ** 0.5 # Or: np.sqrt(np.sum(np.square(tri), 1))
    array([1.4142, 3.1623, 3.6056])

    es posible que reconocer que estamos realmente sólo encontrar normas euclidianas:

    >>> np.linalg.norm(tri, axis=1)
    array([1.4142, 3.1623, 3.6056])

    lugar de hacer referencia al origen, también se puede encontrar en la norma de cada punto con respecto a la década de triángulo centroide:

    >>> np.linalg.norm(tri - centroid, axis=1)
    array([1.2019, 1.2019, 1.3333])

    Por último, vamos a llevar esto un paso más allá: Digamos que tiene una matriz 2D X y una matriz 2D de múltiples (x, y) “propuesta” centroides. Algoritmos tales como K-means clustering trabajo mediante la asignación al azar inicial “proponen” centroides, a continuación, la reasignación de cada punto de datos para su centroide más cercano. A partir de ahí, los nuevos centroides se calculan, con el algoritmo converge en una solución una vez que las etiquetas de re-generado (una codificación de los centroides) son sin cambios entre iteraciones. Una parte de este proceso iterativo requiere calcular la distancia euclídea de cada punto de cada centroide :

    >>> X = np.repeat([[5, 5], [10, 10]], [5, 5], axis=0)
    >>> X = X + np.random.randn(*X.shape) # 2 distinct "blobs"
    >>> centroids = np.array([[5, 5], [10, 10]])

    >>> X
    array([[ 3.3955, 3.682 ],
    [ 5.9224, 5.785 ],
    [ 5.9087, 4.5986],
    [ 6.5796, 3.8713],
    [ 3.8488, 6.7029],
    [10.1698, 9.2887],
    [10.1789, 9.8801],
    [ 7.8885, 8.7014],
    [ 8.6206, 8.2016],
    [ 8.851 , 10.0091]])

    >>> centroids
    array([[ 5, 5],
    [10, 10]])

    En otras palabras, queremos responder a la pregunta, a la que centroide hace cada punto dentro de X pertenecen ? Tenemos que hacer algo de remodelación para permitir la difusión de aquí, con el fin de calcular la distancia euclídea entre cada punto en X y cada punto de centroides :

    >>> centroids[:, None]
    array([[[ 5, 5]],

    [[10, 10]]])

    >>> centroids[:, None].shape
    (2, 1, 2)

    Esto nos permite restar limpiamente una matriz de otro usando un producto combinatorio de sus filas :

    >>> np.linalg.norm(X - centroids[:, None], axis=2).round(2)
    array([[2.08, 1.21, 0.99, 1.94, 2.06, 6.72, 7.12, 4.7 , 4.83, 6.32],
    [9.14, 5.86, 6.78, 7.02, 6.98, 0.73, 0.22, 2.48, 2.27, 1.15]])

    En otras palabras, la forma NumPy de X - centroides [:, Ninguno] es (2, 10, 2), que representan esencialmente dos matrices apiladas que son cada uno el tamaño de X. a continuación, queremos que el etiqueta (número de índice) de cada centroide más cercano, la búsqueda de la distancia mínima en el eje 0 ª de la matriz anterior:

    >>> np.argmin(np.linalg.norm(X - centroids[:, None], axis=2), axis=0)
    array([0, 0, 0, 0, 0, 1, 1, 1, 1, 1])

    Usted puede poner todo esto junto en forma funcional: de

    >>> def get_labels(X, centroids) -> np.ndarray:
    ... return np.argmin(np.linalg.norm(X - centroids[:, None], axis=2),
    ... axis=0)
    >>> labels = get_labels(X, centroids)

    Let inspeccionan esto visualmente, el trazado tanto los dos clusters y sus etiquetas asignadas con un color de mapeo:

    >>> c1, c2 = ['#bc13fe', '#be0119'] # https://xkcd.com/color/rgb/
    >>> llim, ulim = np.trunc([X.min() * 0.9, X.max() * 1.1])

    >>> _, ax = plt.subplots(figsize=(5, 5))
    >>> ax.scatter(*X.T, c=np.where(labels, c2, c1), alpha=0.4, s=80)
    >>> ax.scatter(*centroids.T, c=[c1, c2], marker='s', s=95,
    ... edgecolor='yellow')
    >>> ax.set_ylim([llim, ulim])
    >>> ax.set_xlim([llim, ulim])
    >>> ax.set_title('One K-Means Iteration: Predicted Classes')

    tablas de amortización

    vectorización tiene aplicaciones en las finanzas también.

    Dada una tasa anual de interés, frecuencia de pago (veces por año), el equilibrio inicial del préstamo, y el plazo del préstamo, puede crear una tabla de amortización con saldos de préstamos y pagos mensuales, de una forma vectorizada. conjunto de Let algunas constantes escalares primera:

    >>> freq = 12 # 12 months per year
    >>> rate = .0675 # 6.75% annualized
    >>> nper = 30 # 30 years
    >>> pv = 200000 # Loan face value

    >>> rate /= freq # Monthly basis
    >>> nper *= freq # 360 months

    NumPy viene precargado con un puñado de funciones financieras que, a diferencia de sus primos de Excel, son capaces de producir salidas de vectores.

    El deudor (o arrendatario) paga una cantidad mensual constante que se compone de un componente principal e intereses. A medida que el saldo pendiente del préstamo disminuye, la parte del interés del pago total disminuye con él.

    >>> periods = np.arange(1, nper + 1, dtype=int)
    >>> principal = np.ppmt(rate, periods, nper, pv)
    >>> interest = np.ipmt(rate, periods, nper, pv)
    >>> pmt = principal + interest # Or: pmt = np.pmt(rate, nper, pv)

    A continuación, te nee d para calcular un balance mensual, tanto ante un d después del pago de ese mes, que puede ser d efinir d como el valor futuro del saldo original menos el futuro valor de una anualidad (un flujo de pagos), utilizando un factor de iscount d d :

    Funcionalmente, esto se parece a:

    >>> def balance(pv, rate, nper, pmt) -> np.ndarray:
    ... d = (1 + rate) ** nper # Discount factor
    ... return pv * d - pmt * (d - 1) / rate

    por último, se puede dejar esto en un formato tabular con una de las pandas trama de datos . Tenga cuidado con los signos aquí. PMT es una salida desde la perspectiva del deudor.

    >>> import pandas as pd

    >>> cols = ['beg_bal', 'prin', 'interest', 'end_bal']
    >>> data = [balance(pv, rate, periods - 1, -pmt),
    ... principal,
    ... interest,
    ... balance(pv, rate, periods, -pmt)]

    >>> table = pd.DataFrame(data, columns=periods, index=cols).T
    >>> table.index.name = 'month'

    >>> with pd.option_context('display.max_rows', 6):
    ... # Note: Using floats for $$ in production-level code = bad
    ... print(table.round(2))
    ...
    beg_bal prin interest end_bal
    month
    1 200000.00 -172.20 -1125.00 199827.80
    2 199827.80 -173.16 -1124.03 199654.64
    3 199654.64 -174.14 -1123.06 199480.50
    ... ... ... ... ...
    358 3848.22 -1275.55 -21.65 2572.67
    359 2572.67 -1282.72 -14.47 1289.94
    360 1289.94 -1289.94 -7.26 -0.00

    Al final del año 30, el préstamo se paga:

    >>> final_month = periods[-1]
    >>> np.allclose(table.loc[final_month, 'end_bal'], 0)
    True

    Nota : Durante el uso de flotadores para representar el dinero puede ser útil para la ilustración del concepto en un entorno de programación, usando Python flota para los cálculos financieros en un entorno de producción podría hacer que su cálculo sea un centavo o dos en algunos casos.

    Imagen de extracción de características

    En un último ejemplo, vamos a trabajar con una imagen de octubre de 1941 el USS Lexington (CV-2), los restos del que fue descubierto frente a la costa de Australia en 2018. de marzo de primer lugar, podemos mapa de la imagen en una matriz de NumPy de sus valores de píxeles:

    >>> from skimage import io

    >>> url = ('https://www.history.navy.mil/bin/imageDownload?image=/'
    ... 'content/dam
    hhc/our-collections/photography/images/'
    ... '80-G-410000/80-G-416362&rendition=cq5dam.thumbnail.319.319.png')
    >>> img = io.imread(url, as_grey=True)

    >>> fig, ax = plt.subplots()
    >>> ax.imshow(img, cmap='gray')
    >>> ax.grid(False)

    Por razones de simplicidad, la imagen se carga en escala de grises, lo que resulta en una matriz 2D de 64 bits flota en lugar de una matriz MxNx4 RGBA 3-dimensional , con valores más bajos denotan manchas más oscuras:

    >>> img.shape
    (254, 319)

    >>> img.min(), img.max()
    (0.027450980392156862, 1.0)

    >>> img[0, :10] # First ten cells of the first row
    array([0.8078, 0.7961, 0.7804, 0.7882, 0.7961, 0.8078, 0.8039, 0.7922,
    0.7961, 0.7961])
    >>> img[-1, -10:] # Last ten cells of the last row
    array([0.0784, 0.0784, 0.0706, 0.0706, 0.0745, 0.0706, 0.0745, 0.0784,
    0.0784, 0.0824])

    una técnica comúnmente empleados como un paso intermedio en el análisis de imagen es extracción parche . Como su nombre indica, este consiste en extraer más pequeños superpuestos submatrices de una matriz más grande y puede ser utilizado en casos en los que es ventajoso “eliminación de ruido” o desenfocar una imagen.

    Este concepto se extiende a otros campos, también. Por ejemplo, sería hacer algo similar mediante la adopción de “rodar” ventanas de una serie de tiempo con múltiples características (variables). Es incluso útil para la construcción de Juego de la vida. (Aunque, con un núcleo de convolución 3x3 es un enfoque más directo.)

    Aquí, vamos a encontrar la significa la superposición de cada parche de 10x10 dentro img. Tomando un ejemplo en miniatura, el primer grupo de parches 3x3 en la esquina superior izquierda de img sería:

    >>> img[:3, :3]
    array([[0.8078, 0.7961, 0.7804],
    [0.8039, 0.8157, 0.8078],
    [0.7882, 0.8 , 0.7961]])

    >>> img[:3, :3].mean()
    0.7995642701525054

    El enfoque puro-Python a la creación de parches de deslizamiento implicaría un para-bucle anidado. Que había necesidad de tener en cuenta que el índice a partir de los parches más a la derecha estará en el índice n - 3 + 1, donde n es el ancho de la matriz. En otras palabras, si estuviera extrayendo parches 3x3 a partir de una matriz llamada 10x10 arr, el último parche sería tomada desde arr [07:10, 07:10]. También hay que tener en cuenta que la gama de Python () no incluye su parámetro de parada:

    >>> size = 10
    >>> m, n = img.shape
    >>> mm, nn = m - size + 1, n - size + 1
    >>>
    >>> patch_means = np.empty((mm, nn))
    >>> for i in range(mm):
    ... for j in range(nn):
    ... patch_means[i, j] = img[i: i+size, j: j+size].mean()

    >>> fig, ax = plt.subplots()
    >>> ax.imshow(patch_means, cmap='gray')
    >>> ax.grid(False)

    Con este bucle, que está realizando una gran cantidad de llamadas de Python.

    Una alternativa que sea escalable para ampliar la imagen RGB o RGBA es stride_tricks de NumPy.

    Un primer paso instructivo es visualizar, dado el tamaño del parche y la forma de la imagen, lo que es una matriz de dimensiones superiores de los parches se vería así. Tenemos un img matriz 2D con forma (254, 319) y una (10, 10) patch 2d. Esto significa que nuestra forma de salida (antes de tomar la media de cada 10x10 matriz “interior”) sería:

    >>> shape = (img.shape[0] - size + 1, img.shape[1] - size + 1, size, size)
    >>> shape
    (245, 310, 10, 10)

    También es necesario especificar el pasos de la nueva matriz. de una matriz pasos es una tupla de bytes para saltar en cada dimensión cuando se mueve a lo largo de la matriz. Cada píxel en img es un flotador 64 bits (8 bytes), es decir, el tamaño total de la imagen se 254 x 319 x 8 = 648208 bytes.

    >>> img.dtype
    dtype('float64')

    >>> img.nbytes
    648208

    Internamente, img se mantiene en la memoria como un bloque contiguo de 648,208 bytes. pasos es, por tanto, una especie de “metadatos” -como atributo que nos indica la cantidad de bytes que necesitamos dar un salto adelante para pasar a la siguiente posición largo de cada eje . Nos movemos en bloques de 8 bytes a lo largo de las filas, pero necesidad de atravesar 8 x 319 = 2552 bytes para moverse “hacia abajo” de una fila a otra.

    >>> img.strides
    (2552, 8)

    En nuestro caso, los pasos de los parches resultantes solo se repetirán los pasos de img dos veces:

    >>> strides = 2 * img.strides
    >>> strides
    (2552, 8, 2552, 8)

    Ahora, vamos a poner estas piezas juntas con stride_tricks de NumPy:

    >>> from numpy.lib import stride_tricks

    >>> patches = stride_tricks.as_strided(img, shape=shape, strides=strides)
    >>> patches.shape
    (245, 310, 10, 10)

    Aquí está el primer parche 10x10 :

    >>> patches[0, 0].round(2)
    array([[0.81, 0.8 , 0.78, 0.79, 0.8 , 0.81, 0.8 , 0.79, 0.8 , 0.8 ],
    [0.8 , 0.82, 0.81, 0.79, 0.79, 0.79, 0.78, 0.81, 0.81, 0.8 ],
    [0.79, 0.8 , 0.8 , 0.79, 0.8 , 0.8 , 0.82, 0.83, 0.79, 0.81],
    [0.8 , 0.79, 0.81, 0.81, 0.8 , 0.8 , 0.78, 0.76, 0.8 , 0.79],
    [0.78, 0.8 , 0.8 , 0.78, 0.8 , 0.79, 0.78, 0.78, 0.79, 0.79],
    [0.8 , 0.8 , 0.78, 0.78, 0.78, 0.8 , 0.8 , 0.8 , 0.81, 0.79],
    [0.78, 0.77, 0.78, 0.76, 0.77, 0.8 , 0.8 , 0.77, 0.8 , 0.8 ],
    [0.79, 0.76, 0.77, 0.78, 0.77, 0.77, 0.79, 0.78, 0.77, 0.76],
    [0.78, 0.75, 0.76, 0.76, 0.73, 0.75, 0.78, 0.76, 0.77, 0.77],
    [0.78, 0.79, 0.78, 0.78, 0.78, 0.78, 0.77, 0.76, 0.77, 0.77]])

    el último paso es complicado. Para obtener una media vectorizado de cada matriz interior 10x10 , tenemos que pensar cuidadosamente acerca de la dimensionalidad de lo que tenemos ahora. El resultado debe colapsar las últimas dos dimensiones por lo que nos quedamos con una sola matriz 245x310 .

    One (subóptima) forma sería la de parches reshape primero, aplanando los arrays 2D interiores a la longitud-100 vectores, y luego calculando la media sobre el eje final:

    >>> veclen = size ** 2
    >>> patches.reshape(*patches.shape[:2], veclen).mean(axis=-1).shape
    (245, 310)

    Sin embargo, también puede especificar eje como una tupla, informática una media en las últimas dos ejes, que deberían ser más eficiente que la remodelación: maquillaje de

    >>> patches.mean(axis=(-1, -2)).shape
    (245, 310)

    Let seguro de que esto comprueba mediante la comparación de igualdad a nuestra versión en bucle. Que hace:

    >>> strided_means = patches.mean(axis=(-1, -2))
    >>> np.allclose(patch_means, strided_means)
    True

    Si el concepto de pasos que tiene babeo, no se preocupe: scikit-learn ya ha encajado muy bien todo este proceso dentro de su módulo de feature_extraction.

    un pensamiento de despedida: No se exceda en Optimizar

    En este artículo, se discute la optimización en tiempo de ejecución mediante el aprovechamiento de la programación de matriz en NumPy. Cuando se trabaja con grandes conjuntos de datos, es importante ser consciente de microperformance.

    Sin embargo, hay un subconjunto de casos en los que evitar una nativa de Python para el bucle no es posible. Como aconsejó Donald Knuth, “La optimización prematura es la raíz de todo mal”. Los programadores pueden predecir de forma incorrecta, donde en su código aparecerá un cuello de botella, de pasar horas tratando de vectorizar totalmente una operación que daría lugar a una mejora relativamente insignificante en tiempo de ejecución.

    No hay nada malo con fines de bucles roció aquí y allá. A menudo, puede ser más productivo pensar en vez acerca de cómo optimizar el flujo y la estructura de toda la secuencia de comandos en un nivel más alto de abstracción.

    Más Recursos adicionales

    gratuito: Haga clic aquí para obtener acceso a una Guía de Recursos libre NumPy que señala al los mejores tutoriales, videos y libros para mejorar sus habilidades NumPy.

    NumPy Documentación:

    • ¿Cuál es NumPy? funciones
    • Radiodifusión
    • Universal
    • NumPy para los usuarios de MATLAB
    • El índice completo NumPy Referencia

    Libros: Guía del

    • Travis Oliphant a NumPy, 2ª ed. (Travis es el creador principal de NumPy)
    • Capítulo 2 ( “Introducción a NumPy”) de Jake Vanderplas' Python Data Science Handbook
    • Capítulo 4 ( ‘NumPy Fundamentos’) y en el capítulo 12 ( ‘Advanced NumPy’) de Wes McKinney pitón de Análisis de datos 2ª ed.
    • Capítulo 2 ( “Los matemáticos bloques de construcción de redes neuronales”) de Aprendizaje de François Chollet profundo con Python
    • Robert Johansson Numerical Python
    • Ivan Idris: Guía del Principiante Numpy, 3ª ed.

    Otros Recursos:

    • Wikipedia: Array Programming
    • SciPy Lecture Notes: básico y avanzado NumPy
    • EricsBroadcastingDoc: Array Radiodifusión en NumPy
    • SciPy Cookbook: Vistas frente a copias en NumPy
    • Nicolas Rougier: A partir de Python a Numpy y 100 NumPy Ejercicios docs
    • TensorFlow: docs Radiodifusión Semántica
    • Theano: Radiodifusión
    • Eli Bendersky: Radiodifusión Arrays en Numpy
    Categorías
    Python

    Pensando de forma recursiva en Python

     

    Tabla de Contenidos

    • Comparando Idiomas: Python vs C ++
    • Compilación vs Virtual Machine
    • Sintaxis DifferencesWhitespaceBoolean ExpressionsVariables y de PointersComprehensionsPython std :: algoritmos variables
    • espacios en blanco
    • Expresiones booleanas
    • y std Punteros
    • de comprensión
    • de Python: : algoritmos
    • estático vs dinámico TypingStatic TypingDuck TypingTemplatesType Comprobación
    • establecimiento de tipos estáticos
    • Duck Typing
    • plantillas
    • Tipo Comprobación
    • orientada a objetos ProgrammingSimilaritiesDifferencesOperator sobrecargas vs Diferencias Métodos Dunder
    • Similitudes
    • sobrecargas de operadores vs Métodos Dunder
    • memoria ManagementReference Contando basura CollectorGenerational CollectorWhen usted no quiere Garbage Collection
    • de referencia de conteo del colector de basura generacional
    • C ollector
    • cuando no lo hacen ¿Quieres Garbage Collection
    • roscar, multiprocesamiento, y asíncrono IOThreadingMultiprocessingAsync IO
    • Threading de
    • multiprocesamiento
    • asíncrono IO
    • Varios Problemas
    • Resumen: Python vs C ++
    • Conclusión
    • espacios en blanco Variables
    • Expresiones booleanas
    • y std Punteros
    • de comprensión
    • de Python :: algoritmos
    • establecimiento de tipos estáticos
    • Duck Typing
    • plantillas
    • Tipo Comprobación diferencias
    • Similitudes
    • sobrecargas de operadores vs Dunder Contar métodos
    • Referencia colector
    • generacional del colector de basura
    • cuando no lo desea Garbage Collection
    • Threading de
    • multiprocesamiento
    • asíncrono IO

    son yo u a ++ desarrollador C comparando Python vs C ++? ¿Está buscando en Python y preguntando lo que todo el alboroto? ¿Se pregunta cómo Python se compara con los conceptos que ya conoce? O tal vez usted tiene una apuesta sobre quién ganaría si bloqueado C ++ y Python en una jaula y dejar que ellos se enfrentarán? ¡Entonces este articulo es para usted!

    En este artículo, usted aprenderá acerca de : Diferencias

    • y similitudes cuando se está comparando Python vs C ++
    • Momentos en Python puede ser una mejor opción para un problema y viceversa Recursos
    • a su vez a y cuando usted tiene preguntas mientras que el aprendizaje de Python

    Este artículo está dirigido a los desarrolladores de C ++ que están aprendiendo Python. Se asume un conocimiento básico de los dos idiomas y utilizará conceptos desde Python 3.6 y superiores, así como C ++ 11 o posterior. buceo de

    Let en la mirada de Python vs C ++! Bono

    gratuito: Haga clic aquí para obtener acceso a un capítulo de trucos Python: El libro que te muestra las mejores prácticas de Python con ejemplos sencillos puede aplicar instantáneamente a escribir código más bonito + Pythonic.

    Comparando Idiomas: Python vs C ++

    frecuentes, encontrará artículos que exaltan las virtudes de un lenguaje de programación sobre otro. Muy a menudo, se delegan en los esfuerzos para promover una lengua mediante la degradación de la otra. Esto no es ese tipo de artículo.

    Cuando usted está comparando Python vs C ++, recordar que los dos son herramientas, y ambos tienen usos para diferentes problemas. Piense en la comparación de un martillo y un destornillador. Usted podría utilizar un destornillador para conducir en las uñas, y usted podría utilizar un martillo para la fuerza de tornillos, pero ni experiencia será del todo eficaz.

    Usando la herramienta adecuada para el trabajo es importante. En este artículo, usted aprenderá acerca de las características de Python y C ++ que hacen que cada uno de ellos la elección correcta para ciertos tipos de problemas. Por lo tanto, no ver el “vs” en Python vs C ++ en el sentido de “en contra”. Por el contrario, pensar en ella como una comparación.

    Compilación vs inicio de la máquina virtual

    Vamos con la mayor diferencia cuando se está comparando Python vs C ++. En C ++, se utiliza un compilador que convierte el código fuente en código máquina y produce un archivo ejecutable. El ejecutable es un archivo independiente que luego se puede ejecutar como un programa autónomo:

    Este proceso salidas instrucciones reales de la máquina para el procesador y el sistema operativo que está construido para. En este dibujo, que es un programa de Windows. Esto significa que tendrías que volver a compilar el programa por separado para Windows, Mac y Linux:

    Es probable que necesita modificar su código C ++ para ejecutarse en los diferentes sistemas.

    Python, por el contrario, utiliza un proceso diferente. Ahora, recuerde que se le busca en CPython que es la implementación estándar para el idioma. A menos que usted está haciendo algo especial, este es el pitón que se está ejecutando.

    Python se ejecuta cada vez que se ejecuta el programa. Se compila su fuente al igual que el compilador de C ++. La diferencia es que Python compila a código de bytes en lugar de código máquina nativo. Código de bytes es el código de instrucciones nativas para la máquina virtual de Python. Para acelerar las ejecuciones posteriores de su programa, tiendas de Python el código de bytes en archivos .pyc:

    Si está utilizando Python 2, a continuación, encontrará estos archivos junto a los archivos .py. Para Python 3, se encuentra en un directorio __pycache__.

    El código de bytes generada no se ejecuta de forma nativa en su procesador. En su lugar, es dirigido por la máquina virtual de Python. Esto es similar a la máquina virtual Java o .NET Runtime Environment Común. La ejecución inicial de su código resultará en un paso de compilación. A continuación, el código de bytes será interpretada para ejecutarse en su hardware específico:

    Mientras que el programa no se ha cambiado, cada ejecución posterior se saltará el paso de compilación y utilizar el código de bytes previamente compilado de interpretar:

    código

    Interpretación va a ser más lenta que la ejecución de código nativo directamente en el hardware. Entonces, ¿por qué Python funciona de esa manera? Pues bien, interpretar el código en un medio de máquinas virtuales que sólo las necesidades de la máquina virtual que deberán elaborarse de un sistema operativo específico en un procesador específico. Todo el código Python se ejecuta se pueden ejecutar en cualquier máquina que tenga Python.

    Nota: CPython está escrito en C, por lo que puede funcionar en la mayoría de los sistemas que tienen un compilador C.

    Otra característica de este soporte multiplataforma que es extensa biblioteca estándar de Python se escribe en el trabajo en todos los sistemas operativos.

    Usando pathlib, por ejemplo, se encargará de separadores de ruta para que si estás en Windows, Mac, o Linux. Los desarrolladores de esas bibliotecas pasaron mucho tiempo por lo que es portátil, por lo que no es necesario preocuparse por ello en su programa de Python!

    Antes de continuar, vamos a empezar a hacer el seguimiento de un Python vs C ++ tabla de comparación. Y cuando cubra nuevas comparaciones, se añadirán en cursiva:

    Ahora que usted ha visto las diferencias en tiempo de ejecución cuando se está comparando Python vs C ++, vamos a profundizar en los detalles de la sintaxis de los lenguajes. Diferencias

    sintaxis

    Python y C ++ comparten muchas similitudes sintácticas, pero no discutimos algunas áreas vale la pena:

    • espacios en blanco
    • booleanas expresiones variables
    • y punteros de inicio
    • de comprensión

    Vamos con el más polémico primera : espacio en blanco. Los espacios en blanco

    Lo primero que la mayoría de los desarrolladores de aviso cuando se comparan Python vs C ++ es el “problema de espacio en blanco.” Python usa el espacio en blanco que conduce al alcance marca. Esto significa que el cuerpo de un bloque si u otra estructura similar se indica por el nivel de indentación. C ++ utiliza llaves ({}) para indicar la misma idea.

    Mientras que el analizador léxico Python aceptará cualquier espacio en blanco, siempre y cuando eres consistente, PEP8 (la guía de estilo oficial para Python) especifica 4 espacios para cada nivel de sangría. La mayoría de los editores se pueden configurar para hacer esto automáticamente.

    Ha habido una enorme cantidad de escritos, gritando y vociferando acerca de las reglas de espacio en blanco de Python ya, así que vamos a saltar más allá de esa cuestión y a otros asuntos.

    En lugar de confiar en un marcador léxica similares; al final de cada declaración, Python usa el final de la línea. Si necesita extender una declaración sobre una sola línea, a continuación, puede utilizar la barra invertida (\) para indicar que. (Tenga en cuenta que si usted está dentro de un conjunto de paréntesis, a continuación, no es necesario el carácter de continuación.)

    Hay personas que no están conformes a ambos lados de la cuestión de espacio en blanco. Algunos desarrolladores de Python el amor que usted no tiene que escribir los apoyos y puntos y comas. Algunos desarrolladores de C ++ odian la dependencia de formateo. Aprender a ser cómodo con ambos es la mejor opción.

    Ahora que ha contemplado el tema de espacio en blanco, vamos a pasar a uno que es un poco menos polémico: expresiones booleanas.

    Expresiones booleanas

    La forma en que vamos a usar expresiones booleanas cambia ligeramente en Python vs C ++. En C ++, puede utilizar valores numéricos para indicar verdadero o falso, además de la incorporada en valores. Cualquier cosa que se evalúa como 0 se considera falsa, mientras que cualquier otro valor numérico es cierto.

    Python tiene un concepto similar, pero se extiende para incluir otros casos. Los fundamentos son bastante similares. Los estados de documentación Python que los siguientes elementos se evalúan a False:

    • Constantes define como falsa: NoneFalse
    • Ninguno
    • False
    • ceros de cualquier tipo numérico: 00.00jDecimal (0) Fracción (0, 1)
    • 0
    • 0,0
    • 0j
    • decimal (0) Fracción
    • (0, 1) secuencias y colecciones vacíos
    • : » () [] {} set () rango (0)
    • »
    • ()
    • []
    • {} conjunto
    • () rango de
    • (0)
    • Ninguno
    • False
    • 0
    • 0,0
    • 0j
    • decimal (0)
    • Fracción (0, 1 )
    • »
    • ()
    • [] {}
    • conjunto
    • () rango de
    • (0)

    Todos los demás elementos son ciertas. Esto significa que una lista vacía [] es falsa, mientras que una lista que contiene sólo cero [0] sigue siendo cierto.

    mayoría de los objetos será evaluada como verdadera, a menos que el objeto tiene __bool __ () que devuelve Falso o __len __ () que devuelve 0. Esto le permite extender sus clases personalizadas para actuar como expresiones booleanas.

    Python tiene algunos ligeros cambios de C ++ en los operadores booleanos también. Para empezar, si y mientras los estados no requieren los paréntesis que rodean como lo hacen en C ++. Los paréntesis pueden ayudar a facilitar la lectura, sin embargo, a fin de utilizar su mejor juicio. operadores

    La mayor parte de C ++ booleanas tienen los operadores similares en Python:

    La mayoría de los operadores son similares a C ++, pero si quieres repasar que pueden leer los operadores y expresiones en Python. Variables y punteros

    Cuando use por primera vez después de escribir Python en C ++, no se podrían dar las variables mucho pensamiento. Parece que en general el trabajo como lo hacen en C ++. Sin embargo, no son lo mismo. Mientras que en C ++ utiliza variables con valores de referencia, en Python utiliza nombres.

    Nota: Para esta sección, en la que está buscando en las variables y nombres en Python vs C ++, va a utilizar las variables para C ++ y nombres para Python. En otras partes, los dos se llaman variables .

    En primer lugar, vamos a retroceder un poco y tomar una mirada más amplia a modelo de objetos de Python.

    En Python, todo es un objeto. Los números se llevan a cabo en los objetos. Los módulos se llevan a cabo en los objetos. Tanto el objeto de una clase y la propia clase son objetos. Las funciones son también objetos:

    >>> a_list_object = list()
    >>> a_list_object
    []
    >>> a_class_object = list
    >>> a_class_object

    >>> def sayHi(name):
    ... print(f'Hello, {name}')
    ...
    >>> a_function_object = sayHi
    >>> a_function_object

    lista de llamadas () crea un nuevo objeto de la lista, que se asigna a a_list_object. Usando el nombre de la lista de clase por sí mismo coloca una etiqueta en el objeto de clase. Puede colocar una nueva etiqueta en función también. Esta es una herramienta potente y, como todas las herramientas de gran alcance, que puede ser peligroso. (Estoy mirando a ti, señor de la motosierra.)

    Nota: “Lea, Eval, Imprimir Loop” El código anterior se muestra corriendo en un REPL, lo que significa Este entorno interactivo se utiliza con frecuencia para probar las ideas en Python y otros lenguajes interpretados.

    Si escribe pitón en un símbolo del sistema, a continuación, se abrirá una REPL donde se puede empezar a escribir en código y probar cosas por ti mismo!

    Volviendo a la discusión de Python vs C ++, nota que este es el comportamiento es diferente de lo que verá en C ++. A diferencia de Python, C ++ tiene variables que se asignan a una posición de memoria, y usted debe indicar la cantidad de memoria que utilizará la variable:

    int an_int;
    float a_big_array_of_floats[REALLY_BIG_NUMBER];

    En Python, todos los objetos se crean en la memoria, y aplicar etiquetas a ellos. Las etiquetas en sí mismas no tienen tipos, y se pueden poner en cualquier tipo de objeto:

    >>> my_flexible_name = 1
    >>> my_flexible_name
    1
    >>> my_flexible_name = 'This is a string'
    >>> my_flexible_name
    'This is a string'
    >>> my_flexible_name = [3, 'more info', 3.26]
    >>> my_flexible_name
    [3, 'more info', 3.26]
    >>> my_flexible_name = print
    >>> my_flexible_name

    Puede asignar my_flexible_name a cualquier tipo de objeto, y Python se acaba de rodar con él.

    Cuando usted está comparando Python vs C ++, la diferencia en las variables vs nombres puede ser un poco confuso, pero viene con algunos excelentes beneficios. Una es que en Python no tiene punteros, y que nunca es necesario pensar en el montón vs cuestiones pila. Vas a sumergirse en la gestión de memoria un poco más adelante en este artículo.

    de comprensión

    Python tiene una función de lenguaje llamado listas por comprensión . Si bien es posible emular la lista por comprensión en C ++, que es bastante complicado. En Python, que son una herramienta básica que se enseña a los programadores principiantes.

    Una manera de pensar acerca de las listas por comprensión es que son como un super-cargado inicializador para listas, predice, o conjuntos. Dado un objeto iterable, puede crear una lista, y el filtro o modificar el original mientras lo hace:

    >>> [x**2 for x in range(5)]
    [0, 1, 4, 9, 16]

    Este script se inicia con la gama iterable (5) y crea una lista que contiene el cuadrado de cada elemento en el iterable.

    de posible para añadir condiciones a los valores en la primera iterable:

    >>> odd_squares = [x**2 for x in range(5) if x % 2]
    >>> odd_squares
    [1, 9]

    El si x% 2 al final de esta comprensión limita los números usados ​​de la gama de (5) a sólo los impares.

    En este punto usted podría estar teniendo dos pensamientos:

    Si bien es cierto que se puede crear un vector de los cuadrados de los números impares en C ++, haciendo así que por lo general significa un código de poco más:

    std::vector odd_squares;
    for (int ii = 0; ii < 10; ++ii) { if (ii % 2) { odd_squares.push_back(ii*ii); } }

    Para los desarrolladores que vienen de C al estilo de idiomas, listas por comprensión son una de las primeras formas notables que pueden escribir un código más Pythonic. Muchos desarrolladores de Python comienzan a escribir con la estructura C ++:

    odd_squares = []
    for ii in range(5):
    if (ii % 2):
    odd_squares.append(ii)

    Esto es perfectamente válida en Python. Es probable que se ejecutará más lentamente, sin embargo, y no es tan claro y conciso como la lista de comprensión. Aprender a usar las listas por comprensión no sólo acelerar su código, pero también hará que su código sea más Pythonic y más fácil de leer!

    Nota: Cuando estás leyendo sobre Python, que con frecuencia verá la palabra Pythonic utiliza para describir algo. Esto es sólo un término de la comunidad utiliza para describir el código que es limpio, elegante y parece que fue escrito por un Jedi Python. de

    Python std :: algoritmos

    C ++ tiene un rico conjunto de algoritmos incorporados en la biblioteca estándar. Python tiene un conjunto similar de funciones integradas que cubren el mismo terreno.

    El primero y más poderoso de todos ellos es el de operador, lo que proporciona una prueba bastante legible para ver si un artículo está incluido en una lista, conjunto o diccionario:

    >>> x = [1, 3, 6, 193]
    >>> 6 in x
    True
    >>> 7 in x
    False
    >>> y = { 'Jim' : 'gray', 'Zoe' : 'blond', 'David' : 'brown' }
    >>> 'Jim' in y
    True
    >>> 'Fred' in y
    False
    >>> 'gray' in y
    False

    Tenga en cuenta que el operador in, cuando se utiliza en los diccionarios, sólo prueba para las llaves, no valores. Esto se muestra en la prueba final, 'gris' en y.

    en se puede combinar con la sintaxis no muy legible:

    if name not in y:
    print(f"{name} not found")

    El siguiente paso en su desfile de Python incorporada de operadores alguna. Esta es una función booleana que devuelve True si cualquier elemento de los evalúa iterables dados a True. Esto puede parecer un poco tonto hasta que se acuerda de sus listas por comprensión! Combinando estos dos pueden producir poderosa sintaxis, clara para muchas situaciones:

    >>> my_big_list = [10, 23, 875]
    >>> my_small_list = [1, 2, 8]
    >>> any([x < 3 for x in my_big_list]) False >>> any([x < 3 for x in my_small_list]) True

    Fin todo Y, usted tiene toda , que es similar a cualquier. Esto devuelve Verdadero única si usted adivinado-IT todo de los elementos en el iterable son ciertas. Una vez más, combinando esto con listas por comprensión produce una potente característica del lenguaje:

    >>> list_a = [1, 2, 9]
    >>> list_b = [1, 3, 9]
    >>> all([x % 2 for x in list_a])
    False
    >>> all([x % 2 for x in list_b])
    True

    cualquiera y todos pueden cubrir gran parte de la misma tierra donde los desarrolladores de C ++ se vería a std :: encontrar o std :: find_if.

    Nota: En los cualquiera y todos los ejemplos anteriores, puede eliminar los corchetes ([]) sin ninguna pérdida de funcionalidad. (Por ejemplo: los (x% 2 para x en list_a)) esto hace uso de expresiones generador que, mientras que bastante práctico, están más allá del alcance de este artículo.

    Antes de pasar a la tipificación variables, vamos a actualizar su Python vs C ++ tabla de comparación:

    Bien, ahora ya está listo para mirar variable y la tipificación de parámetros. ¡Vamonos!

    estático vs dinámico Typing

    Otro gran tema cuando se está comparando Python vs C ++ es el uso de tipos de datos. C ++ es un lenguaje de tipos estáticos, mientras que Python se escribe de forma dinámica. Vamos a explorar lo que eso significa.

    establecimiento de tipos estáticos

    C ++ se escribe de forma estática, lo que significa que cada variable que utiliza en su código debe tener un tipo de datos específico, como int, char, float, y así sucesivamente. Puede asignar valores solo del tipo correcto a una variable, a menos que saltar a través de algunos aros.

    Esto tiene algunas ventajas, tanto para el desarrollador y el compilador. El desarrollador gana la ventaja de saber cuál es el tipo de una variable en particular es antes de tiempo, y por lo tanto los que se les permite operaciones. El compilador puede utilizar la información de tipo para optimizar el código, por lo que es más pequeño, más rápido, o ambos.

    Este conocimiento anticipado tiene un costo, sin embargo. Los parámetros pasados ​​a una función debe coincidir con el tipo esperado por la función, que puede reducir la flexibilidad y la utilidad potencial del código.

    Duck Typing

    dinámico tipificación se refiere con frecuencia como tipificación de pato. Es un nombre extraño, y usted leer más sobre esto en un minuto! Pero primero, vamos a empezar con un ejemplo. Esta función toma un objeto de archivo y lee las primeras líneas de diez:

    def read_ten(file_like_object):
    for line_number in range(10):
    x = file_like_object.readline()
    print(f"{line_number} = {x.strip()}")

    Para utilizar esta función, creará un objeto de archivo y pasarlo en:

    with open("types.py") as f:
    read_ten(f)

    Esto muestra cómo el diseño básico de las obras de función. Si bien esta función fue descri ser d como “leer las primeras líneas de diez a partir de un objeto de archivo,” no hay nada en Python que requiere que sea file_like_object un archivo. Mientras el objeto pasado en soportes .readline (), el objeto puede ser de cualquier tipo:

    class Duck():
    def readline(self):
    return "quack"

    my_duck = Duck()
    read_ten(my_duck)

    Calling read_ten () con un objeto Duck produce:

    0 = quack
    1 = quack
    2 = quack
    3 = quack
    4 = quack
    5 = quack
    6 = quack
    7 = quack
    8 = quack
    9 = quack

    Th es es la esencia de duck typing . Como dice el refrán, “Si parece un pato, nada como un pato, y grazna como un pato, entonces probablemente lo es un pato.”

    En otras palabras, si el objeto tiene los métodos necesarios, entonces es aceptable para pasarlo en, independientemente del tipo del objeto. Pato o tipado dinámico le da una enorme cantidad de flexibilidad, ya que permite cualquier tipo que se utiliza donde se encuentra con las interfaces necesarias.

    Sin embargo, hay un problema aquí. ¿Qué pasa si se pasa en un objeto que no se se encuentran la interfaz necesaria? Por ejemplo, ¿qué pasaría si se pasa en un número de read_ten (), así: read_ten (3)?

    Esto resulta en una excepción que son lanzados. A menos que coger la excepción, el programa va a explotar con un rastreo:

    Traceback (most recent call last):
    File "", line 1, in
    File "duck_test.py", line 4, in read_ten
    x = file_like_object.readline()
    AttributeError: 'int' object has no attribute 'readline'

    dinámico de datos puede ser una herramienta muy poderosa, pero como se puede ver, se debe tener precaución cuando se emplea la misma.

    Nota: Python y C ++ son los dos idiomas inflexible de tipos considerados. Aunque C ++ tiene un sistema de tipo más fuerte, los detalles de este general no son significativas para alguien que está aprendiendo Python. el movimiento de

    Vamos a una característica que se beneficia de tipado dinámico de Python: Plantillas.

    plantillas

    Python no tiene plantillas como C ++, pero por lo general no los necesita. En Python, todo es una subclase de un solo tipo de base. Esto es lo que le permite crear funciones de escritura de pato como los anteriores. sistema de plantillas en C ++ El

    le permite crear funciones o algoritmos que operan en varios tipos diferentes. Esto es muy potente y puede ahorrar mucho tiempo y esfuerzo. Sin embargo, también puede ser una fuente de confusión y frustración, ya que los errores de compilación en las plantillas se dejará desconcertado.

    Ser capaz de utilizar la tipificación de pato en lugar de las plantillas hace que algunas cosas mucho más fácil. Pero esto también puede causar difíciles de detectar problemas. Al igual que en todas las decisiones complejas, hay ventajas y desventajas cuando se está comparando Python vs C ++.

    Tipo Comprobación

    Ha habido mucho interés y discusión en la comunidad Python últimamente acerca de la comprobación de tipos estática en Python. Proyectos como mypy han planteado la posibilidad de añadir el tipo de pre-ejecución de cheques a puntos específicos en el idioma. Esto puede ser muy útil en la gestión de las interfaces entre las porciones de grandes paquetes o las API específicas.

    Ayuda a dirección de una de las desventajas de la tipificación de pato. Para los desarrolladores utilizando una función, ayuda si pueden entender completamente lo que cada parámetro tiene que ser. Esto puede ser útil en grandes equipos de proyecto, donde muchos desarrolladores necesitan comunicarse a través de APIs.

    Una vez más, vamos a echar un vistazo a su Python vs C ++ tabla de comparación:

    Ahora ya está listo para pasar a las diferencias en la programación orientada a objetos.

    programación orientada a objetos

    Al igual que C ++, Python admite un modelo de programación orientado a objetos. Muchos de los mismos conceptos que ha aprendido en C ++ servirán en Python. No obstante, deberá tomar decisiones sobre la herencia, la composición y la herencia múltiple.

    Similitudes

    herencia entre clases funciona de manera similar en Python vs C ++. Una nueva clase puede heredar métodos y atributos de una o más clases de base, al igual que lo has visto en C ++. Algunos de los detalles son un poco diferente, sin embargo. clases

    base en Python no tienen su constructor llamado automáticamente como lo hacen en C ++. Esto puede ser confuso cuando se está cambiando idiomas.

    La herencia múltiple también funciona en Python, y tiene al igual que muchas peculiaridades y reglas extrañas como lo hace en C ++.

    Del mismo modo, también se puede utilizar la composición de clases de construcción, donde hay objetos de un tipo de retención otros tipos. Teniendo en cuenta todo es un objeto en Python, esto significa que las clases pueden contener cualquier otra cosa en el lenguaje. Diferencias

    Existen algunas diferencias, sin embargo, cuando usted está comparando Python vs C ++. Los dos primeros están relacionados.

    La primera diferencia es que Python no tiene concepto de modificadores de acceso para las clases. Todo en un objeto de clase es pública. La comunidad Python ha desarrollado una convención que cualquier miembro de una clase de partida con un solo subrayado es tratada como privada. Esto es de ninguna manera forzada por el lenguaje, pero parece que funciona bastante bien.

    El hecho de que cada miembro de la clase y el método es público en Python conduce a la segunda diferencia: Python tiene el apoyo de encapsulación mucho más débil que C ++.

    Como se ha mencionado, la convención subrayado único hace que esta muy lejos de ser un problema en bases de código prácticos de lo que es en un sentido teórico. En general, cualquier usuario que rompe esta regla y depende del funcionamiento interno de una clase es buscar problemas.

    sobrecargas de operadores vs Métodos Dunder

    En C ++, puede agregar operador sobrecargas . Estos le permiten definir el comportamiento de los operadores sintácticas específicas (como ==) para ciertos tipos de datos. Por lo general, esto se utiliza para agregar un uso más natural de sus clases. Para el operador ==, se puede definir exactamente lo que significa para los dos objetos de una clase a ser iguales.

    Una diferencia que se lleva a algunos desarrolladores mucho tiempo a entender es cómo evitar la falta de sobrecargas de operadores en Python. Es muy bueno que Python de objetos todo el trabajo en cualquiera de los contenedores estándar, pero lo que si desea que el operador == para hacer una profunda comparación entre dos objetos de la nueva clase? En C ++, se crearía un operador == () en su clase y hacer la comparación.

    Python tiene una estructura similar que se utiliza bastante coherente en toda la lengua: métodos dunder . métodos dunder reciben este nombre porque todos comienzan y terminan con un doble subrayado, o “D-bajo”.

    Muchas de las funciones integradas que operan sobre objetos en Python son manejados por las llamadas a métodos dunder de ese objeto. Para su ejemplo anterior, se puede añadir __eq __ () a su clase para hacer lo que te gusta la comparación de lujo:

    class MyFancyComparisonClass():
    def __eq__(self, other):
    return True

    Esto produce una clase que compara la misma manera que cualquier otra instancia de su clase. No es particularmente útil, pero demuestra el punto.

    Hay un gran número de métodos utilizados dunder en Python, y el uso integrado de funciones que de ellos ampliamente. Por ejemplo, la adición de __lt __ () permitirá Python para comparar el orden relativo de dos de sus objetos. Esto significa que no sólo el operador , <=, y > = también trabajo también.

    Aún mejor, si tiene varios objetos de la nueva clase en una lista, entonces usted puede utilizar ordenados () en la lista y que van a ser ordenados usando __lt __ ().

    Una vez más, vamos a echar un vistazo a su Python vs C ++ tabla de comparación:

    Ahora que usted ha visto la codificación a través de ambos lenguajes orientados a objetos, vamos a ver cómo Python y C ++ gestionar esos objetos en la memoria.

    Gestión de memoria

    Una de las mayores diferencias, cuando se está comparando Python vs C ++, es la forma en que manejan la memoria. Como se vio en la sección acerca de las variables en C ++ y nombres de Python, Python no tiene punteros, ni fácilmente le permiten manipular la memoria directamente. Si bien hay momentos en los que quieren tener ese nivel de control, la mayoría de las veces no es necesario.

    Ceder el control directo de posiciones de memoria trae algunos beneficios. Usted no necesita preocuparse por la propiedad de memoria, o asegurarse de que la memoria se libera una vez (y sólo una vez) después de que haya sido asignado. También nunca tiene que preocuparse acerca de si o no un objeto se asigna en la pila o el montón, que tiende a tropezar a partir de desarrolladores de C ++.

    Python gestiona todas estas cuestiones para usted. Para ello todo en Python es un objeto de la clase derivada de Python. Esto permite que el intérprete de Python para implementar el recuento de referencias como un medio de hacer el seguimiento de los cuales los objetos son todavía en uso y que puede ser liberado.

    Esta comodidad tiene un precio, por supuesto. Para liberar los objetos de memoria asignados para que, en ocasiones necesitará Python para ejecutar lo que se llama un colector de basura , que encuentra objetos de memoria no utilizados y los libera.

    Nota: CPython tiene un esquema de gestión de memoria compleja, lo que significa que la liberación de memoria no significa necesariamente que la memoria se devuelve al sistema operativo.

    Python utiliza dos herramientas para liberar memoria: la mirada de

    Veamos cada una de ellas por separado. Contar

    Referencia colector

    El colector recuento de referencias es fundamental para el intérprete de Python estándar y siempre se está ejecutando. Su acción consiste en llevar la cuenta de cuántas veces un bloque dado de la memoria (que es siempre un objeto de Python) tiene un nombre que se le atribuye, mientras que su programa se está ejecutando. Muchas reglas describen cuando el recuento de referencia se incrementa o disminuye, sino un ejemplo de un caso podrían aclarar:

    1 >>> x = 'A long string'
    2 >>> y = x
    3 >>> del x
    4 >>> del y

    En el ejemplo anterior, la línea 1 crea un nuevo objeto que contiene la cadena "Una larga cadena". A continuación, coloca el nombre x en este objeto, el aumento de recuento de referencia del objeto a 1:

    En la línea 2 se asigna y para nombrar el mismo objeto, lo que aumentará el número de referencias a 2:

    Cuando llama a del con x en la línea 3, que está retirando una de las referencias al objeto, dejando caer la parte posterior recuento de 1:

    por último, cuando se quita y, la última referencia al objeto, su contador de referencia cae a cero y puede ser liberado por el recolector de basura recuento de referencias. Puede o no puede ser liberado de inmediato en este punto, pero en general, que no debe importar a los desarrolladores:

    Si bien esto se hará cargo de encontrar y liberar a muchos de los objetos que necesitan ser liberados, hay algunas situaciones que no van a coger. Por eso, es necesario el recolector de basura generacional.

    generacional del colector de basura

    Uno de los grandes agujeros en el esquema de referencia que cuenta es que su programa puede crear un ciclo de referencias, en los que el objeto A tiene una referencia al objeto B, que tiene una espalda referencia al objeto A. Es muy posible para golpear esta situación y no tienen nada en su código que hace referencia a cualquiera de los objetos. En este caso, ninguno de los objetos serán nunca golpeó a un contador de referencia de 0.

    El recolector de basura generacional implica un algoritmo complejo que está más allá del alcance de este artículo, pero va a encontrar algunos de estos ciclos de referencia huérfanos y gratuita para usted. Se ejecuta de forma ocasional controlada por los ajustes descritos en la documentación. Uno de estos parámetros es desactivar esta recolector de basura por completo.

    cuando no lo hacen ¿Quieres Garbage Collection

    Cuando usted está comparando Python vs C ++, como cuando usted está comparando las dos herramientas, cada una ventaja viene con una solución de compromiso. Python no requiere la gestión de memoria explícita, pero en ocasiones se gastará una cantidad de tiempo más largo de lo esperado en la recolección de basura. El inverso es cierto para C ++: el programa tendrá tiempos de respuesta consistentes, pero tendrá que gastar más esfuerzo en la gestión de la memoria.

    En muchos programas de vez en cuando la recolección de basura golpe no es importante. If you’re writing a script that only runs for 10 seconds, then you’re unlikely to notice the difference. Some situations, however, require consistent response times. Real-time systems are a great example, where responding to a piece of hardware in a fixed amount of time can be essential to the proper operation of your system.

    Systems with hard real-time requirements are some of the systems for which Python is a poor language choice. Having a tightly controlled system where you’re certain of the timing is a good use of C++. These are the types of issues to consider when you’re deciding on the language for a project.

    Time to update your Python vs C++ chart:

    Threading, Multiprocessing, and Async IO

    The concurrency models in C++ and Python are similar, but they have different results and benefits. Both languages have support for threading, multiprocessing, and Async IO operations. Let’s look at each of these.

    Threading

    While both C++ and Python have threading built into the language, the results can be markedly different, depending on the problem you’re solving. Frequently, threading is used to address performance problems. In C++, threading can provide a general speed-up for both computationally bound and I/O bound problems, as threads can take full advantage of the cores on a multiprocessor system.

    Python, on the other hand, has made a design trade-off to use the Global Interpreter Lock , or the GIL, to simplify its threading implementation. There are many benefits to the GIL, but the drawback is that only one thread will be running at a single time, even if there are multiple cores.

    If your problem is I/O bound, like fetching several web pages at once, then this limitation will not bother you in the least. You’ll appreciate Python’s easier threading model and built-in methods for inter-thread communications. If your problem is CPU-bound, however, then the GIL will restrict your performance to that of a single processor. Fortunately, Python’s multiprocessing library has a similar interface to its threading library.

    Multiprocessing

    Multiprocessing support in Python is built into the standard library. It has a clean interface that allows you to spin up multiple processes and share information between them. You can create a pool of processes and spread work across them using several techniques.

    While Python still uses similar OS primitives to create the new processes, much of the low-level complication is hidden from the developer.

    C++ relies on fork() to provide multiprocessing support. While this gives you direct access to all of the controls and issues of spawning multiple processes, it’s also much more complex.

    Async IO

    While both Python and C++ support Async IO routines, they’re handled differently. In C++, the std::async methods are likely to use threading to achieve the Async IO nature of their operations. In Python, Async IO code will only run on a single thread.

    There are trade-offs here as well. Using separate threads allows the C++ Async IO code to perform faster on computationally bound problems. The Python tasks used in its Async IO implementation are more lightweight, so it’s faster to spin up a large number of them to handle I/O bound issues.

    Your Python vs C++ comparison chart remains unchanged for this section. Both languages support a full range of concurrency options, with varying trade-offs between speed and convenience.

    Miscellaneous Issues

    If you’re comparing Python vs C++ and looking at adding Python to your toolbelt, then there are a few other things to consider. While your current editor or IDE will certainly work for Python, you might want to add certain extensions or language packs. It’s also worth giving PyCharm a look, as it’s Python-specific.

    Several C++ projects have Python bindings. Things like Qt, WxWidgets, and many messaging APIs having multiple-language bindings.

    If you want to embed Python in C++, then you can use the Python/C API.

    Finally, there are several methods for using your C++ skills to extend Python and add functionality, or to call your existing C++ libraries from within your Python code. Tools like CTypes, Cython, CFFI, Boost.Python and Swig can help you combine these languages and use each for what it’s best at.

    Summary: Python vs C++

    You’ve spent some time reading and thinking about the differences between Python vs C++. While Python has easier syntax and fewer sharp edges, it’s not a perfect fit for all problems. You’ve looked at the syntax, memory management, processing, and several other aspects of these two languages.

    Let’s take a final look at your Python vs C++ comparison chart:

    If you’re comparing Python vs C++, then you can see from your chart that this is not a case where one is better than the other. Each of them is a tool that’s well crafted for various use cases. Just like you don’t use a hammer for driving screws, using the right language for the job will make your life easier!

    Conclusion

    Congrats! You’ve now seen some of the strengths and weaknesses of both Python and C++. You’ve learned some of the features of each language and how they are similar.

    You’ve seen that C++ is great when you want:

    • Fast execution speed (potentially at the cost of development speed)
    • Complete control of memory

    Conversely, Python is great when you want:

    • Fast development speed (potentially at the cost of execution speed)
    • Managed memory

    You’re now ready to make a wise language choice when it comes to your next project!