Python pandas: mantenga la columna seleccionada como DataFrame en lugar de Serie

92

Al seleccionar una sola columna de un DataFrame de pandas (digamos df.iloc[:, 0], df['A']o df.A, etc.), el vector resultante se convierte automáticamente en una Serie en lugar de en un DataFrame de una sola columna. Sin embargo, estoy escribiendo algunas funciones que toman un DataFrame como argumento de entrada. Por lo tanto, prefiero tratar con DataFrame de una sola columna en lugar de Series para que la función pueda asumir que df.columns es accesible. En este momento tengo que convertir explícitamente la Serie en un DataFrame usando algo como pd.DataFrame(df.iloc[:, 0]). Este no parece el método más limpio. ¿Existe una forma más elegante de indexar desde un DataFrame directamente para que el resultado sea un DataFrame de una sola columna en lugar de una Serie?


fuente
6
df.iloc [:, [0]] o df [['A']]; df.A solo devolverá una serie sin embargo
Jeff

Respuestas:

99

Como menciona @Jeff, hay algunas formas de hacer esto, pero recomiendo usar loc / iloc para ser más explícito (y generar errores temprano si intentas algo ambiguo):

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

Las dos últimas opciones eliminan la ambigüedad en el caso de nombres de columnas enteros (precisamente por qué se crearon loc / iloc). Por ejemplo:

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
fuente
2
Lamento molestarlo, pero solo una pregunta muy rápida sobre esto. Veo cómo el extra []hace que el resultado sea a en DataFramelugar de a Series, pero ¿en qué parte de los documentos de pandas se discute este tipo de sintaxis de indexación? Solo estoy tratando de obtener el nombre "oficial" de esta técnica de indexación para que realmente la entienda. ¡Gracias!
sparc_spread
3
@sparc_spread pandas.pydata.org/pandas-docs/stable/indexing.html#basics "Puede pasar una lista de columnas a [] para seleccionar columnas en ese orden". ¡No estoy seguro de si esto tiene un nombre!
Andy Hayden
Sí, parece que no tiene uno, pero lo seguiré usando a partir de ahora. Es increíble la cantidad de cosas que hay enterradas tanto en la API como en los documentos. ¡Gracias!
sparc_spread
Esta distinción ha sido útil para mí, porque a veces quiero un DataFrame de una sola columna para poder usar los métodos de DataFrame en los datos que no estaban disponibles en Series. (ISTR el método de la gráfica se comportó de manera diferente). Fue una epifanía para mí cuando me di cuenta de que podía usar una lista de un solo elemento.
RufusVS
4

Como recomienda Andy Hayden , utilizar .iloc / .loc para indexar el marco de datos (de una sola columna) es el camino a seguir; otro punto a tener en cuenta es cómo expresar las posiciones del índice. Use etiquetas / posiciones de índice enumeradas mientras especifica los valores de los argumentos para indexar como Dataframe; si no lo hace, se devolverá un '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))

Salida:

    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
fuente
1

Puede usar df.iloc[:, 0:1], en este caso el vector resultante será unDataFrame y no una serie.

Como puedes ver:

ingrese la descripción de la imagen aquí

p47hf1nd3r
fuente
1

Se han mencionado estos tres enfoques:

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 () es otro enfoque.

Debido a que es un método, se puede utilizar en situaciones en las que el segundo y tercer enfoque anteriores no se aplican. En particular, es útil cuando se aplica algún método a una columna en su marco de datos y desea convertir la salida en un marco de datos en lugar de una serie. Por ejemplo, en un Jupyter Notebook, una serie no tendrá una salida bonita, pero un marco de datos sí.

# 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_
fuente