Como iterar sobre linhas em um DataFrame no Pandas?

1951

Eu tenho um DataFramedos pandas:

import pandas as pd
inp = [{'c1':10, 'c2':100}, {'c1':11,'c2':110}, {'c1':12,'c2':120}]
df = pd.DataFrame(inp)
print df

Resultado:

   c1   c2
0  10  100
1  11  110
2  12  120

Agora eu quero percorrer as linhas desse quadro. Para cada linha, quero poder acessar seus elementos (valores em células) pelo nome das colunas. Por exemplo:

for row in df.rows:
   print row['c1'], row['c2']

É possível fazer isso em pandas?

Eu encontrei essa pergunta semelhante . Mas isso não me dá a resposta que eu preciso. Por exemplo, é sugerido lá usar:

for date, row in df.T.iteritems():

ou

for row in df.iterrows():

Mas não entendo qual é o rowobjeto e como posso trabalhar com ele.

romano
fonte
11
O df.iteritems () itera sobre colunas e não linhas. Portanto, para fazer a iteração nas linhas, é necessário transpor (o "T"), o que significa que você altera as linhas e as colunas entre si (reflete na diagonal). Como resultado, você efetivamente iteração da trama de dados originais sobre suas linhas quando você usa df.T.iteritems ()
Stefan Gruenwald
12
Se você é novo neste tópico e é iniciante em pandas, NÃO ITERE !! A iteração sobre os quadros de dados é um antipadrão, e algo que você não deve fazer, a menos que queira se acostumar com muita espera. Dependendo do que você está tentando fazer, existem alternativas muito melhores . iter*funções devem ser usadas em circunstâncias muito raras. Também relacionado .
cs95
19
Ao contrário do que o cs95 diz, há perfeitamente boas razões para querer iterar em um dataframe, para que os novos usuários não se sintam desencorajados. Um exemplo é se você deseja executar algum código usando os valores de cada linha como entrada. Além disso, se o seu quadro de dados for razoavelmente pequeno (por exemplo, menos de 1.000 itens), o desempenho não será realmente um problema.
Oulenz # 16/19
1
@oulenz: Se, por algum motivo estranho, você quiser usar a API para a finalidade para a qual foi projetada (transformações de dados de alto desempenho), fique à vontade. Mas, pelo menos, não use iterrows, existem maneiras melhores de iterar sobre um DataFrame; você também pode iterar sobre uma lista de listas nesse momento. Se você estiver no ponto em que não está fazendo nada além de iterar sobre DataFrames, não há realmente nenhum benefício em usar um DataFrame (presumir que iterá-lo é a única coisa que você está fazendo com ele). Apenas meu 2c.
cs95
8
Eu segundo @oulenz. Tanto quanto eu posso dizer, pandasé a opção de ler um arquivo csv, mesmo que o conjunto de dados seja pequeno. É simplesmente mais fácil a programação para manipular os dados com APIs
Chris

Respostas:

2640

DataFrame.iterrows é um gerador que gera índice e linha

import pandas as pd
import numpy as np

df = pd.DataFrame([{'c1':10, 'c2':100}, {'c1':11,'c2':110}, {'c1':12,'c2':120}])

for index, row in df.iterrows():
    print(row['c1'], row['c2'])

Output: 
   10 100
   11 110
   12 120
waitingkuo
fonte
207
Nota: "Como o iterrows retorna uma série para cada linha, ele não preserva os tipos nas linhas". Além disso, "você nunca deve modificar algo sobre o qual está repetindo". De acordo com pandas 0.19.1 docs
viddik13
3
@ viddik13 é uma ótima nota, obrigado. Por causa disso, me deparei com um caso em que valores numéricos como 431341610650onde são lidos 4.31E+11. Existe uma maneira de preservar os tipos?
Aziz Alto
26
@AzizAlto itertuples, como explicado abaixo. Veja também pandas.pydata.org/pandas-docs/stable/generated/…
Axel
101
Não use as linhas abaixo. Itertuples é mais rápido e preserva o tipo de dados. Mais informações
James L.
11
A partir da documentação : "A iteração através de objetos pandas é geralmente lenta. Em muitos casos, a iteração manual sobre as linhas não é necessária [...]". Sua resposta está correta (no contexto da pergunta), mas não a menciona em nenhum lugar; portanto, não é muito boa.
cs95 28/05/19
460

Como iterar sobre linhas em um DataFrame no Pandas?

