146 votes

Pandas en python : Conserver la colonne sélectionnée comme DataFrame au lieu de Series

Lors de la sélection d'une seule colonne dans un DataFrame pandas (disons df.iloc[:, 0] , df['A'] o df.A etc.), le vecteur résultant est automatiquement converti en une série au lieu d'un DataFrame à une seule colonne. Cependant, j'écris certaines fonctions qui prennent un DataFrame comme argument d'entrée. Par conséquent, je préfère traiter un DataFrame à une seule colonne plutôt qu'une série afin que la fonction puisse supposer que df.columns est accessible. Actuellement, je dois convertir explicitement les séries en DataFrame en utilisant quelque chose comme pd.DataFrame(df.iloc[:, 0]) . Cela ne semble pas être la méthode la plus propre. Existe-t-il une manière plus élégante d'indexer directement à partir d'un DataFrame afin que le résultat soit un DataFrame à une seule colonne au lieu d'une série ?

146voto

Andy Hayden Points 38010

Comme le mentionne @Jeff, il y a plusieurs façons de le faire, mais je recommande d'utiliser loc/iloc pour être plus explicite (et de lever les erreurs rapidement si vous essayez quelque chose d'ambigu) :

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

Ces deux derniers choix permettent de lever l'ambiguïté dans le cas de noms de colonnes entières (c'est précisément la raison pour laquelle loc/iloc ont été créés). Par exemple :

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

15voto

Sumanth Lazarus Points 29

Comme Andy Hayden recommande l'utilisation de .iloc/.loc pour indexer un cadre de données (à une seule colonne) ; un autre point à noter est la façon d'exprimer les positions d'index. Utilisez un Liste des étiquettes/positions de l'index tout en spécifiant les valeurs de l'argument à indexer en tant que Dataframe ; si ce n'est pas le cas, un message 'pandas.core.series.Series' sera renvoyé.

Entrée :

    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))

Sortie :

    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'>

6voto

Null_Vallue_ Points 51

Ces trois approches ont été mentionnées :

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() est une autre approche.

Comme il s'agit d'une méthode, elle peut être utilisée dans des situations où les deuxième et troisième approches ci-dessus ne s'appliquent pas. En particulier, elle est utile lorsque vous appliquez une méthode à une colonne de votre cadre de données et que vous souhaitez convertir la sortie en un cadre de données plutôt qu'en une série. Par exemple, dans un Jupyter Notebook, une série n'aura pas une belle sortie, mais un dataframe en aura une.

# 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()

3voto

p47hf1nd3r Points 536

Vous pouvez utiliser df.iloc[:, 0:1] dans ce cas, le vecteur résultant sera a DataFrame et non des séries.

Comme vous pouvez le voir :

enter image description here

1voto

TaylorV Points 341

(Parler des pandas 1.3.4)

Je voudrais ajouter un peu plus de contexte aux réponses impliquant .to_frame() . Si vous sélectionnez une seule ligne d'un cadre de données et que vous exécutez la commande .to_frame() sur cela, alors l'index sera composé des noms de colonnes originaux et vous obtiendrez des noms de colonnes numériques. Vous pouvez simplement ajouter un .T à la fin pour transposer le tout dans le format du cadre de données original (voir ci-dessous).

import pandas as pd
print(pd.__version__)  #1.3.4

df = pd.DataFrame({
    "col1": ["a", "b", "c"],
    "col2": [1, 2, 3]
})

# series
df.loc[0, ["col1", "col2"]]

# dataframe (column names are along the index; not what I wanted)
df.loc[0, ["col1", "col2"]].to_frame()
    #       0
    # col1  a
    # col2  1

# looks like an actual single-row dataframe.
# To me, this is the true answer to the question
# because the output matches the format of the
# original dataframe.
df.loc[0, ["col1", "col2"]].to_frame().T
    #   col1 col2
    # 0    a    1

# this works really well with .to_dict(orient="records") which is 
# what I'm ultimately after by selecting a single row
df.loc[0, ["col1", "col2"]].to_frame().T.to_dict(orient="records")
    # [{'col1': 'a', 'col2': 1}]

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X