A maneira certa de criar um DataFrame
TLDR; (basta ler o texto em negrito)
A maioria das respostas aqui mostrará como criar um DataFrame vazio e preenchê-lo, mas ninguém lhe dirá que é uma coisa ruim a se fazer.
Aqui está o meu conselho: espere até ter certeza de que possui todos os dados com os quais precisa trabalhar. Use uma lista para coletar seus dados e, em seguida, inicialize um DataFrame quando estiver pronto.
data = []
for a, b, c in some_function_that_yields_data():
data.append([a, b, c])
df = pd.DataFrame(data, columns=['A', 'B', 'C'])
É sempre mais barato anexar a uma lista e criar um DataFrame de uma só vez do que criar um DataFrame vazio (ou um dos NaNs) e anexá-lo repetidamente. As listas também ocupam menos memória e são uma estrutura de dados muito mais leve para trabalhar , anexar e remover (se necessário).
A outra vantagem desse método é dtypes
inferida automaticamente (em vez de atribuir object
a todos eles).
A última vantagem é que a RangeIndex
é criada automaticamente para seus dados , portanto, é uma coisa a menos com que se preocupar (dê uma olhada nos métodos append
e nos loc
métodos abaixo, você verá elementos nos dois que exigem o tratamento adequado do índice).
Coisas que você NÃO deve fazer
append
ou concat
dentro de um loop
Aqui está o maior erro que eu já vi dos iniciantes:
df = pd.DataFrame(columns=['A', 'B', 'C'])
for a, b, c in some_function_that_yields_data():
df = df.append({'A': i, 'B': b, 'C': c}, ignore_index=True) # yuck
# or similarly,
# df = pd.concat([df, pd.Series({'A': i, 'B': b, 'C': c})], ignore_index=True)
A memória é re-alocados para cada append
ou concat
operação que você tem. Junte isso a um loop e você terá uma operação de complexidade quadrática . Na df.append
página do documento :
O acréscimo de linhas de forma iterativa a um DataFrame pode ser mais intensivo em termos computacionais do que uma única concatenação. Uma solução melhor é anexar essas linhas a uma lista e concatenar a lista com o DataFrame original de uma só vez.
O outro erro associado df.append
é que os usuários tendem a esquecer o acréscimo não é uma função no local , portanto, o resultado deve ser atribuído novamente. Você também precisa se preocupar com os tipos:
df = pd.DataFrame(columns=['A', 'B', 'C'])
df = df.append({'A': 1, 'B': 12.3, 'C': 'xyz'}, ignore_index=True)
df.dtypes
A object # yuck!
B float64
C object
dtype: object
Lidar com colunas de objetos nunca é uma coisa boa, porque os pandas não podem vetorizar operações nessas colunas. Você precisará fazer isso para corrigi-lo:
df.infer_objects().dtypes
A int64
B float64
C object
dtype: object
loc
dentro de um loop
Eu também vi loc
usado para acrescentar a um DataFrame que foi criado vazio:
df = pd.DataFrame(columns=['A', 'B', 'C'])
for a, b, c in some_function_that_yields_data():
df.loc[len(df)] = [a, b, c]
Como antes, você não pré-alocou a quantidade de memória necessária a cada vez; portanto, a memória é re-crescida cada vez que você cria uma nova linha . É tão ruim quanto append
, e ainda mais feio.
DataFrame vazio de NaNs
E então, está criando um DataFrame de NaNs, e todas as advertências associadas a ele.
df = pd.DataFrame(columns=['A', 'B', 'C'], index=range(5))
df
A B C
0 NaN NaN NaN
1 NaN NaN NaN
2 NaN NaN NaN
3 NaN NaN NaN
4 NaN NaN NaN
Ele cria um DataFrame de colunas de objeto, como as outras.
df.dtypes
A object # you DON'T want this
B object
C object
dtype: object
O anexo ainda tem todos os problemas, conforme os métodos acima.
for i, (a, b, c) in enumerate(some_function_that_yields_data()):
df.iloc[i] = [a, b, c]
A prova está no pudim
A temporização desses métodos é a maneira mais rápida de ver o quanto eles diferem em termos de memória e utilidade.
Código de benchmarking para referência.