Resposta: NÃO * !

A iteração nos pandas é um antipadrão e é algo que você só deve fazer quando tiver esgotado todas as outras opções. Você não deve usar nenhuma função com " iter" em seu nome por mais de alguns milhares de linhas ou terá que se acostumar com muita espera.

Deseja imprimir um DataFrame? Use DataFrame.to_string().

Deseja calcular alguma coisa? Nesse caso, procure métodos nesta ordem (lista modificada aqui ):

  1. Vetorização
  2. Rotinas Cython
  3. Compreensões de lista ( forloop de baunilha )
  4. DataFrame.apply(): i) Reduções que podem ser executadas em cython, ii) Iteração no espaço python
  5. DataFrame.itertuples() e iteritems()
  6. DataFrame.iterrows()

iterrowse itertuples(ambos recebendo muitos votos em respostas a essa pergunta) devem ser usados ​​em circunstâncias muito raras, como a geração de objetos de linha / nametuples para processamento seqüencial, que é realmente a única coisa para a qual essas funções são úteis.

Apelação à autoridade
A página de documentos na iteração tem uma enorme caixa de aviso vermelha que diz:

A iteração através de objetos pandas é geralmente lenta. Em muitos casos, a iteração manual sobre as linhas não é necessária [...].

* Na verdade, é um pouco mais complicado do que "não". df.iterrows()é a resposta correta para essa pergunta, mas "vetorize suas operações" é a melhor. Admito que há circunstâncias em que a iteração não pode ser evitada (por exemplo, algumas operações em que o resultado depende do valor calculado para a linha anterior). No entanto, é preciso alguma familiaridade com a biblioteca para saber quando. Se você não tem certeza se precisa de uma solução iterativa, provavelmente não precisa. PS: Para saber mais sobre minha justificativa para escrever esta resposta, pule para o final.


Mais rápido do que Looping: Vectorization , Cython

Um bom número de operações e cálculos básicos é "vetorizado" pelos pandas (por meio do NumPy ou por funções Cythonized). Isso inclui aritmética, comparações, (a maioria) reduções, remodelagem (como rotação), junções e operações de grupo por grupo. Consulte a documentação sobre Funcionalidade básica essencial para encontrar um método vetorizado adequado para o seu problema.

Se não houver, sinta-se à vontade para criar suas próprias extensões usando o cython personalizado .


Melhor coisa seguinte: lista de compreensões *

A compreensão da lista deve ser o seu próximo porto de escala se 1) não houver uma solução vetorizada disponível, 2) o desempenho for importante, mas não o suficiente para passar pelo incômodo de codificar o código e 3) você estiver tentando executar uma transformação elementar no seu código. Há uma boa quantidade de evidências para sugerir que a compreensão da lista é suficientemente rápida (e às vezes mais rápida) para muitas tarefas comuns dos pandas.

A fórmula é simples,

# iterating over one column - `f` is some function that processes your data
result = [f(x) for x in df['col']]
# iterating over two columns, use `zip`
result = [f(x, y) for x, y in zip(df['col1'], df['col2'])]
# iterating over multiple columns - same data type
result = [f(row[0], ..., row[n]) for row in df[['col1', ...,'coln']].to_numpy()]
# iterating over multiple columns - differing data type
result = [f(row[0], ..., row[n]) for row in zip(df['col1'], ..., df['coln'])]

Se você pode encapsular sua lógica de negócios em uma função, poderá usar uma compreensão de lista que a chama. Você pode fazer coisas arbitrariamente complexas funcionarem através da simplicidade e velocidade do python bruto.

As
compreensões da Lista de Advertências pressupõem que seus dados sejam fáceis de trabalhar - o que significa que seus tipos de dados são consistentes e você não possui NaNs, mas isso nem sempre pode ser garantido.

  1. O primeiro é mais óbvio, mas ao lidar com NaNs, prefira métodos de pandas incorporados, se existirem (porque eles têm uma lógica de manipulação de canto muito melhor) ou garanta que sua lógica de negócios inclua uma lógica de manipulação de NaN apropriada.
  2. Ao lidar com tipos de dados mistos, você deve iterar em zip(df['A'], df['B'], ...)vez de, df[['A', 'B']].to_numpy()pois o último implica implicitamente em transferência de dados para o tipo mais comum. Como exemplo, se A for numérico e B for string, to_numpy()converterá toda a matriz em string, o que pode não ser o que você deseja. Felizmente, zippingar suas colunas juntas é a solução mais direta para isso.

