将选定的列保留为 DataFrame 而不是 Series

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

91031 次浏览

正如@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

根据 Andy Hayden的建议,利用。Iloc/.Loc 索引输出(单列)数据框架是一种方法; 另一个要注意的问题是如何表示索引位置。 使用 上市指数标签/头寸同时指定参数值作为 Dataframe 进行索引; 如果不这样做,将返回‘ panas.core.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'>

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

如你所见:

enter image description here

提到了这三种方法:

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

To _ frame ()是另一种方法。

因为它是一种方法,所以可以在上述第二种和第三种方法不适用的情况下使用它。特别是,当将某种方法应用于数据框架中的列并且希望将输出转换为数据框架而不是序列时,它非常有用。例如,在木星笔记本中,一个序列不会有漂亮的输出,但是一个数据框架会有。

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

(谈论熊猫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}]