pandas on Snowflake¶
O pandas on Snowflake permite que você execute seu código pandas de forma distribuída diretamente em seus dados no Snowflake. Apenas alterando a instrução de importação e algumas linhas de código, é possível obter a experiência conhecida do pandas que você conhece e adora, com os benefícios de escalabilidade e segurança do Snowflake. Com o pandas on Snowflake, você pode trabalhar com conjuntos de dados muito maiores e evitar o tempo e as despesas de portar seus pipelines do pandas para outras estruturas de Big Data ou provisionar máquinas grandes e caras. Ele executa cargas de trabalho nativamente no Snowflake por meio de transpilação para SQL, permitindo que ele aproveite a paralelização e os benefícios de governança e segurança de dados do Snowflake. O pandas on Snowflake é entregue por meio do Snowpark pandas API como parte da biblioteca Snowpark Python, que permite o processamento de dados escalável do código Python dentro da plataforma Snowflake.
Benefícios do uso de pandas on Snowflake¶
Como encontrar desenvolvedores Python onde eles estão – O pandas on Snowflake oferece uma interface familiar para desenvolvedores Python, fornecendo uma camada compatível com o pandas que pode ser executada nativamente no Snowflake.
Padas distribuído escalável – O pandas on Snowflake une a conveniência dos pandas com a escalabilidade do Snowflake, aproveitando as técnicas de otimização de consulta existentes no Snowflake. São necessárias poucas reescritas de código, simplificando a jornada de migração para que você possa passar facilmente do protótipo à produção.
Segurança e governança – Os dados não saem da plataforma segura da Snowflake. O pandas on Snowflake permite uniformidade dentro das organizações de dados sobre como os dados são acessados e permite auditoria e governança mais fáceis.
Nenhuma infraestrutura de computação adicional para gerenciar e ajustar – O pandas on Snowflake aproveita o poderoso mecanismo de computação do Snowflake, então você não precisa definir ou gerenciar nenhuma infraestrutura de computação adicional.
Quando devo usar pandas on Snowflake¶
Você deve usar pandas on Snowflake se alguma das seguintes condições for verdadeira:
Você está familiarizado com a API do pandas e o ecossistema PyData mais amplo
Você trabalha em equipe com outras pessoas que estão familiarizadas com o pandas e querem colaborar na mesma base de código
Você tem um código existente escrito em pandas
Seu fluxo de trabalho tem necessidades relacionadas a pedidos, conforme compatibilidade com o pandas DataFrames. Por exemplo, você precisa que o conjunto de dados esteja na mesma ordem para todo o fluxo de trabalho
Você prefere uma conclusão de código mais precisa em ferramentas de copiloto baseadas em AI
Como começar com o pandas on Snowflake¶
Para instalar o pandas on Snowflake, é possível usar conda ou pip para instalar o pacote. Para obter instruções detalhadas, consulte Instalação.
pip install "snowflake-snowpark-python[modin]"
Depois que o pandas on Snowflake estiver instalado, em vez de importar o pandas como import pandas as pd
, use as duas linhas a seguir:
import modin.pandas as pd
import snowflake.snowpark.modin.plugin
Aqui está um exemplo de como é possível começar a usar o pandas on Snowflake através da biblioteca pandas no Snowpark Python com o Modin.
import modin.pandas as pd
# Import the Snowpark plugin for modin.
import snowflake.snowpark.modin.plugin
# Create a Snowpark session with a default connection.
from snowflake.snowpark.session import Session
session = Session.builder.create()
# Create a Snowpark pandas DataFrame from existing Snowflake table
df = pd.read_snowflake('SNOWFALL')
# Alternatively, create a Snowpark pandas DataFrame with sample data.
df = pd.DataFrame([[1, 'Big Bear', 8],[2, 'Big Bear', 10],[3, 'Big Bear', None],
[1, 'Tahoe', 3],[2, 'Tahoe', None],[3, 'Tahoe', 13],
[1, 'Whistler', None],['Friday', 'Whistler', 40],[3, 'Whistler', 25]],
columns=["DAY", "LOCATION", "SNOWFALL"])
# Inspect the DataFrame
df
DAY LOCATION SNOWFALL
0 1 Big Bear 8.0
1 2 Big Bear 10.0
2 3 Big Bear NaN
3 1 Tahoe 3.0
4 2 Tahoe NaN
5 3 Tahoe 13.0
6 1 Whistler NaN
7 Friday Whistler 40.0
8 3 Whistler 25.0
# In-place point update to fix data error.
df.loc[df["DAY"]=="Friday","DAY"]=2
# Inspect the columns after update.
# Note how the data type is updated automatically after transformation.
df["DAY"]
0 1
1 2
2 3
3 1
4 2
5 3
6 1
7 2
8 3
Name: DAY, dtype: int64
# Drop rows with null values.
df.dropna()
DAY LOCATION SNOWFALL
0 1 Big Bear 8.0
1 2 Big Bear 10.0
3 1 Tahoe 3.0
5 3 Tahoe 13.0
7 2 Whistler 40.0
8 3 Whistler 25.0
# Compute the average daily snowfall across locations.
df.groupby("LOCATION").mean()["SNOWFALL"]
LOCATION
Big Bear 9.0
Tahoe 8.0
Whistler 32.5
Name: SNOWFALL, dtype: float64
Como usar o pandas on Snowflake com Snowpark DataFrames¶
O pandas on Snowflake e DataFrame API é altamente interoperável, então você pode construir um pipeline que aproveite ambas as APIs.
Você pode usar as seguintes operações para fazer conversões entre Snowpark DataFrames e Snowpark pandas DataFrames:
Operação |
Entrada |
Saída |
Notas |
---|---|---|---|
Snowpark DataFrame |
DataFrame Snowpark pandas |
Esta operação atribui uma ordem implícita a cada linha e mantém essa ordem de linha durante a vida útil do DataFrame. Custo de E/S será incorrido nesta conversão. |
|
DataFrame Snowpark pandas ou série Snowpark Pandas |
Snowpark DataFrame |
Esta operação não mantém a ordem das linhas e o DataFrame Snowpark resultante opera em um instantâneo de dados do DataFrame Snowpark pandas de origem. Ao contrário do DataFrames Snowpark criado diretamente da tabela, esse comportamento significa que as alterações na tabela subjacente não serão refletidas durante a avaliação das operações do Snowpark. Nenhuma operação DDL e operações DML limitadas podem ser aplicadas no DataFrame. Nenhum custo de E/S será incorrido nesta conversão. |
Sempre que possível, recomendamos usar read_snowflake para ler a tabela diretamente do Snowflake em vez de convertê-la de e para um Snowpark DataFrame para evitar custos de conversão desnecessários.
Para obter mais informações, consulte DataFrames Snowpark vs. DataFrame Snowpark pandas: Qual devo escolher?.
Como o pandas on Snowflake se compara ao pandas nativo¶
O pandas on Snowflake e o pandas nativo têm DataFrame APIs com assinaturas correspondentes e semânticas semelhantes. O pandas on Snowflake fornece a mesma assinatura de API que o pandas nativo (pandas 2.2.1) e fornece computação escalável com o Snowflake. O pandas on Snowflake respeita a semântica descrita na documentação do pandas nativo o máximo possível, mas usa o sistema de computação e tipo do Snowflake. No entanto, quando o pandas nativo é executado em uma máquina cliente, ele usa o sistema de computação e tipos Python. Para obter informações sobre o mapeamento de tipos entre pandas on Snowflake e Snowflake, consulte Tipos de dados.
Assim como o pandas nativo, o pandas on Snowflake também têm a noção de índice e mantêm a ordem das linhas. No entanto, seus distintos ambientes de execução causam certas diferenças sutis em seu comportamento. Esta seção destaca as principais diferenças que você deve conhecer.
O pandas on Snowflake é melhor usado com dados que já estão no Snowflake, mas é possível usar as seguintes operações para converter entre pandas nativos e pandas on Snowflake:
Operação |
Entrada |
Saída |
Notas |
---|---|---|---|
DataFrame Snowpark pandas |
DataFrame de pandas nativo |
Materialize todos os dados para o ambiente local. Se o conjunto de dados for grande, isso poderá resultar em um erro de falta de memória. |
|
pandas DataFrame nativo, dados brutos, objeto Snowpark pandas |
DataFrame Snowpark pandas |
Isto deve ser reservado para DataFrames pequenos. Criar um DataFrame com grandes quantidades de dados locais introduzirá uma tabela temporária e poderá causar problemas de desempenho devido ao upload de dados. |
|
pandas DataFrame nativo, objeto Snowpark pandas |
Tabela do Snowflake |
O resultado pode ser posteriormente carregado no pandas on Snowflake com |
Ambiente de execução¶
pandas
: opera em uma única máquina e processa dados na memória.pandas on Snowflake
: integra-se ao Snowflake, o que permite computação distribuída em um cluster de máquinas. Essa integração permite o manuseio de conjuntos de dados muito maiores que excedem a capacidade de memória de uma única máquina. Observe que usar a API do Snowpark pandas requer uma conexão com o Snowflake.
Avaliação lenta vs. adiantada¶
pandas
: executa operações imediatamente e materializa os resultados completamente na memória após cada operação. Essa avaliação adiantada das operações pode levar ao aumento da pressão da memória, pois os dados precisam ser movidos extensivamente dentro de uma máquina.pandas on Snowflake
: fornece a mesma experiência de API que o pandas. Ele imita o modelo de avaliação adiantada do pandas, mas cria internamente um gráfico de consulta avaliado lentamente para permitir a otimização entre as operações.As operações de fusão e transpilação por meio de um gráfico de consulta permitem oportunidades adicionais de otimização para o mecanismo de computação distribuído subjacente do Snowflake, o que diminui o custo e o tempo de execução do pipeline de ponta a ponta em comparação à execução do pandas diretamente no Snowflake.
Nota
APIs e APIs relacionadas a E/S cujo valor de retorno não é um objeto Snowpark pandas (ou seja,
DataFrame
,Series
ouIndex
) sempre avaliam de forma adiantada. Por exemplo:read_snowflake
to_snowflake
to_pandas
to_dict
to_list
__repr__
O método dunder,
__array__
que pode ser chamado automaticamente por algumas bibliotecas de terceiros, como o scikit-learn. Chamadas para esse método materializarão resultados na máquina local.
Fonte e armazenamento de dados¶
pandas
: oferece suporte a vários leitores e gravadores listados na documentação do pandas nas ferramentas IO (texto, CSV, HDF5, …).pandas on Snowflake
: Pode ler e escrever de tabelas Snowflake e ler arquivos locais ou preparados, CSV, JSON ou Parquet. Para obter mais informações, consulte IO (leitura e gravação).
Tipos de dados¶
pandas
: possui um rico conjunto de tipos de dados, como inteiros, flutuantes, cadeias de caracteres, tiposdatetime
e tipos categóricos. Também oferece suporte a tipos de dados definidos pelo usuário. Os tipos de dados no pandas geralmente são derivados dos dados subjacentes e são aplicados de forma rigorosa.pandas on Snowflake
: limitado pelo sistema do tipo Snowflake, que mapeia objetos pandas para SQL traduzindo os tipos de dados do pandas para os tipos SQL no Snowflake. A maioria dos tipos de pandas tem um equivalente natural em Snowflake, mas o mapeamento nem sempre é um para um. Em alguns casos, vários tipos de pandas são mapeados para o mesmo tipo SQL.
A tabela a seguir lista os mapeamentos de tipos entre pandas e Snowflake SQL:
Tipo pandas |
Tipo de dados Snowflake |
---|---|
Todos os tipos inteiros assinados/não assinados, incluindo tipos inteiros estendidos do pandas |
NUMBER(38, 0) |
Todos os tipos de float, incluindo os tipos de dados float estendidos do pandas |
FLOAT |
|
BOOLEAN |
|
STRING |
|
TIME |
|
DATE |
Todos os tipos |
TIMESTAMP_NTZ |
Todos os tipos |
TIMESTAMP_TZ |
|
ARRAY |
|
MAP |
Coluna de objeto com tipos de dados mistos |
VARIANT |
Timedelta64[ns] |
NUMBER(38, 0) |
Nota
Tipos de dados categóricos, de período, de intervalo, esparsos e definidos pelo usuário não são suportados. Atualmente, o Timedelta só é compatível com o cliente pandas no Snowpark. Ao escrever Timedelta de volta no Snowflake, ele será armazenado como tipo Number.
A tabela a seguir fornece o mapeamento dos tipos SQL Snowflake de volta para os tipos pandas on Snowflake usando df.dtypes
:
Tipo de dados Snowflake |
Tipo pandas on Snowflake ( |
---|---|
NUMBER ( |
|
NUMBER ( |
|
BOOLEAN |
|
STRING, TEXT |
|
VARIANT, BINARY, GEOMETRY, GEOGRAPHY |
|
ARRAY |
|
OBJECT |
|
TIME |
|
TIMESTAMP, TIMESTAMP_NTZ, TIMESTAMP_LTZ, TIMESTAMP_TZ |
|
DATE |
|
Ao converter do Snowpark pandas DataFrame para os pandas DataFrame nativo com to_pandas()
, o pandas DataFrame nativo terá tipos de dados refinados em comparação aos tipos pandas on Snowflake, que são compatíveis com as funções e procedimentos Mapeamentos de tipos de dados SQL-Python.
Conversão e inferência de tipos¶
pandas
: depende de NumPy e por padrão segue o NumPy e sistema de tipos Python para conversão de tipos implícita e inferência. Por exemplo, ele trata booleanos como tipos inteiros, então1 + True
retorna2
.pandas on Snowflake
: mapeia os tipos NumPy e Python para tipos Snowflake de acordo com a tabela anterior e usa o sistema de tipos Snowflake subjacente para conversão de tipos e inferência implícitos. Por exemplo, de acordo com Tipos de dados lógicos, ele não converte implicitamente booleanos em tipos inteiros, então1 + True
resulta em um erro de conversão de tipo.
Tratamento de valor nulo¶
pandas
: nas versões 1.x do pandas, o pandas era flexível ao manipular dados ausentes, então tratou todo o PythonNone
,np.nan
,pd.NaN
,pd.NA
epd.NaT
como valores ausentes. Em versões posteriores do pandas (2.2.x), esses valores são tratados como valores diferentes.pandas on Snowflake
: adota uma abordagem semelhante às versões anteriores do pandas que trata todos os valores anteriores listados como valores ausentes. O Snowpark reutilizaNaN
,NA
eNaT
do pandas. Mas observe que todos esses valores ausentes são tratados de forma intercambiável e armazenados como SQL NULL na tabela Snowflake.
Aliases de offset/frequência¶
pandas
: os offsets de data no pandas foram alterados na versão 2.2.1. Os aliases de uma única letra'M'
,'Q'
,'Y'
e outros foram descontinuados em favor de offsets de duas letras.pandas on Snowflake
: usa exclusivamente os novos offsets descritos ao documentação da série temporal dos pandas.
Instalação¶
Pré-requisitos: Python 3.9, 3.10 ou 3.11, Modin versão 0.28.1 e pandas versão 2.2.1 são necessários.
Dica
Para usar pandas on Snowflake em Snowflake Notebooks, consulte as instruções de configuração em pandas on Snowflake no notebooks.
Para instalar o pandas on Snowflake em seu ambiente de desenvolvimento, siga estas etapas:
Mude para o diretório do seu projeto e ative seu ambiente virtual Python.
Nota
A API está em desenvolvimento ativo, então recomendamos instalá-la em um ambiente virtual Python em vez de em todo o sistema. Essa prática permite que cada projeto criado use uma versão específica, protegendo você de alterações em versões futuras.
Você pode criar um ambiente virtual Python para uma versão específica do Python usando ferramentas como Anaconda, Miniconda ou virtualenv.
Por exemplo, para usar o conda para criar um ambiente virtual Python 3.9, digite:
conda create --name snowpark_pandas python=3.9 conda activate snowpark_pandas
Nota
Se você instalou anteriormente uma versão mais antiga do pandas on Snowflake usando o Python 3.8 e o pandas 1.5.3, será necessário atualizar suas versões do Python e do pandas conforme descrito acima. Siga as etapas para criar um novo ambiente com Python 3.9, 3.10 ou 3.11.
Instale a biblioteca Python do Snowpark com o Modin.
pip install "snowflake-snowpark-python[modin]"
ou
conda install snowflake-snowpark-python modin==0.28.1
Nota
Certifique-se de que a versão 1.17.0 do
snowflake-snowpark-python
ou posterior esteja instalada.
Autenticação no Snowflake¶
Antes de usar o pandas on Snowflake, é necessário estabelecer uma sessão com o banco de dados Snowflake. Você pode usar um arquivo de configuração para escolher os parâmetros de conexão para sua sessão ou pode enumerá-los em seu código. Para obter mais informações, consulte Como criar uma sessão para o Snowpark Python. Se existir uma sessão Python ativa exclusiva do Snowpark, o pandas on Snowflake a utilizará automaticamente. Por exemplo:
import modin.pandas as pd
import snowflake.snowpark.modin.plugin
from snowflake.snowpark import Session
CONNECTION_PARAMETERS = {
'account': '<myaccount>',
'user': '<myuser>',
'password': '<mypassword>',
'role': '<myrole>',
'database': '<mydatabase>',
'schema': '<myschema>',
'warehouse': '<mywarehouse>',
}
session = Session.builder.configs(CONNECTION_PARAMETERS).create()
# pandas on Snowflake will automatically pick up the Snowpark session created above.
# It will use that session to create new DataFrames.
df = pd.DataFrame([1, 2])
df2 = pd.read_snowflake('CUSTOMER')
O pd.session
é uma sessão do Snowpark, então você pode fazer com ela tudo o que faria com qualquer outra sessão do Snowpark. Por exemplo, você pode usá-lo para executar uma consulta SQL arbitária, que resulta em um DataFrame do Snowpark conforme a API da sessão, mas observe que o resultado disso será um DataFrame do Snowpark, não um DataFrame do Snowpark pandas.
# pd.session is the session that pandas on Snowflake is using for new DataFrames.
# In this case it is the same as the Snowpark session that we've created.
assert pd.session is session
# Run SQL query with returned result as Snowpark DataFrame
snowpark_df = pd.session.sql('select * from customer')
snowpark_df.show()
Como alternativa, você pode configurar os parâmetros de conexão do Snowpark em um arquivo de configuração. Isso elimina a necessidade de enumerar parâmetros de conexão em seu código, permitindo que você escreva seu código pandas on Snowflake quase como você normalmente escreveria o código pandas. Para fazer isso, crie um arquivo de configuração localizado em ~/.snowflake/connections.toml
que se parece com isto:
default_connection_name = "default"
[default]
account = "<myaccount>"
user = "<myuser>"
password = "<mypassword>"
role="<myrole>"
database = "<mydatabase>"
schema = "<myschema>"
warehouse = "<mywarehouse>"
Depois, no código, você só precisa usar snowflake.snowpark.Session.builder.create()
para criar uma sessão usando essas credenciais.
import modin.pandas as pd
import snowflake.snowpark.modin.plugin
from snowflake.snowpark import Session
# Session.builder.create() will create a default Snowflake connection.
Session.builder.create()
# create a DataFrame.
df = pd.DataFrame([[1, 2], [3, 4]])
Você também pode criar várias sessões do Snowpark e atribuir uma delas ao pandas on Snowflake. O pandas on Snowflake usa apenas uma sessão, então você precisa atribuir explicitamente uma das sessões ao pandas on Snowflake com pd.session = pandas_session
.
import modin.pandas as pd
import snowflake.snowpark.modin.plugin
from snowflake.snowpark import Session
pandas_session = Session.builder.configs({"user": "<user>", "password": "<password>", "account": "<account1>").create()
other_session = Session.builder.configs({"user": "<user>", "password": "<password>", "account": "<account2>").create()
pd.session = pandas_session
df = pd.DataFrame([1, 2, 3])
O exemplo a seguir mostra que tentar usar o pandas on Snowflake, quando não há uma sessão ativa do Snowpark, gerará SnowparkSessionException
com um erro como “pandas on Snowflake requer uma sessão ativa do Snowpark, mas não há nenhuma”. Após criar uma sessão, é possível usar pandas on Snowflake. Por exemplo:
import modin.pandas as pd
import snowflake.snowpark.modin.plugin
df = pd.DataFrame([1, 2, 3])
O exemplo a seguir mostra que tentar usar pandas on Snowflake quando há várias sessões ativas do Snowpark causará SnowparkSessionException
com uma mensagem como: “Há várias sessões ativas do Snowpark, mas é preciso escolher uma para pandas on Snowflake.”
import modin.pandas as pd
import snowflake.snowpark.modin.plugin
from snowflake.snowpark import Session
pandas_session = Session.builder.configs({"user": "<user>", "password": "<password>", "account": "<account1>"}).create()
other_session = Session.builder.configs({"user": "<user>", "password": "<password>", "account": "<account2>"}).create()
df = pd.DataFrame([1, 2, 3])
Nota
É necessário definir a sessão usada para um novo Snowpark pandas DataFrame ou Series via modin.pandas.session
. No entanto, os DataFrames de junção ou mesclagem criados com diferentes sessões não são compatíveis, portanto, você deve evitar configurar repetidamente diferentes sessões e criar DataFrames com diferentes sessões em um fluxo de trabalho.
Referência de API¶
Veja a referência da API pandas on Snowflake para obter a lista completa de APIs atualmente implementadas e métodos disponíveis.
Para obter uma lista completa de operações compatíveis, consulte as seguintes tabelas na referência do pandas on Snowflake:
Como usar pandas on Snowflake com os notebooks Snowflake¶
Para usar pandas on Snowflake em notebooks Snowflake, consulte pandas on Snowflake em notebooks.
Como usar o pandas on Snowflake em procedimentos armazenados¶
É possível usar o pandas on Snowflake em um procedimento armazenado para criar um pipeline de dados e agendar a execução do procedimento armazenado com tarefas.
from snowflake.snowpark.context import get_active_session
session = get_active_session()
from snowflake.snowpark import Session
def data_transformation_pipeline(session: Session) -> str:
import modin.pandas as pd
import snowflake.snowpark.modin.plugin
from datetime import datetime
# Create a Snowpark pandas DataFrame with sample data.
df = pd.DataFrame([[1, 'Big Bear', 8],[2, 'Big Bear', 10],[3, 'Big Bear', None],
[1, 'Tahoe', 3],[2, 'Tahoe', None],[3, 'Tahoe', 13],
[1, 'Whistler', None],['Friday', 'Whistler', 40],[3, 'Whistler', 25]],
columns=["DAY", "LOCATION", "SNOWFALL"])
# Drop rows with null values.
df = df.dropna()
# In-place point update to fix data error.
df.loc[df["DAY"]=="Friday","DAY"]=2
# Save Results as a Snowflake Table
timestamp = datetime.now().strftime("%Y_%m_%d_%H_%M")
save_path = f"OUTPUT_{timestamp}"
df.to_snowflake(name=save_path, if_exists="replace", index=False)
return f'Transformed DataFrame saved to {save_path}.'
dt_pipeline_sproc = session.sproc.register(name="run_data_transformation_pipeline_sp",
func=data_transformation_pipeline,
replace=True,
packages=['modin', 'snowflake-snowpark-python'])
Para chamar o procedimento armazenado, é possível executar dt_pipeline_sproc()
em Python ou CALL run_data_transformation_pipeline_sp()
em SQL.
Para agendar o procedimento armazenado como uma tarefa, é possível usar o Snowflake Python API para criar uma tarefa.
Como usar o pandas on Snowflake com bibliotecas de terceiros¶
Ao chamar APIs de uma biblioteca de terceiros com um DataFrame Snowpark pandas, recomendamos converter o DataFrame Snowpark pandas em um DataFrame pandas chamando to_pandas() antes de passar o DataFrame para a chamada da biblioteca de terceiros.
Nota
Chamar to_pandas()
extrai seus dados do Snowflake e os coloca na memória, portanto, tenha isso em mente para grandes conjuntos de dados e casos de uso confidenciais.
O pandas on Snowflake atualmente tem compatibilidade limitada para certas APIs NumPy e Matplotlib, como implementação distribuída para np.where
e interoperabilidade com df.plot
. Converter o DataFrames pandas Snowpark via to_pandas()
ao trabalhar com essas bibliotecas de terceiros evitará múltiplas chamadas de E/S.
Aqui está um exemplo com Altair para visualização e scikit-learn para aprendizado de máquina.
# Create a Snowpark session with a default connection.
session = Session.builder.create()
train = pd.read_snowflake('TITANIC')
train[['Pclass', 'Parch', 'Sex', 'Survived']].head()
Pclass Parch Sex Survived
0 3 0 male 0
1 1 0 female 1
2 3 0 female 1
3 1 0 female 1
4 3 0 male 0
import altair as alt
# Convert to pandas DataFrame
train_df_pandas = train.to_pandas()
survived_per_age_plot = alt.Chart(train_df_pandas).mark_bar(
).encode(
x=alt.X('Age', bin=alt.Bin(maxbins=25)),
y='count()',
column='Survived:N',
color='Survived:N',
).properties(
width=300,
height=300
).configure_axis(
grid=False
)
survived_per_age_plot

Agora podemos usar o scikit-learn para treinar um modelo simples após a conversão para pandas.
feature_cols = ['Pclass', 'Parch']
# Convert features DataFrame to pandas DataFrames
X_pandas = train_snowpark_pandas.loc[:, feature_cols].to_pandas()
# Convert labels Series to pandas Series
y_pandas = train_snowpark_pandas["Survived"].to_pandas()
from sklearn.linear_model import LogisticRegression
logreg = LogisticRegression()
logreg.fit(X_pandas, y_pandas)
y_pred_pandas = logreg.predict(X_pandas)
acc_eval = accuracy_score(y_pandas, y_pred_pandas)

Limitações¶
pandas on Snowflake tem as seguintes limitações:
O pandas on Snowflake não oferece nenhuma garantia de compatibilidade com bibliotecas de terceiros OSS. A partir da versão 1.14.0a1, no entanto, o Snowpark pandas introduz compatibilidade limitada para NumPy, especificamente para o uso de
np.where
. Para obter mais informações, consulte Interoperabilidade do NumPy.Ao chamar APIs da biblioteca de terceiros com um DataFrame Snowpark pandas, Snowflake recomenda que você converta o DataFrame Snowpark pandas em um DataFrame pandas chamando
to_pandas()
antes de passar o DataFrame para a chamada de biblioteca de terceiros. Para obter mais informações, consulte Como usar o pandas on Snowflake com bibliotecas de terceiros.pandas on Snowflake não está integrado ao Snowpark ML. Ao usar o Snowpark ML, recomendamos que você converta o DataFrame Snowpark pandas em um DataFrame Snowpark usando to_snowpark() antes de chamar o Snowpark ML.
Os objetos
MultiIndex
lentos não são suportados. QuandoMultiIndex
é usado, ele retorna um objetoMultiIndex
pandas nativo, que requer a extração de todos os dados para o lado do cliente.Nem todos as APIs pandas têm uma implementação distribuída ainda no pandas on Snowflake. Para APIs não suportadas,
NotImplementedError
é lançado. Operações que não têm implementação distribuída retornam a um procedimento armazenado. Para obter informações sobre as APIs suportadas, consulte a documentação de referência da API.O pandas on Snowflake requer uma versão específica do pandas. O pandas on Snowflake requer o pandas 2.2.1 e só oferece compatibilidade com o pandas 2.2.1.
O pandas on Snowflake não pode ser referenciado dentro da função
apply()
do pandas on Snowflake. Somente é possível usar pandas nativo dentro deapply()
.
Solução de problemas¶
Esta seção descreve dicas de solução de problemas ao usar o pandas on Snowflake.
Ao solucionar problemas, tente executar a mesma operação em um DataFrame pandas nativo (ou em uma amostra) para ver se o mesmo erro persiste. Essa abordagem pode fornecer dicas sobre como corrigir sua consulta. Por exemplo:
df = pd.DataFrame({"a": [1,2,3], "b": ["x", "y", "z"]}) # Running this in Snowpark pandas throws an error df["A"].sum() # Convert a small sample of 10 rows to pandas DataFrame for testing pandas_df = df.head(10).to_pandas() # Run the same operation. KeyError indicates that the column reference is incorrect pandas_df["A"].sum() # Fix the column reference to get the Snowpark pandas query working df["a"].sum()
Se você tiver um notebook de longa execução aberto, observe que, por padrão, as sessões do Snowflake atingem o tempo limite após ficarem ociosas por 240 minutos (4 horas). Quando a sessão expirar, você receberá o seguinte erro se executar consultas pandas on Snowflake adicionais: “O token de autenticação expirou. O usuário deve se autenticar novamente.” Neste ponto, você deve restabelecer a conexão com o Snowflake novamente. Isso pode resultar na perda de quaisquer variáveis de sessão não persistentes. Para obter mais informações sobre como configurar o parâmetro de tempo limite de inatividade da sessão, consulte Políticas de sessão.
Práticas recomendadas¶
Esta seção descreve as melhores práticas a serem seguidas ao usar o pandas on Snowflake.
Evite usar padrões de código iterativos, como loops
for
,iterrows
eiteritems
. Padrões de código iterativos aumentam rapidamente a complexidade da consulta gerada. Deixe que o pandas on Snowflake realize a distribuição de dados e a paralelização de computação em vez do código do cliente. Quando se trata de padrões de código iterativos, tente procurar operações que possam ser executadas no DataFrame todo e use as operações correspondentes.
for i in np.arange(0, 50):
if i % 2 == 0:
data = pd.concat([data, pd.DataFrame({'A': i, 'B': i + 1}, index=[0])], ignore_index=True)
else:
data = pd.concat([data, pd.DataFrame({'A': i}, index=[0])], ignore_index=True)
# Instead of creating one DataFrame per row and concatenating them,
# try to directly create the DataFrame out of the data, like this:
data = pd.DataFrame(
{
"A": range(0, 50),
"B": [i + 1 if i % 2 == 0 else None for i in range(50)],
},
)
Evite chamar
apply
,applymap
etransform
, que são eventualmente implementados com UDFs ou UDTFs, que pode não ter o mesmo desempenho que as consultas SQL normais. Se a função aplicada tiver uma operação equivalente em DataFrame ou série, use essa operação. Por exemplo, em vez dedf.groupby('col1').apply('sum')
, chame diretamentedf.groupby('col1').sum()
.Chame
to_pandas()
antes de passar o DataFrame ou série para uma biblioteca de terceiros. O pandas on Snowflake não fornece garantia de compatibilidade com bibliotecas de terceiros.Use uma tabela Snowflake regular materializada para evitar sobrecarga extra de E/S. O pandas on Snowflake funciona sobre um instantâneo de dados que funciona apenas para tabelas regulares. Para outros tipos, incluindo tabelas externas, exibições e tabelas Apache Iceberg™, uma tabela temporária é criada antes de tirar o instantâneo, o que introduz sobrecarga extra de materialização.
O pandas on Snowflake fornece capacidade de clonagem rápida e zero-copy ao criar DataFrames de tabelas Snowflake usando
read_snowflake
. No entanto, o recurso de instantâneo só é fornecido para tabelas Snowflake regulares em bancos de dados normais. Materialização extra para tabelas Snowflake regulares será introduzida ao carregar tabelas com tipos como híbrido, Iceberg etc., ou tabelas em bancos de dados compartilhados. O instantâneo é necessário para fornecer consistência de dados e garantia de ordenação, e atualmente não há outra maneira de contornar a materialização extra. Tente usar tabelas normais do Snowflake sempre que possível ao usar pandas on Snowflake.Verifique novamente o tipo de resultado antes de prosseguir com outras operações e faça a conversão de tipo explícita com
astype
, se necessário.Devido à capacidade limitada de inferência de tipo, se nenhuma dica de tipo for fornecida,
df.apply
retornará resultados do tipo objeto (variante) mesmo que o resultado contenha todos os valores inteiros. Se outras operações exigirem que odtype
sejaint
, você pode fazer uma conversão de tipo explícita chamando o métodoastype
para corrigir o tipo de coluna antes de continuar.Evite chamar APIs que requerem avaliação e materialização se não forem necessárias.
APIs que não retornam
Series
ouDataframe
exigem avaliação e materialização adiantadas para produzir o resultado no tipo correto. O mesmo vale para métodos de plotagem. Reduza as chamadas para aquelas APIs para minimizar avaliações e materializações desnecessárias.Evite chamar
np.where(<cond>, <escalar>, n)
em grandes conjuntos de dados. O<escalar>
será transmitido para um DataFrame do tamanho de<cond>
, o que pode ser lento.Ao trabalhar com consultas construídas iterativamente,
df.cache_result
pode ser usado para materializar resultados intermediários e reduzir a avaliação repetida, melhorar a latência e reduzir a complexidade da consulta geral. Por exemplo:df = pd.read_snowflake('pandas_test') df2 = pd.pivot_table(df, index='index_col', columns='pivot_col') # expensive operation df3 = df.merge(df2) df4 = df3.where(df2 == True)
No exemplo acima, a consulta para produzir
df2
é cara de calcular e é reutilizada na criação dedf3
edf4
. Materializandodf2
em uma tabela temporária (fazendo operações subsequentes envolvendo uma varredura de tabeladf2
em vez de um pivô) pode reduzir a latência geral do bloco de código:df = pd.read_snowflake('pandas_test') df2 = pd.pivot_table(df, index='index_col', columns='pivot_col') # expensive operation df2.cache_result(inplace=True) df3 = df.merge(df2) df4 = df3.where(df2 == True)
Exemplos¶
Aqui está um exemplo de código com operações do pandas. Começamos com um DataFrame Snowpark pandas chamado pandas_test
, que contém três colunas: COL_STR
, COL_FLOAT
e COL_INT
. Para exibir o notebook associado a esses exemplos, consulte os exemplos do pandas on Snowflake no repositório Snowflake-Labs.
import modin.pandas as pd
import snowflake.snowpark.modin.plugin
from snowflake.snowpark import Session
CONNECTION_PARAMETERS = {
'account': '<myaccount>',
'user': '<myuser>',
'password': '<mypassword>',
'role': '<myrole>',
'database': '<mydatabase>',
'schema': '<myschema>',
'warehouse': '<mywarehouse>',
}
session = Session.builder.configs(CONNECTION_PARAMETERS).create()
df = pd.DataFrame([['a', 2.1, 1],['b', 4.2, 2],['c', 6.3, None]], columns=["COL_STR", "COL_FLOAT", "COL_INT"])
df
COL_STR COL_FLOAT COL_INT
0 a 2.1 1.0
1 b 4.2 2.0
2 c 6.3 NaN
Salvamos DataFrame como uma tabela Snowflake nomeada pandas_test
que usaremos em nossos exemplos.
df.to_snowflake("pandas_test", if_exists='replace',index=False)
Em seguida, criamos um DataFrame a partir da tabela Snowflake. Nós descartamos a coluna COL_INT
e então salvamos o resultado de volta no Snowflake com uma coluna chamada row_position
.
# Create a DataFrame out of a Snowflake table.
df = pd.read_snowflake('pandas_test')
df.shape
(3, 3)
df.head(2)
COL_STR COL_FLOAT COL_INT
0 a 2.1 1
1 b 4.2 2
df.dropna(subset=["COL_FLOAT"], inplace=True)
df
COL_STR COL_FLOAT COL_INT
0 a 2.1 1
1 c 6.3 2
df.shape
(2, 3)
df.dtypes
COL_STR object
COL_FLOAT float64
COL_INT int64
dtype: object
# Save the result back to Snowflake with a row_pos column.
df.reset_index(drop=True).to_snowflake('pandas_test2', if_exists='replace', index=True, index_label=['row_pos'])
Você acaba com uma nova tabela, pandas_test2
, que se parece com isto:
row_pos COL_STR COL_FLOAT COL_INT
0 1 a 2.0 1
1 2 b 4.0 2
IO (leitura e gravação)¶
# Reading and writing to Snowflake
df = pd.DataFrame({"fruit": ["apple", "orange"], "size": [3.4, 5.4], "weight": [1.4, 3.2]})
df.to_snowflake("test_table", if_exists="replace", index=False )
df_table = pd.read_snowflake("test_table")
# Generate sample CSV file
with open("data.csv", "w") as f:
f.write('fruit,size,weight\napple,3.4,1.4\norange,5.4,3.2')
# Read from local CSV file
df_csv = pd.read_csv("data.csv")
# Generate sample JSON file
with open("data.json", "w") as f:
f.write('{"fruit":"apple", "size":3.4, "weight":1.4},{"fruit":"orange", "size":5.4, "weight":3.2}')
# Read from local JSON file
df_json = pd.read_json('data.json')
# Upload data.json and data.csv to Snowflake stage named @TEST_STAGE
# Read CSV and JSON file from stage
df_csv = pd.read_csv('@TEST_STAGE/data.csv')
df_json = pd.read_json('@TEST_STAGE/data.json')
Para obter mais informações, consulte Entrada/Saída.
Indexação¶
df = pd.DataFrame({"a": [1,2,3], "b": ["x", "y", "z"]})
df.columns
Index(['a', 'b'], dtype='object')
df.index
Index([0, 1, 2], dtype='int8')
df["a"]
0 1
1 2
2 3
Name: a, dtype: int8
df["b"]
0 x
1 y
2 z
Name: b, dtype: object
df.iloc[0,1]
'x'
df.loc[df["a"] > 2]
a b
2 3 z
df.columns = ["c", "d"]
df
c d
0 1 x
1 2 y
2 3 z
df = df.set_index("c")
df
d
c
1 x
2 y
3 z
df.rename(columns={"d": "renamed"})
renamed
c
1 x
2 y
3 z
Valores ausentes¶
import numpy as np
df = pd.DataFrame([[np.nan, 2, np.nan, 0],
[3, 4, np.nan, 1],
[np.nan, np.nan, np.nan, np.nan],
[np.nan, 3, np.nan, 4]],
columns=list("ABCD"))
df
A B C D
0 NaN 2.0 NaN 0.0
1 3.0 4.0 NaN 1.0
2 NaN NaN NaN NaN
3 NaN 3.0 NaN 4.0
df.isna()
A B C D
0 True False True False
1 False False True False
2 True True True True
3 True False True False
df.fillna(0)
A B C D
0 0.0 2.0 0.0 0.0
1 3.0 4.0 0.0 1.0
2 0.0 0.0 0.0 0.0
3 0.0 3.0 0.0 4.0
df.dropna(how="all")
A B C D
0 NaN 2.0 NaN 0.0
1 3.0 4.0 NaN 1.0
3 NaN 3.0 NaN 4.0
Conversão de tipo¶
df = pd.DataFrame({"int": [1,2,3], "str": ["4", "5", "6"]})
df
int str
0 1 4
1 2 5
2 3 6
df_float = df.astype(float)
df_float
int str
0 1.0 4.0
1 2.0 5.0
2 3.0 6.0
df_float.dtypes
int float64
str float64
dtype: object
pd.to_numeric(df.str)
0 4.0
1 5.0
2 6.0
Name: str, dtype: float64
df = pd.DataFrame({'year': [2015, 2016],
'month': [2, 3],
'day': [4, 5]})
pd.to_datetime(df)
0 2015-02-04
1 2016-03-05
dtype: datetime64[ns]
Operações binárias¶
df_1 = pd.DataFrame([[1,2,3],[4,5,6]])
df_2 = pd.DataFrame([[6,7,8]])
df_1.add(df_2)
0 1 2
0 7.0 9.0 11.0
1 NaN NaN NaN
s1 = pd.Series([1, 2, 3])
s2 = pd.Series([2, 2, 2])
s1 + s2
0 3
1 4
2 5
dtype: int64
df = pd.DataFrame({"A": [1,2,3], "B": [4,5,6]})
df["A+B"] = df["A"] + df["B"]
df
A B A+B
0 1 4 5
1 2 5 7
2 3 6 9
Agregação¶
df = pd.DataFrame([[1, 2, 3],
[4, 5, 6],
[7, 8, 9],
[np.nan, np.nan, np.nan]],
columns=['A', 'B', 'C'])
df.agg(['sum', 'min'])
A B C
sum 12.0 15.0 18.0
min 1.0 2.0 3.0
df.median()
A 4.0
B 5.0
C 6.0
dtype: float64
Merge¶
df1 = pd.DataFrame({'lkey': ['foo', 'bar', 'baz', 'foo'],
'value': [1, 2, 3, 5]})
df1
lkey value
0 foo 1
1 bar 2
2 baz 3
3 foo 5
df2 = pd.DataFrame({'rkey': ['foo', 'bar', 'baz', 'foo'],
'value': [5, 6, 7, 8]})
df2
rkey value
0 foo 5
1 bar 6
2 baz 7
3 foo 8
df1.merge(df2, left_on='lkey', right_on='rkey')
lkey value_x rkey value_y
0 foo 1 foo 5
1 foo 1 foo 8
2 bar 2 bar 6
3 baz 3 baz 7
4 foo 5 foo 5
5 foo 5 foo 8
df = pd.DataFrame({'key': ['K0', 'K1', 'K2', 'K3', 'K4', 'K5'],
'A': ['A0', 'A1', 'A2', 'A3', 'A4', 'A5']})
df
key A
0 K0 A0
1 K1 A1
2 K2 A2
3 K3 A3
4 K4 A4
5 K5 A5
other = pd.DataFrame({'key': ['K0', 'K1', 'K2'],
'B': ['B0', 'B1', 'B2']})
df.join(other, lsuffix='_caller', rsuffix='_other')
key_caller A key_other B
0 K0 A0 K0 B0
1 K1 A1 K1 B1
2 K2 A2 K2 B2
3 K3 A3 None None
4 K4 A4 None None
5 K5 A5 None None
Groupby¶
df = pd.DataFrame({'Animal': ['Falcon', 'Falcon','Parrot', 'Parrot'],
'Max Speed': [380., 370., 24., 26.]})
df
Animal Max Speed
0 Falcon 380.0
1 Falcon 370.0
2 Parrot 24.0
3 Parrot 26.0
df.groupby(['Animal']).mean()
Max Speed
Animal
Falcon 375.0
Parrot 25.0
Para obter mais informações, consulte GroupBy.
Pivô¶
df = pd.DataFrame({"A": ["foo", "foo", "foo", "foo", "foo",
"bar", "bar", "bar", "bar"],
"B": ["one", "one", "one", "two", "two",
"one", "one", "two", "two"],
"C": ["small", "large", "large", "small",
"small", "large", "small", "small",
"large"],
"D": [1, 2, 2, 3, 3, 4, 5, 6, 7],
"E": [2, 4, 5, 5, 6, 6, 8, 9, 9]})
df
A B C D E
0 foo one small 1 2
1 foo one large 2 4
2 foo one large 2 5
3 foo two small 3 5
4 foo two small 3 6
5 bar one large 4 6
6 bar one small 5 8
7 bar two small 6 9
8 bar two large 7 9
pd.pivot_table(df, values='D', index=['A', 'B'],
columns=['C'], aggfunc="sum")
C large small
A B
bar one 4.0 5
two 7.0 6
foo one 4.0 1
two NaN 6
df = pd.DataFrame({'foo': ['one', 'one', 'one', 'two', 'two', 'two'],
'bar': ['A', 'B', 'C', 'A', 'B', 'C'],
'baz': [1, 2, 3, 4, 5, 6],
'zoo': ['x', 'y', 'z', 'q', 'w', 't']})
df
foo bar baz zoo
0 one A 1 x
1 one B 2 y
2 one C 3 z
3 two A 4 q
4 two B 5 w
5 two C 6 t