* YMMV pelos motivos descritos na seção Advertências acima.


Um exemplo óbvio

Vamos demonstrar a diferença com um exemplo simples de adição de duas colunas de pandas A + B. Como é uma operação vetorizável, será fácil contrastar o desempenho dos métodos discutidos acima.

insira a descrição da imagem aqui

Código de benchmarking, para sua referência.

Devo mencionar, no entanto, que nem sempre é tão fácil assim. Às vezes, a resposta para "qual é o melhor método para uma operação" é "depende dos seus dados". Meu conselho é testar diferentes abordagens nos seus dados antes de escolher um.


Leitura adicional

* Os métodos de string do Pandas são "vetorizados" no sentido em que são especificados na série, mas operam em cada elemento. Os mecanismos subjacentes ainda são iterativos, porque as operações de cadeia de caracteres são inerentemente difíceis de vetorizar.


Por que escrevi esta resposta

Uma tendência comum que noto de novos usuários é fazer perguntas do formulário "como posso iterar meu df para fazer o X?". Mostrando código que chama iterrows()enquanto faz algo dentro de um loop for. Aqui está o porquê. Um novo usuário da biblioteca que não tenha sido introduzido no conceito de vetorização provavelmente visualizará o código que resolve o problema como iterando sobre os dados para fazer alguma coisa. Sem saber como iterar em um DataFrame, a primeira coisa que eles fazem é pesquisar no Google e acabar aqui, nesta pergunta. Eles veem a resposta aceita dizendo como e fecham os olhos e executam esse código sem antes questionar se a iteração não é a coisa certa a fazer.

O objetivo desta resposta é ajudar os novos usuários a entender que a iteração não é necessariamente a solução para todos os problemas, e que soluções melhores, mais rápidas e mais idiomáticas podem existir, e que vale a pena investir tempo explorando-as. Não estou tentando iniciar uma guerra de iteração x vetorização, mas quero que novos usuários sejam informados ao desenvolver soluções para seus problemas com esta biblioteca.

cs95
fonte
24
Esta é a única resposta que se concentra nas técnicas idiomáticas que se deve usar com os pandas, tornando-a a melhor resposta para esta pergunta. Aprender a obter a resposta certa com o código certo (em vez da resposta certa com o código errado - ou seja, ineficiente, não escalável, muito adequado a dados específicos) é uma grande parte do aprendizado de pandas (e dados em geral).
LinkBerest
3
Eu acho que você está sendo injusto com o loop for, visto que eles são um pouco mais lentos que a compreensão da lista nos meus testes. O truque é fazer um loop em zip(df['A'], df['B'])vez de df.iterrows().
Noite imperecível
2
@ImperishableNight Nem um pouco; o objetivo deste post não é denunciar a iteração em geral - é denunciar especificamente o uso de iterrows()e implicitamente denunciar a iteração, se e quando existirem melhores alternativas. foros loops sozinhos são bons, mas a compreensão da lista é melhor se você estiver executando iterativamente transformações em elementos.
cs95
1
@sdbbs, use sort_values ​​para classificar seus dados, depois chame to_string () no resultado.
cs95
1
Em Compreensões de lista, o exemplo "iterando sobre várias colunas" precisa de uma ressalva: DataFrame.valuesconverterá todas as colunas em um tipo de dados comum. DataFrame.to_numpy()faz isso também. Felizmente, podemos usar zipcom qualquer número de colunas.
David Wasserman
397

Primeiro, considere se você realmente precisa iterar sobre as linhas em um DataFrame. Veja esta resposta para alternativas.

Se você ainda precisar iterar sobre as linhas, poderá usar os métodos abaixo. Observe algumas advertências importantes que não são mencionadas em nenhuma das outras respostas.

itertuples() é suposto ser mais rápido do que iterrows()

