【问题标题】:Python pandas: Keep selected column as DataFrame instead of SeriesPython pandas:将所选列保留为 DataFrame 而不是 Series
【发布时间】:2013-05-22 20:24:15
【问题描述】:

当从 pandas DataFrame(比如df.iloc[:, 0]df['A']df.A 等)中选择单列时,生成的向量会自动转换为 Series 而不是单列 DataFrame。但是,我正在编写一些将 DataFrame 作为输入参数的函数。因此,我更喜欢处理单列 DataFrame 而不是 Series,以便函数可以假设 df.columns 是可访问的。现在,我必须使用pd.DataFrame(df.iloc[:, 0]) 之类的东西将 Series 显式转换为 DataFrame。这似乎不是最干净的方法。有没有更优雅的方式直接从 DataFrame 中进行索引,以便结果是单列 DataFrame 而不是 Series?

【问题讨论】:

  • df.iloc[:,[0]] 或 df[['A']]; df.A 只会返回一个系列

标签: python pandas


【解决方案1】:

正如@Jeff 提到的,有几种方法可以做到这一点,但我建议使用 loc/iloc 更明确(如果您尝试一些模棱两可的事情,请尽早提出错误):

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

后两种选择消除了整数列名情况下的歧义(正是创建 loc/iloc 的原因)。例如:

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

【讨论】:

  • 很抱歉打扰您,但只是一个非常简短的问题。我看到额外的[] 如何使结果成为DataFrame 而不是Series,但是在pandas 文档中的哪里讨论了这种索引语法?我只是想获得这种索引技术的“官方”名称,以便我真正理解它。谢谢!
  • @sparc_spread pandas.pydata.org/pandas-docs/stable/indexing.html#basics "您可以将列列表传递给 [] 以按该顺序选择列。"我不确定这是否有名字!
  • 是的,它看起来好像没有 - 但我会从现在开始继续使用它。令人惊讶的是,API 和文档中隐藏了多少东西。谢谢!
  • 这种区别对我很有用,因为有时我想要一个单列 DataFrame,这样我就可以对 Series 上不可用的数据使用 DataFrame 方法。 (ISTR plot 方法的行为不同)。当我意识到我可以使用单元素列表时,我顿悟了!
【解决方案2】:

正如 Andy Hayden 所建议的,使用 .iloc/.loc 来索引(单列)数据框是可行的方法;还有一点需要注意的是如何表示索引位置。 使用列出的索引标签/位置,同时指定要作为数据帧索引的参数值;否则将返回“pandas.core.series.Series”

输入:

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

输出:

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

【讨论】:

    【解决方案3】:

    您可以使用df.iloc[:, 0:1],在这种情况下,结果向量将是DataFrame,而不是系列。

    如你所见:

    【讨论】:

      【解决方案4】:

      已经提到了这三种方法:

      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() 是另一种方法。

      因为它是一种方法,所以可以在上面第二种和第三种方法不适用的情况下使用。特别是,当您将某些方法应用于数据框中的列并且您希望将输出转换为数据框而不是系列时,它非常有用。例如,在 Jupyter Notebook 中,系列不会有漂亮的输出,但数据框会有。

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

      【讨论】:

        【解决方案5】:

        (谈熊猫 1.3.4)

        我想为涉及.to_frame() 的答案添加更多上下文。如果您选择数据框的单行并对其执行.to_frame(),则索引将由原始列名组成,您将获得数字列名。您只需在末尾添加 .T 即可将其转回原始数据框的格式(见下文)。

        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}]
        
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2019-06-02
          • 1970-01-01
          • 2016-12-28
          • 2018-11-06
          • 2013-03-17
          • 2023-01-23
          • 1970-01-01
          相关资源
          最近更新 更多