Quais regras o Pandas usa para gerar uma visualização em vez de uma cópia?

118

Estou confuso sobre as regras que o Pandas usa ao decidir que uma seleção de um dataframe é uma cópia do dataframe original ou uma visualização do original.

Se eu tenho, por exemplo,

df = pd.DataFrame(np.random.randn(8,8), columns=list('ABCDEFGH'), index=range(1,9))

Eu entendo que a querydevolve uma cópia para que algo como

foo = df.query('2 < index <= 5')
foo.loc[:,'E'] = 40

não terá nenhum efeito sobre a trama de dados original, df. Eu também entendo que fatias escalares ou nomeadas retornam uma visualização, de modo que as atribuições a elas, como

df.iloc[3] = 70

ou

df.ix[1,'B':'E'] = 222

vai mudar df. Mas estou perdido quando se trata de casos mais complicados. Por exemplo,

df[df.C <= df.B] = 7654321

mudanças df, mas

df[df.C <= df.B].ix[:,'B':'E']

não.

Existe uma regra simples que o Pandas está usando e que estou perdendo? O que está acontecendo nesses casos específicos; e, em particular, como altero todos os valores (ou um subconjunto de valores) em um dataframe que satisfaça uma consulta específica (como estou tentando fazer no último exemplo acima)?


Nota: Esta não é a mesma questão ; e eu li a documentação , mas não fui esclarecido por ela. Eu também li as questões "Relacionadas" neste tópico, mas ainda estou perdendo a regra simples que o Pandas está usando e como eu a aplicaria para - por exemplo - modificar os valores (ou um subconjunto de valores) em um dataframe que satisfaça uma consulta específica.

orome
fonte

Respostas:

138

Estas são as regras, modificação subsequente:

  • Todas as operações geram uma cópia

  • Se inplace=Truefor fornecido, ele será modificado no local; apenas algumas operações suportam isso

  • Um indexador que define, por exemplo, .loc/.iloc/.iat/.atirá definir no local.

  • Um indexador que obtém um objeto com dtipo único quase sempre é uma visualização (dependendo do layout da memória, pode não ser, por isso não é confiável). Isso é principalmente para eficiência. (o exemplo acima é para .query; isso sempre retornará uma cópia conforme avaliada por numexpr)

  • Um indexador que obtém um objeto com vários tipos de dados é sempre uma cópia.

Seu exemplo de chained indexing

df[df.C <= df.B].loc[:,'B':'E']

não é garantido que funcione (e, portanto, você nunca deve fazer isso).

Em vez disso, faça:

df.loc[df.C <= df.B, 'B':'E']

pois isso é mais rápido e sempre funcionará

A indexação encadeada consiste em 2 operações python separadas e, portanto, não pode ser interceptada de forma confiável por pandas (muitas vezes você obterá um SettingWithCopyWarning, mas também não será 100% detectável). Os dev docs , que você apontou, oferecem uma explicação muito mais completa.

Jeff
fonte
3
.querySEMPRE retornará uma cópia por causa do que está fazendo (e não uma visão), porque é avaliada por n numexpr. Então, vou adicionar isso às 'regras'
Jeff,
3
O pandas depende do numpy para determinar se uma visualização é gerada. Em um único caso de tipo d (que pode ser 1-d para uma série, 2-d para um quadro, etc). numpy pode gerar uma visualização; depende do que você está fatiando; às vezes você pode ter uma visão e às vezes não. Os pandas não contam com esse fato, pois nem sempre é óbvio se uma visualização é gerada. mas isso não importa, já que loc não depende disso ao configurar. No entanto, quando a indexação de cadeia é muito importante (e, portanto, por que a indexação de cadeia é ruim)
Jeff,
3
Muito obrigado Jeff, sua resposta é muito útil. Qual é a sua fonte / referência neste tópico?
Kamixave
4
Então, primeiro, obrigado pelo seu excelente trabalho! E em segundo lugar, se você tiver tempo suficiente, acho que seria ótimo adicionar um parágrafo semelhante à sua resposta principal no documento.
Kamixave
2
certamente seria necessário uma solicitação pull para adicionar / revisar os documentos. vá em frente.
Jeff