Eu tentei descobrir uma resposta para essa pergunta por muitos meses enquanto aprendia pandas. Eu uso o SAS no meu trabalho diário e é ótimo pelo suporte fora do núcleo. No entanto, o SAS é horrível como um software por várias outras razões.
Um dia, espero substituir meu uso do SAS por python e pandas, mas atualmente não tenho um fluxo de trabalho fora do núcleo para grandes conjuntos de dados. Não estou falando de "big data" que requer uma rede distribuída, mas de arquivos muito grandes para caber na memória, mas pequenos o suficiente para caber em um disco rígido.
Meu primeiro pensamento é usar HDFStore
para armazenar grandes conjuntos de dados em disco e puxar apenas as peças necessárias para os quadros de dados para análise. Outros mencionaram o MongoDB como uma alternativa mais fácil de usar. Minha pergunta é esta:
Quais são alguns fluxos de trabalho de práticas recomendadas para realizar o seguinte:
- Carregando arquivos simples em uma estrutura de banco de dados permanente em disco
- Consultando esse banco de dados para recuperar dados para alimentar uma estrutura de dados do pandas
- Atualizando o banco de dados após manipular peças nos pandas
Exemplos do mundo real seriam muito apreciados, especialmente de quem usa pandas em "grandes dados".
Editar - um exemplo de como eu gostaria que isso funcionasse:
- Importe iterativamente um arquivo simples grande e armazene-o em uma estrutura de banco de dados permanente em disco. Esses arquivos geralmente são grandes demais para caber na memória.
- Para usar o Pandas, eu gostaria de ler subconjuntos desses dados (geralmente apenas algumas colunas por vez) que podem caber na memória.
- Eu criaria novas colunas executando várias operações nas colunas selecionadas.
- Eu teria que anexar essas novas colunas na estrutura do banco de dados.
Estou tentando encontrar uma maneira de praticar as melhores práticas para executar essas etapas. Lendo links sobre pandas e tabelas, parece que acrescentar uma nova coluna pode ser um problema.
Editar - Respondendo especificamente às perguntas de Jeff:
- Estou construindo modelos de risco de crédito ao consumidor. Os tipos de dados incluem características de telefone, SSN e endereço; valores de propriedade; informações depreciativas, como antecedentes criminais, falências, etc. Os conjuntos de dados que eu uso todos os dias têm cerca de 1.000 a 2.000 campos, em média, de tipos mistos de dados: variáveis contínuas, nominais e ordinais de dados numéricos e de caracteres. Eu raramente anexo linhas, mas realizo muitas operações que criam novas colunas.
- As operações típicas envolvem a combinação de várias colunas usando lógica condicional em uma nova coluna composta. Por exemplo
if var1 > 2 then newvar = 'A' elif var2 = 4 then newvar = 'B'
,. O resultado dessas operações é uma nova coluna para cada registro no meu conjunto de dados. - Por fim, gostaria de acrescentar essas novas colunas à estrutura de dados em disco. Eu repetiria a etapa 2, explorando os dados com tabelas cruzadas e estatísticas descritivas, tentando encontrar relacionamentos interessantes e intuitivos para modelar.
- Um arquivo de projeto típico costuma ter cerca de 1 GB. Os arquivos são organizados de tal maneira que uma linha consiste em um registro de dados do consumidor. Cada linha tem o mesmo número de colunas para cada registro. Este sempre será o caso.
- É muito raro eu agrupar por linhas ao criar uma nova coluna. No entanto, é bastante comum eu definir subconjuntos em linhas ao criar relatórios ou gerar estatísticas descritivas. Por exemplo, convém criar uma frequência simples para uma linha de negócios específica, como cartões de crédito de varejo. Para fazer isso, selecionaria apenas os registros em que a linha de negócios = varejo, além das colunas nas quais quero relatar. Ao criar novas colunas, no entanto, eu puxaria todas as linhas de dados e apenas as colunas necessárias para as operações.
- O processo de modelagem exige que eu analise todas as colunas, procure relacionamentos interessantes com alguma variável de resultado e crie novas colunas compostas que descrevam esses relacionamentos. As colunas que exploro são geralmente feitas em pequenos conjuntos. Por exemplo, vou me concentrar em um conjunto de 20 colunas, digamos, apenas lidando com valores de propriedades e observando como eles se relacionam com a inadimplência de um empréstimo. Depois que essas são exploradas e novas colunas são criadas, passo para outro grupo de colunas, digamos educação universitária e repito o processo. O que estou fazendo é criar variáveis candidatas que explicam a relação entre meus dados e algum resultado. No final deste processo, aplico algumas técnicas de aprendizado que criam uma equação a partir dessas colunas compostas.
É raro que eu adicione linhas ao conjunto de dados. Eu quase sempre vou criar novas colunas (variáveis ou recursos na estatística / linguagem de aprendizado de máquina).
Respostas:
Uso rotineiramente dezenas de gigabytes de dados exatamente dessa maneira; por exemplo, tenho tabelas em disco que leio por meio de consultas, crio dados e anexo novamente.
Vale a pena ler os documentos e no final deste tópico para obter várias sugestões de como armazenar seus dados.
Detalhes que afetarão como você armazena seus dados, como:
Forneça o máximo de detalhes possível; e eu posso ajudá-lo a desenvolver uma estrutura.
(Dar um exemplo de brinquedo pode nos permitir oferecer recomendações mais específicas.)
Solução
Verifique se você tem pelo menos pandas
0.10.1
instalados.Leia arquivos iterativos, pedaço por pedaço, e várias consultas de tabela .
Como o pytables é otimizado para operar em linhas (que é o que você consulta), criaremos uma tabela para cada grupo de campos. Dessa forma, é fácil selecionar um pequeno grupo de campos (que funcionará com uma tabela grande, mas é mais eficiente fazê-lo dessa maneira ... Acho que posso consertar essa limitação no futuro ... mais intuitivo de qualquer maneira):
(O seguinte é pseudocódigo.)
Lendo os arquivos e criando o armazenamento (essencialmente fazendo o que
append_to_multiple
faz):Agora você tem todas as tabelas no arquivo (na verdade, você pode armazená-las em arquivos separados, se desejar, provavelmente adicionaria o nome do arquivo ao group_map, mas provavelmente isso não é necessário).
É assim que você obtém colunas e cria novas:
Quando você estiver pronto para o pós-processamento:
Sobre data_columns, você realmente não precisa definir QUALQUER data_columns; eles permitem que você sub-selecione linhas com base na coluna. Por exemplo, algo como:
Eles podem ser mais interessantes para você no estágio final de geração do relatório (essencialmente, uma coluna de dados é segregada de outras colunas, o que pode afetar um pouco a eficiência, se você definir muito).
Você também pode querer:
Avise-me quando tiver alguma dúvida!
fonte
Eu acho que as respostas acima estão faltando uma abordagem simples que eu achei muito útil.
Quando tenho um arquivo muito grande para carregar na memória, divido o arquivo em vários arquivos menores (por linha ou coluna)
Exemplo: no caso de 30 dias no valor de dados comerciais com tamanho de ~ 30 GB, divido-os em um arquivo por dia com tamanho de ~ 1 GB. Posteriormente, processo cada arquivo separadamente e agrego os resultados no final
Uma das maiores vantagens é que ele permite o processamento paralelo dos arquivos (vários threads ou processos)
A outra vantagem é que a manipulação de arquivos (como adicionar / remover datas no exemplo) pode ser realizada por comandos regulares do shell, o que não é possível em formatos de arquivo mais avançados / complicados
Essa abordagem não abrange todos os cenários, mas é muito útil em muitos deles
fonte
Agora, dois anos após a pergunta, existe um equivalente de panda 'fora do núcleo': dask . É excelente! Embora ele não suporte todas as funcionalidades dos pandas, você pode ir muito longe com isso.
fonte
dask
.Se seus conjuntos de dados tiverem entre 1 e 20 GB, você deverá obter uma estação de trabalho com 48 GB de RAM. Então o Pandas pode armazenar todo o conjunto de dados na RAM. Sei que não é a resposta que você procura aqui, mas fazer computação científica em um notebook com 4 GB de RAM não é razoável.
fonte
Eu sei que esse é um tópico antigo, mas acho que vale a pena conferir a biblioteca do Blaze . Ele foi criado para esse tipo de situação.
Dos documentos:
O Blaze estende a usabilidade do NumPy e Pandas à computação distribuída e fora do núcleo. O Blaze fornece uma interface semelhante à do NumPy ND-Array ou Pandas DataFrame, mas mapeia essas interfaces familiares em uma variedade de outros mecanismos computacionais, como Postgres ou Spark.
Edit: A propósito, é suportado pelo ContinuumIO e Travis Oliphant, autor de NumPy.
fonte
É o caso do pymongo. Também prototipei usando sql server, sqlite, HDF, ORM (SQLAlchemy) em python. Primeiro e acima de tudo, o pymongo é um banco de dados baseado em documento; portanto, cada pessoa seria um documento (
dict
de atributos). Muitas pessoas formam uma coleção e você pode ter muitas coleções (pessoas, mercado de ações, renda).pd.dateframe -> pymongo Nota: Eu uso o
chunksize
inread_csv
para mantê-lo entre 5 e 10k registros (o pymongo descarta o soquete, se maior)consulta: gt = maior que ...
.find()
retorna um iterador, então eu costumo usarichunked
para dividir em iteradores menores.Que tal uma junção, já que normalmente consigo 10 fontes de dados para colar:
então (no meu caso, às vezes eu tenho que
aJoinDF
começar primeiro antes de ser "mesclável".)E você pode gravar as novas informações em sua coleção principal através do método de atualização abaixo. (coleção lógica x fontes de dados físicas).
Em pesquisas menores, apenas desnormalize. Por exemplo, você tem código no documento e apenas adiciona o texto do código do campo e faz uma
dict
pesquisa ao criar documentos.Agora você tem um bom conjunto de dados baseado em uma pessoa, pode liberar sua lógica em cada caso e criar mais atributos. Finalmente, você pode ler em pandas seus 3 principais indicadores de memória máxima e fazer pivots / agg / exploração de dados. Isso funciona para mim por 3 milhões de registros com números / texto grande / categorias / códigos / flutuadores / ...
Você também pode usar os dois métodos criados no MongoDB (MapReduce e estrutura agregada). Consulte aqui para obter mais informações sobre a estrutura agregada , pois parece ser mais fácil que o MapReduce e parece útil para o trabalho agregado rápido. Observe que eu não precisava definir meus campos ou relações e posso adicionar itens a um documento. No estado atual do conjunto de ferramentas numpy, pandas e python em rápida mudança, o MongoDB me ajuda a começar a trabalhar :)
fonte
In [96]: test.insert((a[1].to_dict() for a in df.iterrows())) --------------- InvalidDocument: Cannot encode object: 0
. Alguma idéia do que pode estar errado? Meu dataframe consiste em todos os tipos de int64 e é muito simples.Vi isso um pouco tarde, mas trabalho com um problema semelhante (modelos de pagamento antecipado de hipotecas). Minha solução foi pular a camada HDFStore do pandas e usar tabelas de pitons retas. Eu salvo cada coluna como uma matriz HDF5 individual no meu arquivo final.
Meu fluxo de trabalho básico é primeiro obter um arquivo CSV do banco de dados. Eu fecho o zip, para que não seja tão grande. Em seguida, converto isso em um arquivo HDF5 orientado a linhas, repetindo-o em python, convertendo cada linha em um tipo de dados real e gravando-o em um arquivo HDF5. Isso leva algumas dezenas de minutos, mas não usa memória, pois está operando apenas linha por linha. Em seguida, "transponho" o arquivo HDF5 orientado a linhas para um arquivo HDF5 orientado a colunas.
A tabela de transposição se parece com:
Lê-lo de volta então se parece com:
Agora, eu geralmente executo isso em uma máquina com uma tonelada de memória; portanto, talvez não tenha cuidado o suficiente com o uso de memória. Por exemplo, por padrão, a operação de carregamento lê todo o conjunto de dados.
Isso geralmente funciona para mim, mas é um pouco desajeitado, e eu não posso usar a mágica fantasia das mesas de píer.
Edit: A vantagem real dessa abordagem, sobre o padrão de tabelas de tabelas de matriz de registros, é que eu posso carregar os dados no R usando o h5r, que não pode manipular tabelas. Ou, pelo menos, não consegui carregar tabelas heterogêneas.
fonte
Um truque que achei útil para casos de uso de dados grandes é reduzir o volume dos dados, reduzindo a precisão da flutuação para 32 bits. Não é aplicável em todos os casos, mas em muitos aplicativos a precisão de 64 bits é um exagero e a economia de memória 2x vale a pena. Para tornar um ponto óbvio ainda mais óbvio:
fonte
Como observado por outros, depois de alguns anos surgiu um equivalente de panda 'fora do núcleo': dask . Embora o dask não substitua os pandas e toda a sua funcionalidade, ele se destaca por vários motivos:
O Dask é uma biblioteca de computação paralela flexível para computação analítica que é otimizada para agendamento dinâmico de tarefas para cargas de trabalho computacionais interativas de coleções de “Big Data”, como matrizes paralelas, quadros de dados e listas que estendem interfaces comuns, como iteradores NumPy, Pandas ou Python para maiores ambientes distribuídos que a memória ou distribuídos e dimensiona de laptops a clusters.
e para adicionar um exemplo de código simples:
substitui alguns códigos de pandas como este:
e, especialmente digno de nota, fornece por meio da
concurrent.futures
interface uma infraestrutura geral para o envio de tarefas personalizadas:fonte
Vale mencionar aqui Ray também,
é uma estrutura de computação distribuída, que possui sua própria implementação para pandas de maneira distribuída.
Apenas substitua a importação dos pandas, e o código deve funcionar da seguinte maneira:
pode ler mais detalhes aqui:
https://rise.cs.berkeley.edu/blog/pandas-on-ray/
fonte
Mais uma variação
Muitas das operações realizadas no pandas também podem ser feitas como uma consulta db (sql, mongo)
O uso de um RDBMS ou mongodb permite executar algumas das agregações na Consulta ao DB (que é otimizada para grandes dados e usa cache e índices de forma eficiente)
Posteriormente, você pode executar o pós-processamento usando pandas.
A vantagem desse método é que você obtém otimizações do banco de dados para trabalhar com dados grandes, enquanto define a lógica em uma sintaxe declarativa de alto nível - e não precisa lidar com os detalhes de decidir o que fazer na memória e o que fazer de núcleo.
E embora a linguagem de consulta e os pandas sejam diferentes, geralmente não é complicado traduzir parte da lógica de uma para outra.
fonte
Considere o Ruffus se você seguir o caminho simples de criar um pipeline de dados dividido em vários arquivos menores.
fonte
Recentemente, deparei com um problema semelhante. Descobri que simplesmente ler os dados em pedaços e anexá-los à medida que escrevo em pedaços para o mesmo csv funciona bem. Meu problema foi adicionar uma coluna de data com base nas informações de outra tabela, usando o valor de determinadas colunas da seguinte maneira. Isso pode ajudar aqueles confusos com dask e hdf5, mas mais familiarizado com pandas como eu.
fonte
Eu gostaria de destacar o pacote Vaex.
Dê uma olhada na documentação: https://vaex.readthedocs.io/en/latest/ A API está muito próxima da API dos pandas.
fonte
Por que pandas? Você já experimentou o Standard Python ?
O uso de python de biblioteca padrão. O Pandas está sujeito a atualizações frequentes, mesmo com o recente lançamento da versão estável.
Usando a biblioteca python padrão, seu código sempre será executado.
Uma maneira de fazer isso é ter uma idéia da maneira como você deseja que seus dados sejam armazenados e quais perguntas você deseja resolver em relação aos dados. Em seguida, desenhe um esquema de como você pode organizar seus dados (tabelas de reflexão) que o ajudarão a consultar os dados, não necessariamente a normalização.
Você pode fazer bom uso de:
Ram e HDD estão se tornando cada vez mais baratos com o tempo e o python 3 padrão está amplamente disponível e estável.
fonte
No momento, estou trabalhando "como" você, apenas em uma escala mais baixa, e é por isso que não tenho um PoC para minha sugestão.
No entanto, parece que tenho sucesso em usar pickle como sistema de cache e terceirizar a execução de várias funções em arquivos - executando esses arquivos a partir do meu comando / arquivo principal; Por exemplo, eu uso um prepare_use.py para converter tipos de objetos, dividir um conjunto de dados em teste, validação e conjunto de dados de previsão.
Como funciona seu cache com pickle? Eu uso seqüências de caracteres para acessar arquivos pickle criados dinamicamente, dependendo de quais parâmetros e conjuntos de dados foram passados (com isso, tento capturar e determinar se o programa já foi executado, usando .shape para conjunto de dados, ditado para passado parâmetros). Respeitando essas medidas, recebo uma String para tentar encontrar e ler um arquivo .pickle e, se encontrado, pode pular o tempo de processamento para pular para a execução na qual estou trabalhando agora.
Usando bancos de dados, encontrei problemas semelhantes, e foi por isso que senti alegria ao usar esta solução; no entanto - há muitas restrições - por exemplo, armazenar grandes conjuntos de picles devido à redundância. A atualização de uma tabela de antes para depois de uma transformação pode ser feita com a indexação adequada - as informações de validação abrem outro livro (tentei consolidar dados de aluguel rastreados e parei de usar um banco de dados após 2 horas basicamente - como eu gostaria de voltar depois todo processo de transformação)
Espero que meus 2 centavos o ajudem de alguma forma.
Saudações.
fonte