Mas esteja ciente, de acordo com os documentos (pandas 0.24.2 no momento):

  • iterrows: dtypepode não corresponder de uma linha para outra

    Como o iterrows retorna uma Série para cada linha, ele não preserva os tipos nas linhas (os tipos são preservados nas colunas dos DataFrames). Para preservar os dtypes durante a iteração nas linhas, é melhor usar itertuples (), que retorna nomes nomeados dos valores e geralmente é muito mais rápido do que iterrows ()

  • iterrows: Não modifique linhas

    Você nunca deve modificar algo sobre o qual está iterando. Não é garantido que funcione em todos os casos. Dependendo dos tipos de dados, o iterador retorna uma cópia e não uma visualização, e a gravação nela não terá efeito.

    Use DataFrame.apply () :

    new_df = df.apply(lambda x: x * 2)
  • itertuples:

    Os nomes das colunas serão renomeados para nomes posicionais se forem identificadores Python inválidos, repetidos ou começarem com um sublinhado. Com um grande número de colunas (> 255), as tuplas regulares são retornadas.

Consulte os documentos do pandas sobre iteração para obter mais detalhes.

viddik13
fonte
4
Apenas uma pequena pergunta de alguém que está lendo este tópico há muito tempo após sua conclusão: como o df.apply () se compara aos ituplos em termos de eficiência?
Raul Guarini 26/01
4
Nota: você também pode dizer algo como for row in df[['c1','c2']].itertuples(index=True, name=None):incluir apenas determinadas colunas no iterador da linha.
Brian Burns
12
Em vez de getattr(row, "c1"), você pode usar apenas row.c1.
Viraptor 13/08/19
1
Tenho cerca de 90% de certeza de que, se você usar em getattr(row, "c1")vez de row.c1, perderá qualquer vantagem de desempenho itertuplese, se realmente precisar acessar a propriedade por meio de uma string, use as linhas abaixo.
Noctiphobia
3
Eu me deparei com essa pergunta porque, embora soubesse que há combinação de aplicar e dividir, eu realmente precisava iterar sobre um DataFrame (como a pergunta afirma). Nem todo mundo tem o luxo de melhorar numbae cython(os mesmos documentos dizem que "sempre vale a pena otimizar no Python primeiro"). Escrevi esta resposta para ajudar outras pessoas a evitar problemas (às vezes frustrantes), pois nenhuma das outras respostas menciona essas advertências. Enganar alguém ou dizer "é a coisa certa a fazer" nunca foi minha intenção. Eu melhorei a resposta.
Viddik13 30/05/19
201

Você deveria usar df.iterrows(). Embora a iteração linha a linha não seja especialmente eficiente, pois os Seriesobjetos precisam ser criados.

Wes McKinney
fonte
12
Isso é mais rápido do que converter o DataFrame em uma matriz numpy (por meio de valores) e operar diretamente na matriz? Eu tenho o mesmo problema, mas acabei convertendo para uma matriz numpy e depois usando o cython.
precisa saber é o seguinte
12
@vgoklani Se a iteração linha a linha for ineficiente e você tiver uma matriz numpy não-objeto, quase certamente o uso da matriz numpy bruta será mais rápido, especialmente para matrizes com muitas linhas. você deve evitar a iteração sobre linhas a menos que seja absolutamente necessário
Phillip Nuvem
7
Fiz alguns testes no consumo de tempo para df.iterrows (), df.itertuples () e zip (df ['a'], df ['b']) e postei o resultado na resposta de outra pergunta: stackoverflow.com/a/34311080/2142098
Richard Wong
154

Embora iterrows()seja uma boa opção, às vezes itertuples()pode ser muito mais rápido:

df = pd.DataFrame({'a': randn(1000), 'b': randn(1000),'N': randint(100, 1000, (1000)), 'x': 'x'})

%timeit [row.a * 2 for idx, row in df.iterrows()]
# => 10 loops, best of 3: 50.3 ms per loop

