python - query - regex in pandas dataframe




Adicione uma linha ao pandas DataFrame (12)

Eu entendo que pandas é projetado para carregar DataFrame totalmente preenchido, mas eu preciso criar um DataFrame vazio, em seguida, adicionar linhas, um por um . Qual é a melhor maneira de fazer isso?

Eu criei com sucesso um DataFrame vazio com:

res = DataFrame(columns=('lib', 'qty1', 'qty2'))

Então eu posso adicionar uma nova linha e preencher um campo com:

res = res.set_value(len(res), 'qty1', 10.0)

Ele funciona, mas parece muito estranho: - / (falha ao adicionar valor de string)

Como posso adicionar uma nova linha ao meu DataFrame (com diferentes tipos de colunas)?


Aqui está a maneira de adicionar / acrescentar uma linha no pandas DataFrame

def add_row(df, row):
    df.loc[-1] = row
    df.index = df.index + 1  
    return df.sort_index()

add_row(df, [1,2,3]) 

Pode ser usado para inserir / anexar uma linha em pandas vazios ou preenchidos DataFrame


Caso você possa obter todos os dados para o quadro de dados de antemão, há uma abordagem muito mais rápida do que anexar a um quadro de dados:

  1. Crie uma lista de dicionários nos quais cada dicionário corresponde a uma linha de dados de entrada.
  2. Crie um quadro de dados nessa lista.

Eu tinha uma tarefa semelhante para a qual anexar a um quadro de dados linha por linha levou 30 min e criar um quadro de dados de uma lista de dicionários concluída dentro de segundos.

rows_list = []
for row in input_rows:

        dict1 = {}
        # get input row in dictionary format
        # key = col_name
        dict1.update(blah..) 

        rows_list.append(dict1)

df = pd.DataFrame(rows_list)               

Descobri um jeito simples e legal:

>>> df
     A  B  C
one  1  2  3
>>> df.loc["two"] = [4,5,6]
>>> df
     A  B  C
one  1  2  3
two  4  5  6

Esta não é uma resposta à pergunta do OP, mas um exemplo de brinquedo para ilustrar a resposta do @ShikharDua acima, o que achei muito útil.

Embora esse fragmento seja trivial, nos dados reais eu tinha 1.000s de linhas e muitas colunas, e gostaria de poder agrupar por colunas diferentes e, em seguida, executar as estatísticas abaixo para mais de uma coluna de taget. Portanto, ter um método confiável para construir o quadro de dados uma linha de cada vez era uma grande conveniência. Obrigado @ShikharDua!

import pandas as pd 

BaseData = pd.DataFrame({ 'Customer' : ['Acme','Mega','Acme','Acme','Mega','Acme'],
                          'Territory'  : ['West','East','South','West','East','South'],
                          'Product'  : ['Econ','Luxe','Econ','Std','Std','Econ']})
BaseData

columns = ['Customer','Num Unique Products', 'List Unique Products']

rows_list=[]
for name, group in BaseData.groupby('Customer'):
    RecordtoAdd={} #initialise an empty dict 
    RecordtoAdd.update({'Customer' : name}) #
    RecordtoAdd.update({'Num Unique Products' : len(pd.unique(group['Product']))})      
    RecordtoAdd.update({'List Unique Products' : pd.unique(group['Product'])})                   

    rows_list.append(RecordtoAdd)

AnalysedData = pd.DataFrame(rows_list)

print('Base Data : \n',BaseData,'\n\n Analysed Data : \n',AnalysedData)

Já faz muito tempo, mas também enfrentei o mesmo problema. E encontrei aqui muitas respostas interessantes. Então eu estava confuso sobre qual método usar.

No caso de adicionar muitas linhas ao dataframe, estou interessado no desempenho da velocidade . Então eu tentei 3 métodos mais populares e verifiquei sua velocidade.

ATUALIZADO EM 2019 usando novas versões de pacotes

DESEMPENHO DE VELOCIDADE

  1. Usando o .append ( resposta do NPE )
  2. Usando .loc ( resposta de Fred e resposta de FooBar )
  3. Usando dict e criar DataFrame no final ( resposta de ShikharDua )

Resultados (em segundos):

Adding    1000 rows  5000 rows   10000 rows
.append   0.69       3.37        6.77
.loc      0.73       3.87        8.14
dict      0.011      0.046       0.088

Também graças ao @krassowski para comentário útil - eu atualizei o código.

Então eu uso adição através do dicionário para mim.

Código:

