# @title Licensed under the Apache License, Version 2.0 (the "License");
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
Nota: Este notebook requiere límites de tasa de nivel de pago para ejecutarse correctamente (consulta precios para más detalles).
Descripción general
Este tutorial demuestra cómo usar los embeddings de la API de Gemini para detectar posibles valores atípicos en tu conjunto de datos. Visualizarás un subconjunto del conjunto de datos 20 Newsgroups usando t-SNE{:.external} y detectarás valores atípicos fuera de un radio particular del punto central de cada clúster categórico.
Para obtener más información sobre cómo empezar a usar los embeddings generados desde la API de Gemini, consulta la guía Primeros pasos.
Requisitos previos
Puedes ejecutar este inicio rápido en Google Colab.
Para completar este inicio rápido en tu propio entorno de desarrollo, asegúrate de que tu entorno cumpla con los siguientes requisitos:
Python 3.11+
Una instalación de jupyter para ejecutar el notebook.
Configuración
Primero, descarga e instala la biblioteca de Python de la API de Gemini.
%pip install -U -q google-genai
import re
import tqdm
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
from google import genai
from google.genai import types
# Used to securely store your API key
from google.colab import userdata
from sklearn.datasets import fetch_20newsgroups
from sklearn.manifold import TSNE
Obtén una clave de API
Antes de que puedas usar la API de Gemini, primero debes obtener una clave de API. Si aún no tienes una, crea una clave con un solo clic en Google AI Studio.
En Colab, agrega la clave al administrador de secretos bajo el "🔑" en el panel izquierdo. Dale el nombre GEMINI_API_KEY.
Una vez que tengas la clave de API, pásala al SDK. Puedes hacerlo de dos maneras:
Coloca la clave en la variable de entorno GEMINI_API_KEY (el SDK la detectará automáticamente desde allí).
Pasa la clave a genai.Client(api_key=...)
# Or use `os.getenv('GEMINI_API_KEY')` to fetch an environment variable.
GEMINI_API_KEY=userdata.get('GEMINI_API_KEY')
client = genai.Client(api_key=GEMINI_API_KEY)
Punto clave: A continuación, elegirás un modelo. Cualquier modelo de embedding funcionará para este tutorial, pero para aplicaciones reales es importante elegir un modelo específico y mantenerlo. Las salidas de diferentes modelos no son compatibles entre sí.
for m in client.models.list():
if 'embedContent' in m.supported_actions:
print(m.name)
El Conjunto de datos de texto 20 Newsgroups{:.external} contiene 18,000 publicaciones de grupos de noticias sobre 20 temas divididos en conjuntos de entrenamiento y prueba. La división entre los conjuntos de datos de entrenamiento y prueba se basa en mensajes publicados antes y después de una fecha específica. Este tutorial utiliza el subconjunto de entrenamiento.
newsgroups_train = fetch_20newsgroups(subset='train')
# View list of class names for dataset
newsgroups_train.target_names
Lines: 15
I was wondering if anyone out there could enlighten me on this car I saw
the other day. It was a 2-door sports car, looked to be from the late 60s/
early 70s. It was called a Bricklin. The doors were really small. In addition,
the front bumper was separate from the rest of the body. This is
all I know. If anyone can tellme a model name, engine specs, years
of production, where this car is made, history, or whatever info you
have on this funky looking car, please e-mail.
Thanks,
- IL
---- brought to you by your neighborhood Lerxst ----
# Apply functions to remove names, emails, and extraneous words from data points in newsgroups.data
newsgroups_train.data = [re.sub(r'[\w\.-]+@[\w\.-]+', '', d) for d in newsgroups_train.data] # Remove email
newsgroups_train.data = [re.sub(r"\([^()]*\)", "", d) for d in newsgroups_train.data] # Remove names
newsgroups_train.data = [d.replace("From: ", "") for d in newsgroups_train.data] # Remove "From: "
newsgroups_train.data = [d.replace("\nSubject: ", "") for d in newsgroups_train.data] # Remove "\nSubject: "
# Cut off each text entry after 5,000 characters
newsgroups_train.data = [d[0:5000] if len(d) > 5000 else d for d in newsgroups_train.data]
# Put training points into a dataframe
df_train = pd.DataFrame(newsgroups_train.data, columns=['Text'])
df_train['Label'] = newsgroups_train.target
# Match label to target name index
df_train['Class Name'] = df_train['Label'].map(newsgroups_train.target_names.__getitem__)
df_train
Text Label \
0 WHAT car is this!?\nNntp-Posting-Host: rac3.w... 7
1 SI Clock Poll - Final Call\nSummary: Final ca... 4
2 PB questions...\nOrganization: Purdue Univers... 4
3 Re: Weitek P9000 ?\nOrganization: Harris Comp... 1
4 Re: Shuttle Launch Question\nOrganization: Sm... 14
... ... ...
11309 Re: Migraines and scans\nDistribution: world... 13
11310 Screen Death: Mac Plus/512\nLines: 22\nOrganiz... 4
11311 Mounting CPU Cooler in vertical case\nOrganiz... 3
11312 Re: Sphere from 4 points?\nOrganization: Cent... 1
11313 stolen CBR900RR\nOrganization: California Ins... 8
Class Name
0 rec.autos
1 comp.sys.mac.hardware
2 comp.sys.mac.hardware
3 comp.graphics
4 sci.space
... ...
11309 sci.med
11310 comp.sys.mac.hardware
11311 comp.sys.ibm.pc.hardware
11312 comp.graphics
11313 rec.motorcycles
[11314 rows x 3 columns]
Text
Label
Class Name
0
WHAT car is this!?\nNntp-Posting-Host: rac3.w...
7
rec.autos
1
SI Clock Poll - Final Call\nSummary: Final ca...
4
comp.sys.mac.hardware
2
PB questions...\nOrganization: Purdue Univers...
4
comp.sys.mac.hardware
3
Re: Weitek P9000 ?\nOrganization: Harris Comp...
1
comp.graphics
4
Re: Shuttle Launch Question\nOrganization: Sm...
14
sci.space
...
...
...
...
11309
Re: Migraines and scans\nDistribution: world...
13
sci.med
11310
Screen Death: Mac Plus/512\nLines: 22\nOrganiz...
4
comp.sys.mac.hardware
11311
Mounting CPU Cooler in vertical case\nOrganiz...
3
comp.sys.ibm.pc.hardware
11312
Re: Sphere from 4 points?\nOrganization: Cent...
1
comp.graphics
11313
stolen CBR900RR\nOrganization: California Ins...
8
rec.motorcycles
11314 rows × 3 columns
A continuación, muestrea algunos de los datos tomando 150 puntos de datos del conjunto de datos de entrenamiento y eligiendo algunas categorías. Este tutorial utiliza las categorías de ciencia.
# Take a sample of each label category from df_train
SAMPLE_SIZE = 150
df_train = (df_train.groupby('Label', as_index = False)
.apply(lambda x: x.sample(SAMPLE_SIZE))
.reset_index(drop=True))
# Choose categories about science
df_train = df_train[df_train['Class Name'].str.contains('sci')]
# Reset the index
df_train = df_train.reset_index()
df_train
/tmp/ipykernel_100019/406673449.py:4: FutureWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.
.apply(lambda x: x.sample(SAMPLE_SIZE))
index Text Label \
0 1650 Privacy & Anonymity on the Internet FAQ \nSup... 11
1 1651 The source of that announcement\nOrganization... 11
2 1652 Would "clipper" make a good cover for other e... 11
3 1653 What the clipper nay-sayers sound like to me.... 11
4 1654 alt.security.pgp\nNntp-Posting-Host: bootes.c... 11
.. ... ... ...
595 2245 Re: Terraforming Venus: can it be done "cheap... 14
596 2246 Re: *Doppelganger* \nArticle-I.D.: mojo.1qkn6... 14
597 2247 Re: What if the USSR had reached the Moon fir... 14
598 2248 Re: DC-X Rollout Report\nArticle-I.D.: topaz.... 14
599 2249 Re: Vandalizing the sky.\nOrganization: Locus... 14
Class Name
0 sci.crypt
1 sci.crypt
2 sci.crypt
3 sci.crypt
4 sci.crypt
.. ...
595 sci.space
596 sci.space
597 sci.space
598 sci.space
599 sci.space
[600 rows x 4 columns]
index
Text
Label
Class Name
0
1650
Privacy & Anonymity on the Internet FAQ \nSup...
11
sci.crypt
1
1651
The source of that announcement\nOrganization...
11
sci.crypt
2
1652
Would "clipper" make a good cover for other e...
11
sci.crypt
3
1653
What the clipper nay-sayers sound like to me....
11
sci.crypt
4
1654
alt.security.pgp\nNntp-Posting-Host: bootes.c...
11
sci.crypt
...
...
...
...
...
595
2245
Re: Terraforming Venus: can it be done "cheap...
14
sci.space
596
2246
Re: *Doppelganger* \nArticle-I.D.: mojo.1qkn6...
14
sci.space
597
2247
Re: What if the USSR had reached the Moon fir...
14
sci.space
598
2248
Re: DC-X Rollout Report\nArticle-I.D.: topaz....
14
sci.space
599
2249
Re: Vandalizing the sky.\nOrganization: Locus...
14
sci.space
600 rows × 4 columns
df_train['Class Name'].value_counts()
Class Name
sci.crypt 150
sci.electronics 150
sci.med 150
sci.space 150
Name: count, dtype: int64
Genera los embeddings
En esta sección, verás cómo generar embeddings para los diferentes textos en el dataframe usando los embeddings de la API de Gemini.
El modelo de embedding de Gemini admite varios tipos de tareas, cada uno adaptado a un objetivo específico. Aquí tienes una descripción general de los tipos disponibles y sus aplicaciones:
Tipo de tarea
Descripción
RETRIEVAL_QUERY
Especifica que el texto dado es una consulta en un entorno de búsqueda/recuperación.
RETRIEVAL_DOCUMENT
Especifica que el texto dado es un documento en un entorno de búsqueda/recuperación.
SEMANTIC_SIMILARITY
Especifica que el texto dado se usará para la similitud textual semántica (STS).
CLASSIFICATION
Especifica que los embeddings se usarán para clasificación.
CLUSTERING
Especifica que los embeddings se usarán para clustering.
from tqdm.auto import tqdm
tqdm.pandas()
def make_embed_text_fn(model):
def embed_fn(text: str) -> list[float]:
# Set the task_type to CLUSTERING.
result = client.models.embed_content(model=model,
contents=text,
config=types.EmbedContentConfig(
task_type="CLUSTERING"))
return np.array(result.embeddings[0].values)
return embed_fn
def create_embeddings(df):
df['Embeddings'] = df['Text'].progress_apply(make_embed_text_fn(MODEL_ID))
return df
df_train = create_embeddings(df_train)
df_train.drop('index', axis=1, inplace=True)
100%|██████████| 600/600 [06:11<00:00, 1.62it/s]
Reducción de dimensionalidad
La dimensión del vector de embedding del documento es 3072. Para visualizar cómo se agrupan los documentos embebidos, deberás aplicar la reducción de dimensionalidad, ya que solo puedes visualizar los embeddings en un espacio 2D o 3D. Los documentos contextualmente similares deben estar más cerca en el espacio en comparación con los documentos que no son tan similares.
len(df_train['Embeddings'][0])
3072
# Convert df_train['Embeddings'] Pandas series to a np.array of float32
X = np.array(df_train['Embeddings'].to_list(), dtype=np.float32)
X.shape
(600, 3072)
Aplicarás el enfoque de t-Distributed Stochastic Neighbor Embedding (t-SNE) para realizar la reducción de dimensionalidad. Esta técnica reduce el número de dimensiones, mientras preserva los clústeres (los puntos que están cerca permanecen cerca). Para los datos originales, el modelo intenta construir una distribución sobre la cual otros puntos de datos son "vecinos" (por ejemplo, comparten un significado similar). Luego optimiza una función objetivo para mantener una distribución similar en la visualización.
Para determinar qué puntos son anómalos, determinarás qué puntos son valores internos y valores atípicos. Comienza por encontrar el centroide, o la ubicación que representa el centro del clúster, y usa la distancia para determinar los puntos que son valores atípicos.
Comienza por obtener el centroide de cada categoría.
def get_centroids(df_tsne):
# Get the centroid of each cluster
centroids = df_tsne.groupby('Class Name').mean()
return centroids
centroids = get_centroids(df_tsne)
centroids
TSNE1 TSNE2
Class Name
sci.crypt 31.146711 -6.366441
sci.electronics 7.322525 19.477852
sci.med -9.485087 -22.437294
sci.space -23.256557 9.471162
TSNE1
TSNE2
Class Name
sci.crypt
31.146711
-6.366441
sci.electronics
7.322525
19.477852
sci.med
-9.485087
-22.437294
sci.space
-23.256557
9.471162
def get_embedding_centroids(df):
emb_centroids = dict()
grouped = df.groupby('Class Name')
for c in grouped.groups:
sub_df = grouped.get_group(c)
# Get the centroid value of dimension 768
emb_centroids[c] = np.mean(sub_df['Embeddings'], axis=0)
return emb_centroids
emb_c = get_embedding_centroids(df_train)
Traza cada centroide que has encontrado contra el resto de los puntos.
# Plot the centroids against the cluster
fig, ax = plt.subplots(figsize=(8,6)) # Set figsize
sns.set_style('darkgrid', {"grid.color": ".6", "grid.linestyle": ":"})
sns.scatterplot(data=df_tsne, x='TSNE1', y='TSNE2', hue='Class Name', palette='Set2');
sns.scatterplot(data=centroids, x='TSNE1', y='TSNE2', color="black", marker='X', s=100, label='Centroids')
sns.move_legend(ax, "upper left", bbox_to_anchor=(1, 1))
plt.title('Scatter plot of news using t-SNE with centroids')
plt.xlabel('TSNE1')
plt.ylabel('TSNE2');
<Figure size 800x600 with 1 Axes>
Elige un radio. Cualquier cosa más allá de este límite desde el centroide de esa categoría se considera un valor atípico.
def calculate_euclidean_distance(p1, p2):
return np.sqrt(np.sum(np.square(p1 - p2)))
def detect_outlier(df, emb_centroids, radius):
for idx, row in df.iterrows():
class_name = row['Class Name'] # Get class name of row
# Compare centroid distances
dist = calculate_euclidean_distance(row['Embeddings'],
emb_centroids[class_name])
df.at[idx, 'Outlier'] = dist > radius
return len(df[df['Outlier'] == True])
range_ = np.arange(0.3, 0.75, 0.02).round(decimals=2).tolist()
num_outliers = []
for i in range_:
num_outliers.append(detect_outlier(df_train, emb_c, i))
# Plot range_ and num_outliers
fig = plt.figure(figsize = (14, 8))
plt.rcParams.update({'font.size': 12})
plt.bar(list(map(str, range_)), num_outliers)
plt.title("Number of outliers vs. distance of points from centroid")
plt.xlabel("Distance")
plt.ylabel("Number of outliers")
for i in range(len(range_)):
plt.text(i, num_outliers[i], num_outliers[i], ha = 'center')
plt.show()
<Figure size 1400x800 with 1 Axes>
Dependiendo de cuán sensible quieras que sea tu detector de anomalías, puedes elegir qué radio deseas usar. Por ahora, se usa 0.58, pero puedes cambiar este valor.
# View the points that are outliers
RADIUS = 0.54
detect_outlier(df_train, emb_c, RADIUS)
df_outliers = df_train[df_train['Outlier'] == True]
df_outliers.head()
# Use the index to map the outlier points back to the projected TSNE points
outliers_projected = df_tsne.loc[df_outliers['Outlier'].index]
Traza los valores atípicos y denótalos usando un color rojo transparente.
fig, ax = plt.subplots(figsize=(8,6)) # Set figsize
plt.rcParams.update({'font.size': 10})
sns.set_style('darkgrid', {"grid.color": ".6", "grid.linestyle": ":"})
sns.scatterplot(data=df_tsne, x='TSNE1', y='TSNE2', hue='Class Name', palette='Set2');
sns.scatterplot(data=centroids, x='TSNE1', y='TSNE2', color="black", marker='X', s=100, label='Centroids')
# Draw a red circle around the outliers
sns.scatterplot(data=outliers_projected, x='TSNE1', y='TSNE2', color='red', marker='o', alpha=0.5, s=90, label='Outliers')
sns.move_legend(ax, "upper left", bbox_to_anchor=(1, 1))
plt.title('Scatter plot of news with outliers projected with t-SNE')
plt.xlabel('TSNE1')
plt.ylabel('TSNE2')
Text(0, 0.5, 'TSNE2')
<Figure size 800x600 with 1 Axes>
Usa los valores de índice de los dataframes para imprimir algunos ejemplos de cómo pueden verse los valores atípicos en cada categoría. Aquí, se imprime el primer punto de datos de cada categoría. Explora otros puntos en cada categoría para ver datos que se consideran valores atípicos o anomalías.
Electric power line "balls"
Article-I.D.: almaden.19930406.142616.248
Lines: 4
Power lines and airplanes don't mix. In areas where lines are strung very
high, or where a lot of crop dusting takes place, or where there is danger
of airplanes flying into the lines, they place these plastic balls on the
lines so they are easier to spot.
LARSONIAN Astronomy and Physics
Organization: University of Wisconsin Eau Claire
Lines: 552
LARSONIAN Astronomy and Physics
Orthodox physicists, astronomers, and astrophysicists
CLAIM to be looking for a "Unified Field Theory" in which all
of the forces of the universe can be explained with a single
set of laws or equations. But they have been systematically
IGNORING or SUPPRESSING an excellent one for 30 years!
The late Physicist Dewey B. Larson's comprehensive
GENERAL UNIFIED Theory of the physical universe, which he
calls the "Reciprocal System", is built on two fundamental
postulates about the physical and mathematical natures of
space and time:
"The physical universe is composed ENTIRELY of ONE
component, MOTION, existing in THREE dimensions, in DISCRETE
UNITS, and in two RECIPROCAL forms, SPACE and TIME."
"The physical universe conforms to the relations of
ORDINARY COMMUTATIVE mathematics, its magnitudes are
ABSOLUTE, and its geometry is EUCLIDEAN."
From these two postulates, Larson developed a COMPLETE
Theoretical Universe, using various combinations of
translational, vibrational, rotational, and vibrational-
rotational MOTIONS, the concepts of IN-ward and OUT-ward
SCALAR MOTIONS, and speeds in relation to the Speed of Light
.
At each step in the development, Larson was able to
MATCH objects in his Theoretical Universe with objects in the
REAL physical universe, , even objects NOT YET
DISCOVERED THEN .
And applying his Theory to his NEW model of the atom,
Larson was able to precisely and accurately CALCULATE inter-
atomic distances in crystals and molecules, compressibility
and thermal expansion of solids, and other properties of
matter.
All of this is described in good detail, with-OUT fancy
complex mathematics, in his books.
BOOKS of Dewey B. Larson
The following is a complete list of the late Physicist
Dewey B. Larson's books about his comprehensive GENERAL
UNIFIED Theory of the physical universe. Some of the early
books are out of print now, but still available through
inter-library loan.
"The Structure of the Physical Universe"
"The Case AGAINST the Nuclear Atom"
"Beyond Newton"
"New Light on Space and Time"
"Quasars and Pulsars"
"NOTHING BUT MOTION"
[A $9.50 SUBSTITUTE for the $8.3 BILLION "Super
Collider".]
[The last four chapters EXPLAIN chemical bonding.]
"The Neglected Facts of Science"
"THE UNIVERSE OF MOTION"
[FINAL SOLUTIONS to most ALL astrophysical
mysteries.]
"BASIC PROPERTIES OF MATTER"
All but the last of these books were published by North
Pacific Publishers, P.O. Box 13255, Portland, OR 97213, and
should be available via inter-library loan if your local
university or public library doesn't have each of them.
Several of them, INCLUDING the last one, are available
from: The International Society of Unified Science ,
1680 E. Atkin Ave., Salt Lake City, Utah 84106. This is the
organization that was started to promote Larson's Theory.
They have other related publications, including the quarterly
journal "RECIPROCITY".
Physicist Dewey B. Larson's Background
Physicist Dewey B. Larson was a retired Engineer
. He was about 91 years old when he
died in May 1989. He had a Bachelor of Science Degree in
Engineering Science from Oregon State University. He
developed his comprehensive GENERAL UNIFIED Theory of the
physical universe while trying to develop a way to COMPUTE
chemical properties based only on the elements used.
Larson's lack of a fancy "PH.D." degree might be one
reason that orthodox physicists are ignoring him, but it is
NOT A VALID REASON. Sometimes it takes a relative outsider
to CLEARLY SEE THE FOREST THROUGH THE TREES. At the same
time, it is clear from his books that he also knew ORTHODOX
physics and astronomy as well as ANY physicist or astronomer,
Próximos pasos
¡Ahora has creado un detector de anomalías usando embeddings! Intenta usar tus propios datos textuales para visualizarlos como embeddings, y elige algún límite para que puedas detectar valores atípicos. Puedes realizar una reducción de dimensionalidad para completar el paso de visualización. Ten en cuenta que t-SNE es bueno para agrupar entradas, pero puede tardar más tiempo en converger o quedarse atascado en mínimos locales.
Para aprender a usar otros servicios en la API de Gemini, consulta la guía Primeros pasos.
Lección del curso «Gemini API Cookbook (examples)» de Google, publicado con licencia Apache 2.0. Traducción y adaptación al español de IA con Clase. IA con Clase no está afiliado a Google. Ver el original · Licencia
Esta lección es gratuita. El resto del curso se abre con la Membresía de IA con Clase, que incluye todos los cursos del catálogo. Ver precios