%timeit [row[1] * 2 for row in df.itertuples()]
# => 1000 loops, best of 3: 541 µs per loop
e9t
fonte
5
Grande parte da diferença de horário nos seus dois exemplos parece ser devido ao fato de você parecer estar usando indexação baseada em rótulo para o comando .iterrows () e indexação baseada em número inteiro para o comando .itertuples ().
Alex
2
Para um quadro de dados baseado em dados financeiros (timestamp e 4x float), itertuples é 19,57 vezes mais rápido do que na minha máquina. Só for a,b,c in izip(df["a"],df["b"],df["c"]:é quase igualmente rápido.
harbun
7
Você pode explicar por que é mais rápido?
Abe Miessler
4
O @AbeMiessler coloca iterrows()cada linha de dados em uma série, enquanto itertuples()que não.
Miradulo
3
Observe que a ordem das colunas é realmente indeterminada, porque dfé criada a partir de um dicionário, portanto, row[1]pode se referir a qualquer uma das colunas. Acontece que os tempos são aproximadamente os mesmos para o número inteiro versus as colunas flutuantes.
Brian Burns
88

Você também pode usar df.apply()para iterar sobre linhas e acessar várias colunas para uma função.

docs: DataFrame.apply ()

def valuation_formula(x, y):
    return x * y * 0.5

df['price'] = df.apply(lambda row: valuation_formula(row['x'], row['y']), axis=1)
cheekybastard
fonte
O df ['price'] refere-se a um nome de coluna no quadro de dados? Estou tentando criar um dicionário com valores exclusivos de várias colunas em um arquivo csv. Usei sua lógica para criar um dicionário com chaves e valores exclusivos e recebi um erro ao declarar TypeError: ("os objetos 'Series' são mutáveis, portanto, não podem ser hash", ocorreu no índice 0 ')
SRS
Código: df ['Workclass'] = df.apply (linha lambda: dic_update (linha), eixo = 1) ID do fim da linha = 0 fim da linha def dic_update (linha): se a linha não estiver em dic: dic [linha] = id id = id + 1
SRS
Não importa, eu entendi. Mudou a linha chamada de função para . Df_new = df [ 'Workclass'] aplicam-se (mesma coisa)
SRS
2
Ter o eixo padrão como 0 é o pior
zthomas.nc 29/11
9
Observe que applynão "iteratita" sobre linhas, mas aplica uma função em linhas. O código acima não iria funcionar se você realmente fazer iterações necessidade e indeces, por exemplo quando se comparam os valores em diferentes linhas (nesse caso, você não pode fazer nada, mas iteração).
usar o seguinte comando
82

Você pode usar a função df.iloc da seguinte maneira:

for i in range(0, len(df)):
    print df.iloc[i]['c1'], df.iloc[i]['c2']
PJay
fonte
1
Eu sei que é preciso evitar isso em favor de linhas ou itens simples, mas seria interessante saber o porquê. Alguma ideia?
Roquevaj #
12
Essa é a única técnica válida que eu conheço se você deseja preservar os tipos de dados e também se refere às colunas pelo nome. itertuplespreserva os tipos de dados, mas se livra de qualquer nome que não goste. iterrowsfaz o oposto.
Ken Williams
6
Passamos horas tentando percorrer as idiossincrasias das estruturas de dados dos pandas para fazer algo simples E expressivo. Isso resulta em código legível.
Sean Anderson
Embora for i in range(df.shape[0])possa acelerar um pouco essa abordagem, ainda é cerca de 3,5x mais lenta que a abordagem iterrows () acima para o meu aplicativo.
22818 Kim Miller
Em grandes Datafrmes, isso parece melhor, pois my_iter = df.itertuples()leva o dobro da memória e muito tempo para copiá-la. o mesmo para iterrows().
Bastiaan
33

Eu estava procurando como iterar em linhas e colunas e terminou aqui, então:

for i, row in df.iterrows():
    for j, column in row.iteritems():
        print(column)
Lucas B
fonte
18

Você pode escrever seu próprio iterador que implementa namedtuple

from collections import namedtuple

def myiter(d, cols=None):
    if cols is None:
        v = d.values.tolist()
        cols = d.columns.values.tolist()
    else:
        j = [d.columns.get_loc(c) for c in cols]
        v = d.values[:, j].tolist()

    n = namedtuple('MyTuple', cols)

    for line in iter(v):
        yield n(*line)

Isto é diretamente comparável a pd.DataFrame.itertuples. Meu objetivo é executar a mesma tarefa com mais eficiência.


Para o dado quadro de dados com minha função:

list(myiter(df))

[MyTuple(c1=10, c2=100), MyTuple(c1=11, c2=110), MyTuple(c1=12, c2=120)]

Ou com pd.DataFrame.itertuples:

list(df.itertuples(index=False))

[Pandas(c1=10, c2=100), Pandas(c1=11, c2=110), Pandas(c1=12, c2=120)]

Um teste abrangente
Testamos a disponibilização de todas as colunas e o subconjunto delas.

def iterfullA(d):
    return list(myiter(d))

def iterfullB(d):
    return list(d.itertuples(index=False))

def itersubA(d):
    return list(myiter(d, ['col3', 'col4', 'col5', 'col6', 'col7']))

def itersubB(d):
    return list(d[['col3', 'col4', 'col5', 'col6', 'col7']].itertuples(index=False))

res = pd.DataFrame(
    index=[10, 30, 100, 300, 1000, 3000, 10000, 30000],
    columns='iterfullA iterfullB itersubA itersubB'.split(),
    dtype=float
)

for i in res.index:
    d = pd.DataFrame(np.random.randint(10, size=(i, 10))).add_prefix('col')
    for j in res.columns:
        stmt = '{}(d)'.format(j)
        setp = 'from __main__ import d, {}'.format(j)
        res.at[i, j] = timeit(stmt, setp, number=100)

res.groupby(res.columns.str[4:-1], axis=1).plot(loglog=True);

insira a descrição da imagem aqui

insira a descrição da imagem aqui

piRSquared
fonte
2
Para pessoas que não querem ler o código: linha azul é intertuples, linha laranja é uma lista de um iterador através de um bloco de rendimento. interrowsnão é comparado.
James L.
18

Como iterar eficientemente?

Se você realmente precisa iterar um quadro de dados do pandas, provavelmente desejará evitar o uso de iterrows () . Existem métodos diferentes e o usual iterrows()está longe de ser o melhor. itertuples () pode ser 100 vezes mais rápido.

Em resumo:

  • Como regra geral, use df.itertuples(name=None). Em particular, quando você tem um número fixo de colunas e menos de 255 colunas. Ver ponto 3)
  • Caso contrário, use, df.itertuples()exceto se suas colunas tiverem caracteres especiais, como espaços ou '-'. Ver ponto 2)
  • É possível usar itertuples()mesmo se o seu quadro de dados tiver colunas estranhas usando o último exemplo. Ver ponto (4)
  • Use apenas iterrows()se você não conseguir as soluções anteriores. Ver ponto 1)