import pandas
import numpy
import time
#%%
del df1, df2, df3
numOfRows = 1000
startTime = time.perf_counter()
df1 = pandas.DataFrame(numpy.random.randint(100, size=(5,5)), columns=['A', 'B', 'C', 'D', 'E'])
for i in range( 1,numOfRows-4):
    df1 = df1.append( dict( (a,numpy.random.randint(100)) for a in ['A','B','C','D','E']), ignore_index=True)
print('Elapsed time: {:6.3f} seconds for {:d} rows'.format(time.perf_counter() - startTime, numOfRows))
print(df1.shape)

startTime = time.perf_counter()
df2 = pandas.DataFrame(numpy.random.randint(100, size=(5,5)), columns=['A', 'B', 'C', 'D', 'E'])
for i in range( 1,numOfRows):
    df2.loc[i]  = numpy.random.randint(100, size=(1,5))[0]
print('Elapsed time: {:6.3f} seconds for {:d} rows'.format(time.perf_counter() - startTime, numOfRows))
print(df2.shape)

startTime = time.perf_counter()
row_list = []
for i in range (0,5):
    row_list.append(dict( (a,numpy.random.randint(100)) for a in ['A','B','C','D','E']))
for i in range( 1,numOfRows-4):
    dict1 = dict( (a,numpy.random.randint(100)) for a in ['A','B','C','D','E'])
    row_list.append(dict1)

df3 = pandas.DataFrame(row_list, columns=['A','B','C','D','E'])
print('Elapsed time: {:6.3f} seconds for {:d} rows'.format(time.perf_counter() - startTime, numOfRows))
print(df3.shape)

PS Acredito, minha realização não é perfeita, e talvez haja alguma otimização.


Outra maneira de fazer isso (provavelmente não é muito eficiente):

# add a row
def add_row(df, row):
    colnames = list(df.columns)
    ncol = len(colnames)
    assert ncol == len(row), "Length of row must be the same as width of DataFrame: %s" % row
    return df.append(pd.DataFrame([row], columns=colnames))

Você também pode melhorar a classe DataFrame assim:

import pandas as pd
def add_row(self, row):
    self.loc[len(self.index)] = row
pd.DataFrame.add_row = add_row

Por uma questão de modo Pythonic, aqui adicione minha resposta:

res = pd.DataFrame(columns=('lib', 'qty1', 'qty2'))
res = res.append([{'qty1':10.0}], ignore_index=True)
print(res.head())

   lib  qty1  qty2
0  NaN  10.0   NaN

Se você souber o número de entradas ex ante, deverá pré-alocar o espaço fornecendo também o índice (tomando o exemplo de dados de uma resposta diferente):

import pandas as pd
import numpy as np
# we know we're gonna have 5 rows of data
numberOfRows = 5
# create dataframe
df = pd.DataFrame(index=np.arange(0, numberOfRows), columns=('lib', 'qty1', 'qty2') )

# now fill it up row by row
for x in np.arange(0, numberOfRows):
    #loc or iloc both work here since the index is natural numbers
    df.loc[x] = [np.random.randint(-1,1) for n in range(3)]
In[23]: df
Out[23]: 
   lib  qty1  qty2
0   -1    -1    -1
1    0     0     0
2   -1     0    -1
3    0    -1     0
4   -1     0     0

Comparação de velocidade

In[30]: %timeit tryThis() # function wrapper for this answer
In[31]: %timeit tryOther() # function wrapper without index (see, for example, @fred)
1000 loops, best of 3: 1.23 ms per loop
100 loops, best of 3: 2.31 ms per loop

E - a partir dos comentários - com um tamanho de 6000, a diferença de velocidade se torna ainda maior:

Aumentar o tamanho da matriz (12) e o número de linhas (500) torna a diferença de velocidade mais impressionante: 313ms vs 2.29s


Você pode acrescentar uma única linha como um dicionário usando a opção ignore_index .

>>> f = pandas.DataFrame(data = {'Animal':['cow','horse'], 'Color':['blue', 'red']})
>>> f
  Animal Color
0    cow  blue
1  horse   red
>>> f.append({'Animal':'mouse', 'Color':'black'}, ignore_index=True)
  Animal  Color
0    cow   blue
1  horse    red
2  mouse  black


import pandas as pd 
t1=pd.DataFrame()
for i in range(len(the number of rows)):
    #add rows as columns
    t1[i]=list(rows)
t1=t1.transpose()
t1.columns=list(columns)

mycolumns = ['A', 'B']
df = pd.DataFrame(columns=mycolumns)
rows = [[1,2],[3,4],[5,6]]
for row in rows:
    df.loc[len(df)] = row






append