Python pandas: mantenha a coluna selecionada como DataFrame em vez de Series

99

Ao seleccionar uma única coluna a partir de uma trama de dados pandas (por exemplo df.iloc[:, 0], df['A'], ou df.A, etc), o vector resultante é automaticamente convertido a uma série em vez de uma trama de dados de uma única coluna. No entanto, estou escrevendo algumas funções que levam um DataFrame como argumento de entrada. Portanto, prefiro lidar com DataFrame de coluna única em vez de Series para que a função possa assumir, digamos, df.columns como acessível. Agora eu tenho que converter explicitamente a série em um DataFrame usando algo parecido pd.DataFrame(df.iloc[:, 0]). Este não parece o método mais limpo. Existe uma maneira mais elegante de indexar de um DataFrame diretamente para que o resultado seja um DataFrame de coluna única em vez de Series?


fonte
6
df.iloc [:, [0]] ou df [['A']]; df.A apenas retribuirá uma série
Jeff

Respostas:

104

Como @Jeff menciona, existem algumas maneiras de fazer isso, mas recomendo usar loc / iloc para ser mais explícito (e levantar erros no início, se estiver tentando algo ambíguo):

In [10]: df = pd.DataFrame([[1, 2], [3, 4]], columns=['A', 'B'])

In [11]: df
Out[11]:
   A  B
0  1  2
1  3  4

In [12]: df[['A']]

In [13]: df[[0]]

In [14]: df.loc[:, ['A']]

In [15]: df.iloc[:, [0]]

Out[12-15]:  # they all return the same thing:
   A
0  1
1  3

As duas últimas opções removem a ambigüidade no caso de nomes de colunas inteiras (precisamente por que loc / iloc foram criados). Por exemplo:

In [16]: df = pd.DataFrame([[1, 2], [3, 4]], columns=['A', 0])

In [17]: df
Out[17]:
   A  0
0  1  2
1  3  4

In [18]: df[[0]]  # ambiguous
Out[18]:
   A
0  1
1  3
Andy Hayden
fonte
2
Desculpe incomodá-lo, mas apenas uma pergunta muito rápida sobre isso. Eu vejo como o extra []torna o resultado um em DataFramevez de um Series, mas onde nos documentos do pandas esse tipo de sintaxe de indexação é discutido? Estou apenas tentando obter o nome "oficial" para esta técnica de indexação para que eu realmente entenda. THX!
sparc_spread
3
@sparc_spread pandas.pydata.org/pandas-docs/stable/indexing.html#basics "Você pode passar uma lista de colunas para [] para selecionar as colunas nessa ordem." Não tenho certeza se isso tem um nome!
Andy Hayden
Sim, parece que não tem um - mas vou continuar usando a partir de agora. É incrível a quantidade de coisas enterradas na API e nos documentos. THX!
sparc_spread
Essa distinção foi útil para mim, porque às vezes eu quero um DataFrame de coluna única para poder usar métodos DataFrame nos dados que não estavam disponíveis em Series. (ISTR o método de plot se comportou de maneira diferente). Foi uma epifania para mim quando percebi que poderia usar uma lista de um único elemento!
RufusVS
4

Como Andy Hayden recomenda, utilizar .iloc / .loc para indexar dataframe (coluna única) é o caminho a percorrer; outro ponto a ser observado é como expressar as posições do índice. Use marcadores / posições de índice listados enquanto especifica os valores dos argumentos a serem indexados como Dataframe; não fazer isso retornará um 'pandas.core.series.Series'

Entrada:

    A_1 = train_data.loc[:,'Fraudster']
    print('A_1 is of type', type(A_1))
    A_2 = train_data.loc[:, ['Fraudster']]
    print('A_2 is of type', type(A_2))
    A_3 = train_data.iloc[:,12]
    print('A_3 is of type', type(A_3))
    A_4 = train_data.iloc[:,[12]]
    print('A_4 is of type', type(A_4))

Resultado:

    A_1 is of type <class 'pandas.core.series.Series'>
    A_2 is of type <class 'pandas.core.frame.DataFrame'>
    A_3 is of type <class 'pandas.core.series.Series'>
    A_4 is of type <class 'pandas.core.frame.DataFrame'>
Sumanth Lazarus
fonte
2

Você pode usar df.iloc[:, 0:1], neste caso, o vetor resultante será a DataFramee não uma série.

Como você pode ver:

insira a descrição da imagem aqui

p47hf1nd3r
fonte
1

Essas três abordagens foram mencionadas:

pd.DataFrame(df.loc[:, 'A'])  # Approach of the original post
df.loc[:,[['A']]              # Approach 2 (note: use iloc for positional indexing)
df[['A']]                     # Approach 3

pd.Series.to_frame () é outra abordagem.

Por ser um método, pode ser usado em situações em que a segunda e a terceira abordagens acima não se aplicam. Em particular, é útil ao aplicar algum método a uma coluna em seu dataframe e você deseja converter a saída em um dataframe em vez de uma série. Por exemplo, em um Notebook Jupyter, uma série não terá uma saída bonita, mas um dataframe terá.

# Basic use case: 
df['A'].to_frame()

# Use case 2 (this will give you pretty output in a Jupyter Notebook): 
df['A'].describe().to_frame()

# Use case 3: 
df['A'].str.strip().to_frame()

# Use case 4: 
def some_function(num): 
    ...

df['A'].apply(some_function).to_frame()
Null_Vallue_
fonte