Métodos diferentes para iterar sobre linhas em um dataframe do pandas:

Gere um quadro de dados aleatório com um milhão de linhas e 4 colunas:

    df = pd.DataFrame(np.random.randint(0, 100, size=(1000000, 4)), columns=list('ABCD'))
    print(df)

1) O habitual iterrows()é conveniente, mas muito lento:

start_time = time.clock()
result = 0
for _, row in df.iterrows():
    result += max(row['B'], row['C'])

total_elapsed_time = round(time.clock() - start_time, 2)
print("1. Iterrows done in {} seconds, result = {}".format(total_elapsed_time, result))

2) O padrão itertuples()já é muito mais rápido, mas não funciona com nomes de colunas como My Col-Name is very Strange(você deve evitar esse método se suas colunas forem repetidas ou se um nome de coluna não puder ser simplesmente convertido em um nome de variável python) .:

start_time = time.clock()
result = 0
for row in df.itertuples(index=False):
    result += max(row.B, row.C)

total_elapsed_time = round(time.clock() - start_time, 2)
print("2. Named Itertuples done in {} seconds, result = {}".format(total_elapsed_time, result))

3) O padrão itertuples()usando name = None é ainda mais rápido, mas não é realmente conveniente, pois você precisa definir uma variável por coluna.

start_time = time.clock()
result = 0
for(_, col1, col2, col3, col4) in df.itertuples(name=None):
    result += max(col2, col3)

total_elapsed_time = round(time.clock() - start_time, 2)
print("3. Itertuples done in {} seconds, result = {}".format(total_elapsed_time, result))

4) Finalmente, o nomeado itertuples()é mais lento que o ponto anterior, mas você não precisa definir uma variável por coluna e funciona com nomes de colunas como My Col-Name is very Strange.

start_time = time.clock()
result = 0
for row in df.itertuples(index=False):
    result += max(row[df.columns.get_loc('B')], row[df.columns.get_loc('C')])

total_elapsed_time = round(time.clock() - start_time, 2)
print("4. Polyvalent Itertuples working even with special characters in the column name done in {} seconds, result = {}".format(total_elapsed_time, result))

Resultado:

         A   B   C   D
0       41  63  42  23
1       54   9  24  65
2       15  34  10   9
3       39  94  82  97
4        4  88  79  54
...     ..  ..  ..  ..
999995  48  27   4  25
999996  16  51  34  28
999997   1  39  61  14
999998  66  51  27  70
999999  51  53  47  99

[1000000 rows x 4 columns]

1. Iterrows done in 104.96 seconds, result = 66151519
2. Named Itertuples done in 1.26 seconds, result = 66151519
3. Itertuples done in 0.94 seconds, result = 66151519
4. Polyvalent Itertuples working even with special characters in the column name done in 2.94 seconds, result = 66151519

Este artigo é uma comparação muito interessante entre iterrows e itertuples

Romain Capron
fonte
14

Para fazer o loop de todas as linhas em um dataframevocê pode usar:

for x in range(len(date_example.index)):
    print date_example['Date'].iloc[x]
CONvid19
fonte
1
Isso é indexação encadeada. Eu não recomendo fazer isso.
cs95
@ cs95 O que você recomendaria?
perfil completo de CONvid19
Se você quiser fazer isso funcionar, chame df.columns.get_loc para obter a posição do índice inteiro da coluna date (fora do loop) e use uma única chamada de indexação iloc dentro.
cs95
14
 for ind in df.index:
     print df['c1'][ind], df['c2'][ind]
Grag2015
fonte
1
como é o desempenho dessa opção quando usada em um quadro de dados grande (milhões de linhas, por exemplo)?
Bazyli Debowski
Honestamente, não sei exatamente, acho que, em comparação com a melhor resposta, o tempo decorrido será o mesmo, porque ambos os casos usam a construção "para". Mas a memória pode ser diferente em alguns casos.
Grag2015
4
Isso é indexação encadeada. Não use isso!
cs95
7

Às vezes, um padrão útil é:

# Borrowing @KutalmisB df example
df = pd.DataFrame({'col1': [1, 2], 'col2': [0.1, 0.2]}, index=['a', 'b'])
# The to_dict call results in a list of dicts
# where each row_dict is a dictionary with k:v pairs of columns:value for that row
for row_dict in df.to_dict(orient='records'):
    print(row_dict)

O que resulta em:

{'col1':1.0, 'col2':0.1}
{'col1':2.0, 'col2':0.2}
Zach
fonte
6

Para fazer o loop de todas as linhas em a dataframee usar os valores de cada linha convenientemente , namedtuplespode ser convertido em ndarrays. Por exemplo:

df = pd.DataFrame({'col1': [1, 2], 'col2': [0.1, 0.2]}, index=['a', 'b'])

Iterando sobre as linhas:

for row in df.itertuples(index=False, name='Pandas'):
    print np.asarray(row)

resulta em:

[ 1.   0.1]
[ 2.   0.2]

Observe que, se index=True, o índice é adicionado como o primeiro elemento do tuplo , que podem ser indesejáveis para algumas aplicações.

Engenheiro Livre de Herpes
fonte
5

Existe uma maneira de iterar as linhas de lançamento ao obter um DataFrame em troca, e não uma Série. Não vejo ninguém mencionando que você pode passar o índice como uma lista para a linha ser retornada como um DataFrame:

for i in range(len(df)):
    row = df.iloc[[i]]

Observe o uso de colchetes duplos. Isso retorna um DataFrame com uma única linha.

Zeitgeist
fonte
Isso foi muito útil para obter a enésima maior linha em um quadro de dados após a classificação. Obrigado!
Jason Harrison
3

Para visualizar e modificar valores, eu usaria iterrows(). Em um loop for e usando a descompactação da tupla (veja o exemplo i, row:), eu uso o rowpara exibir apenas o valor e o uso icom o locmétodo quando desejar modificar valores. Conforme declarado nas respostas anteriores, aqui você não deve modificar algo sobre o qual está iterando.

for i, row in df.iterrows():
    df_column_A = df.loc[i, 'A']
    if df_column_A == 'Old_Value':
        df_column_A = 'New_value'  

Aqui row, o loop é uma cópia dessa linha, e não uma visão dela. Portanto, você NÃO deve escrever algo como row['A'] = 'New_Value'isso não modificará o DataFrame. No entanto, você pode usar ie loce especificar a trama de dados para fazer o trabalho.

Hossein
fonte
2

Sei que estou atrasado para a parte que responde, mas só quero adicionar a resposta do @ cs95 acima, que acredito que deve ser a resposta aceita. Em sua resposta, ele mostra que a vetorização de pandas supera em muito outros métodos de pandas para calcular coisas com quadros de dados.

Eu gostaria de acrescentar que, se você primeiro converter o quadro de dados em uma matriz numpy e depois usar a vetorização, é ainda mais rápido que a vetorização de quadro de dados do pandas (e isso inclui tempo para transformá-lo novamente em uma série de quadros de dados).

Se você adicionar as seguintes funções ao código de referência do @ cs95, isso se tornará bastante evidente:

def np_vectorization(df):
    np_arr = df.to_numpy()
    return pd.Series(np_arr[:,0] + np_arr[:,1], index=df.index)

def just_np_vectorization(df):
    np_arr = df.to_numpy()
    return np_arr[:,0] + np_arr[:,1]

insira a descrição da imagem aqui

bug_spray
fonte
1

Você também pode fazer a numpyindexação para acelerar ainda mais. Não é realmente iterativo, mas funciona muito melhor do que a iteração para certos aplicativos.

subset = row['c1'][0:5]
all = row['c1'][:]

Você também pode querer convertê-lo em uma matriz. Esses índices / seleções devem agir como matrizes Numpy, mas eu tive problemas e precisei transmitir

np.asarray(all)
imgs[:] = cv2.resize(imgs[:], (224,224) ) #resize every image in an hdf5 file
James L.
fonte
1

Existem muitas maneiras de iterar sobre as linhas no dataframe do pandas. Uma maneira muito simples e intuitiva é:

df=pd.DataFrame({'A':[1,2,3], 'B':[4,5,6],'C':[7,8,9]})
print(df)
for i in range(df.shape[0]):
    # For printing the second column
    print(df.iloc[i,1])
    # For printing more than one columns
    print(df.iloc[i,[0,2]])
Shubham Ranjan
fonte
0

Este exemplo usa o iloc para isolar cada dígito no quadro de dados.

import pandas as pd

 a = [1, 2, 3, 4]
 b = [5, 6, 7, 8]

 mjr = pd.DataFrame({'a':a, 'b':b})

 size = mjr.shape

 for i in range(size[0]):
     for j in range(size[1]):
         print(mjr.iloc[i, j])
mjr2000
fonte
0

Algumas bibliotecas (por exemplo, uma biblioteca de interoperabilidade Java que eu uso) exigem que os valores sejam transmitidos em uma linha por vez, por exemplo, ao transmitir dados. Para replicar a natureza do streaming, eu transmito meus valores do quadro de dados um por um, escrevi abaixo, o que é útil de tempos em tempos.

class DataFrameReader:
  def __init__(self, df):
    self._df = df
    self._row = None
    self._columns = df.columns.tolist()
    self.reset()
    self.row_index = 0

  def __getattr__(self, key):
    return self.__getitem__(key)

  def read(self) -> bool:
    self._row = next(self._iterator, None)
    self.row_index += 1
    return self._row is not None

  def columns(self):
    return self._columns

  def reset(self) -> None:
    self._iterator = self._df.itertuples()

  def get_index(self):
    return self._row[0]

  def index(self):
    return self._row[0]

  def to_dict(self, columns: List[str] = None):
    return self.row(columns=columns)

  def tolist(self, cols) -> List[object]:
    return [self.__getitem__(c) for c in cols]

  def row(self, columns: List[str] = None) -> Dict[str, object]:
    cols = set(self._columns if columns is None else columns)
    return {c : self.__getitem__(c) for c in self._columns if c in cols}

  def __getitem__(self, key) -> object:
    # the df index of the row is at index 0
    try:
        if type(key) is list:
            ix = [self._columns.index(key) + 1 for k in key]
        else:
            ix = self._columns.index(key) + 1
        return self._row[ix]
    except BaseException as e:
        return None

  def __next__(self) -> 'DataFrameReader':
    if self.read():
        return self
    else:
        raise StopIteration

  def __iter__(self) -> 'DataFrameReader':
    return self

Qual pode ser usado:

for row in DataFrameReader(df):
  print(row.my_column_name)
  print(row.to_dict())
  print(row['my_column_name'])
  print(row.tolist())

E preserva o mapeamento de valores / nome para as linhas que estão sendo iteradas. Obviamente, é muito mais lento do que usar o apply e o Cython, conforme indicado acima, mas é necessário em algumas circunstâncias.

morganics
fonte
0

Em resumo

  • Use vetorização, se possível
  • Se a operação não puder ser vetorizada - use a compreensão da lista
  • Se você precisar de um único objeto representando a linha inteira - use itertuples
  • Se o acima estiver muito lento - tente swifter.apply
  • Se ainda estiver muito lento - tente a rotina Cython

Detalhes neste vídeo

Referência Referência de iteração sobre linhas em um DataFrame do pandas

Artoby
fonte