在pandas数据框中选择多个列


1108

我在不同的列中有数据,但是我不知道如何提取数据以将其保存在另一个变量中。

index  a   b   c
1      2   3   4
2      3   4   5

如何选择'a''b'并将其保存到df1?

我试过了

df1 = df['a':'b']
df1 = df.ix[:, 'a':'b']

似乎没有任何工作。


2
您永远都不想使用.ix它,因为它含糊不清。如果需要,请使用.iloc.loc
Acumenus

1
有没有一种方法可以不用参考标题名称来完成?像在R中一样,我可以这样做:> csvtable_imp_1 <- csvtable_imp[0:6]它选择0到6之间的第一列的增量量。我要做的就是读取用readr lib分隔的csv表。
MichaelR '18 -10-19

我已经做了更多的工作。找到了需要的东西。默认是选择char的数目而不是列的数目。infile_1 = largefile_stay.ix[:,0:6]
MichaelR

3
对于那些在此后期绊脚石的人,ix现已不建议使用。熊猫建议使用:(loc基于标签的索引)或iloc(基于位置的索引)。
ZaydH

Answers:


1766

列名(字符串)无法按照您尝试的方式进行切片。

在这里,您有两个选择。如果您从上下文中知道要切出哪些变量,则可以通过将列表传递给__getitem__语法([])来仅返回那些列的视图。

df1 = df[['a','b']]

或者,如果需要对它们进行数字索引而不是按其名称进行索引(例如,您的代码应在不知道前两列名称的情况下自动执行此操作),则可以执行以下操作:

df1 = df.iloc[:,0:2] # Remember that Python does not slice inclusive of the ending index.

此外,您应该熟悉Pandas对象与该对象副本的视图概念。上述方法中的第一个将在内存中返回所需子对象(所需切片)的新副本。

但是,有时熊猫中有一些索引约定不执行此操作,而是给您一个新变量,该变量仅引用与原始对象中的子对象或切片相同的内存块。第二种索引编制方式会发生这种情况,因此您可以使用copy()函数对其进行修改以获取常规副本。发生这种情况时,更改您认为是切片对象的内容有时会更改原始对象。始终对此保持警惕。

df1 = df.iloc[0,0:2].copy() # To avoid the case where changing df1 also changes df

要使用iloc,您需要知道列位置(或索引)。由于列位置可能会改变,而不是硬编码索引,则可以使用ilocget_loc功能的columns数据框对象的方法来获得列索引。

{df.columns.get_loc(c):c for idx, c in enumerate(df.columns)}

现在,您可以使用此字典通过名称和使用来访问列iloc


192
注意:df[['a','b']]出示副本
Wes McKinney 2012年

1
是的,这在我的答案中是隐含的。ix[]如果您出于任何原因更喜欢使用副本,则仅用于复制ix[]
2012年

1
ix索引行,而不是列。我以为OP想要专栏。
滚刀

9
ix接受切片参数,因此您也可以获取列。例如,df.ix[0:2, 0:2]获取左上2x2子数组,就像处理NumPy矩阵一样(当然取决于您的列名)。您甚至可以在列的字符串名称上使用slice语法,例如df.ix[0, 'Col1':'Col5']。这将获取所有恰好在数组之间Col1和数组中排序的列。说索引行是不正确的。那只是它最基本的用途。它还支持更多的索引。因此,对于这个问题完全是笼统的。Col5df.columnsixix
2012年

7
@AndrewCassidy不再使用.ix。如果您想用整数切片,请使用.iloc它来排除最后一个位置,就像Python列表一样。
Ted Petrou

133

从0.11.0版本开始,可以按照您尝试使用.loc索引器的方式对列进行切片:

df.loc[:, 'C':'E']

等价于

df[['C', 'D', 'E']]  # or df.loc[:, ['C', 'D', 'E']]

C通过返回列E


随机生成的DataFrame的演示:

import pandas as pd
import numpy as np
np.random.seed(5)
df = pd.DataFrame(np.random.randint(100, size=(100, 6)), 
                  columns=list('ABCDEF'), 
                  index=['R{}'.format(i) for i in range(100)])
df.head()

Out: 
     A   B   C   D   E   F
R0  99  78  61  16  73   8
R1  62  27  30  80   7  76
R2  15  53  80  27  44  77
R3  75  65  47  30  84  86
R4  18   9  41  62   1  82

要从C到E获得列(请注意,与整数切片不同,列中包含'E'):

df.loc[:, 'C':'E']

Out: 
      C   D   E
R0   61  16  73
R1   30  80   7
R2   80  27  44
R3   47  30  84
R4   41  62   1
R5    5  58   0
...

同样适用于基于标签选择行。从这些列中获取行“ R6”至“ R10”:

df.loc['R6':'R10', 'C':'E']

Out: 
      C   D   E
R6   51  27  31
R7   83  19  18
R8   11  67  65
R9   78  27  29
R10   7  16  94

.loc还接受一个布尔数组,因此您可以选择在数组中对应条目为的列True。例如,如果列名称在列表中,则df.columns.isin(list('BCD'))返回array([False, True, True, True, False, False], dtype=bool)-True ['B', 'C', 'D'];错误,否则。

df.loc[:, df.columns.isin(list('BCD'))]

Out: 
      B   C   D
R0   78  61  16
R1   27  30  80
R2   53  80  27
R3   65  47  30
R4    9  41  62
R5   78   5  58
...

110

假设列名(df.columns)为['index','a','b','c'],则所需数据在第3列和第4列中。如果在脚本运行时不知道它们的名称,则可以执行此操作

newdf = df[df.columns[2:4]] # Remember, Python is 0-offset! The "3rd" entry is at slot 2.

正如EMS在他的回答中指出的那样,df.ix切片列更加简洁,但是.columns切片界面可能更自然,因为它使用了香草1-D python列表索引/切片语法。

警告:这'index'DataFrame列的坏名称。该标签也用于真实df.index属性Index数组。因此,您的列由返回,df['index']而真正的DataFrame索引由返回df.index。An Index是一种特殊的Series优化方法,用于查找其元素的值。对于df.index,它用于按标签查找行。该df.columns属性也是一个pd.Index数组,用于按标签查找列。


3
正如我在注释中提到上述,.ix不是只为行。它用于通用切片,可用于多维切片。它基本上只是NumPy常用__getitem__语法的接口。就是说,您只需应用转置操作就可以轻松地将列切片问题转换为行切片问题df.T。您的示例使用columns[1:3],这有点误导。结果columnsSeries; 注意不要仅仅将其视为数组。另外,您可能应该更改它以使其columns[2:3]与您的“第三和第四”注释匹配。
2012年

@ Mr.F:我[2:4]是对的。你[2:3]错了 并且使用标准的python切片符号来生成序列/系列不会误导IMO。但我喜欢绕过DataFrame接口,以使用访问底层numpy数组ix
滚刀

在这种情况下,您是正确的,但是我要说明的是,一般而言,在Pandas中使用标签切片包括切片端点(或者至少在大多数以前的Pandas版本中都是这种行为)。因此,如果您要检索df.columns并希望按标签对其进行切片,则与按整数索引位置对其进行切片相比,您将具有不同的切片语义。我绝对不会在我之前的评论中很好地解释它。
ely 2016年

嗯,现在我明白了。我忘记了这columns是一个不可变的Series,并且getter已被重写为使用标签作为索引。感谢您抽出宝贵的时间来澄清。
滚刀

2
请注意不推荐使用的警告:.ix不推荐使用。因此,这是有道理的:newdf = df [df.columns [2:4]]
Martien Lubberink

64
In [39]: df
Out[39]: 
   index  a  b  c
0      1  2  3  4
1      2  3  4  5

In [40]: df1 = df[['b', 'c']]

In [41]: df1
Out[41]: 
   b  c
0  3  4
1  4  5

1
如果我想要重命名列,例如是这样的:df[['b as foo', 'c as bar']使得输出列重命名bfoo和列cbar
kuanb

5
df[['b', 'c']].rename(columns = {'b' : 'foo', 'c' : 'bar'})
格雷格

61

我知道这个问题已经很老了,但是在最新版本的熊猫中,有一种简单的方法可以做到这一点。列名(即字符串)可以按您喜欢的任何方式进行切片。

columns = ['b', 'c']
df1 = pd.DataFrame(df, columns=columns)

6
这只能在创建时完成。问题是询问您是否已将其包含在数据框中。
Banjocat

2
@Banjocat,它可与现有数据

23

您可以提供要删除的列的列表,然后仅使用drop()Pandas DataFrame上的函数返回带有所需列的DataFrame。

只是说

colsToDrop = ['a']
df.drop(colsToDrop, axis=1)

将返回仅包含列b和的DataFrame c

drop方法在此处记录


23

有了熊猫

机智列名称

dataframe[['column1','column2']]

通过iloc和具有索引号的特定列进行选择:

dataframe.iloc[:,[1,2]]

与loc列名称可以像

dataframe.loc[:,['column1','column2']]

20

我发现此方法非常有用:

# iloc[row slicing, column slicing]
surveys_df.iloc [0:3, 1:4]

可以在这里找到更多详细信息


例如,您如何只接受第2列和第5列?
324

1
那将是surveys_df.iloc [:, [2,5]]那时。
朱利安·戈弗

15

从0.21.0开始,不推荐使用.loc[]使用带有一个或多个缺少标签的列表,而推荐使用.reindex。因此,您的问题的答案是:

df1 = df.reindex(columns=['b','c'])

在以前的版本中,.loc[list-of-labels]只要找到至少一个键就可以使用using (否则将引发KeyError)。此行为已弃用,现在显示警告消息。推荐的替代方法是使用.reindex()

索引和选择数据中了解更多信息


10

您可以使用熊猫。我创建了DataFrame:

    import pandas as pd
    df = pd.DataFrame([[1, 2,5], [5,4, 5], [7,7, 8], [7,6,9]], 
                      index=['Jane', 'Peter','Alex','Ann'],
                      columns=['Test_1', 'Test_2', 'Test_3'])

数据框:

           Test_1  Test_2  Test_3
    Jane        1       2       5
    Peter       5       4       5
    Alex        7       7       8
    Ann         7       6       9

要按名称选择1列或更多列:

    df[['Test_1','Test_3']]

           Test_1  Test_3
    Jane        1       5
    Peter       5       5
    Alex        7       8
    Ann         7       9

您还可以使用:

    df.Test_2

和哟列 Test_2

    Jane     2
    Peter    4
    Alex     7
    Ann      6

您也可以使用从这些行中选择列和行.loc()。这称为“切片”。请注意,我从列Test_1Test_3

    df.loc[:,'Test_1':'Test_3']

“切片”为:

            Test_1  Test_2  Test_3
     Jane        1       2       5
     Peter       5       4       5
     Alex        7       7       8
     Ann         7       6       9

如果你只是想PeterAnn来自列Test_1Test_3

    df.loc[['Peter', 'Ann'],['Test_1','Test_3']]

你得到:

           Test_1  Test_3
    Peter       5       5
    Ann         7       9

8

如果要按行索引和列名获取一个元素,则可以像那样进行df['b'][0]。它像成像一样简单。

或者,您也可以df.ix[0,'b']混合使用索引和标签。

注意:由于ix不推荐使用v0.20 ,而推荐使用loc/ iloc


6

一种不同而又简单的方法:迭代行

使用iterows

 df1= pd.DataFrame() #creating an empty dataframe
 for index,i in df.iterrows():
    df1.loc[index,'A']=df.loc[index,'A']
    df1.loc[index,'B']=df.loc[index,'B']
    df1.head()

5
请不要建议使用iterrows()。它是大熊猫历史上最恶劣的反模式的公然推动者。
cs95

您能否解释一下“最差的反模式”是什么意思?
Ankita

1
恕我直言,使用熊猫时iterrows()应该是最后的选择。
精灵,

5

以上响应中讨论的不同方法是基于以下假设:用户知道要放下或子集化的列索引,或者用户希望使用一定范围的列(例如,在“ C”与“ E”之间)对数据帧进行子集化。pandas.DataFrame.drop()当然是基于用户定义的列列表对数据进行子集化的选项(尽管您必须谨慎使用始终使用dataframe的副本,并且inplace参数不应设置为True!)

另一种选择是使用pandas.columns.difference(),它对列名进行设置上的区别,并返回包含所需列的数组的索引类型。以下是解决方案:

df = pd.DataFrame([[2,3,4],[3,4,5]],columns=['a','b','c'],index=[1,2])
columns_for_differencing = ['a']
df1 = df.copy()[df.columns.difference(columns_for_differencing)]
print(df1)

输出为: b c 1 3 4 2 4 5


1
copy()不是必需的。即:df1 = df[df.columns.difference(columns_for_differencing)]将返回一个新的/复制的数据帧。您将可以进行修改df1而无需更改df。谢谢,顺便说一句。这正是我所需要的。
Bazyli Debowski

4

您也可以使用df.pop()

>>> df = pd.DataFrame([('falcon', 'bird',    389.0),
...                    ('parrot', 'bird',     24.0),
...                    ('lion',   'mammal',   80.5),
...                    ('monkey', 'mammal', np.nan)],
...                   columns=('name', 'class', 'max_speed'))
>>> df
     name   class  max_speed
0  falcon    bird      389.0
1  parrot    bird       24.0
2    lion  mammal       80.5
3  monkey  mammal 

>>> df.pop('class')
0      bird
1      bird
2    mammal
3    mammal
Name: class, dtype: object

>>> df
     name  max_speed
0  falcon      389.0
1  parrot       24.0
2    lion       80.5
3  monkey        NaN

让我知道这是否对您有帮助,请使用df.pop(c)


3

我已经看到了一些答案,但是仍然不清楚。您将如何选择那些感兴趣的列?答案是,如果将它们收集在列表中,则可以使用列表引用列。

print(extracted_features.shape)
print(extracted_features)

(63,)
['f000004' 'f000005' 'f000006' 'f000014' 'f000039' 'f000040' 'f000043'
 'f000047' 'f000048' 'f000049' 'f000050' 'f000051' 'f000052' 'f000053'
 'f000054' 'f000055' 'f000056' 'f000057' 'f000058' 'f000059' 'f000060'
 'f000061' 'f000062' 'f000063' 'f000064' 'f000065' 'f000066' 'f000067'
 'f000068' 'f000069' 'f000070' 'f000071' 'f000072' 'f000073' 'f000074'
 'f000075' 'f000076' 'f000077' 'f000078' 'f000079' 'f000080' 'f000081'
 'f000082' 'f000083' 'f000084' 'f000085' 'f000086' 'f000087' 'f000088'
 'f000089' 'f000090' 'f000091' 'f000092' 'f000093' 'f000094' 'f000095'
 'f000096' 'f000097' 'f000098' 'f000099' 'f000100' 'f000101' 'f000103']

我有以下list / numpy数组extracted_features,指定63列。原始数据集有103列,我想准确提取出这些列,然后使用

dataset[extracted_features]

你最终会得到这个

在此处输入图片说明

您将在机器学习中(特别是在功能选择中)经常使用此功能。我也想讨论其他方式,但是我认为其他stackoverflowers已经对此进行了讨论。希望这对您有所帮助!



0
df[['a','b']] # select all rows of 'a' and 'b'column 
df.loc[0:10, ['a','b']] # index 0 to 10 select column 'a' and 'b'
df.loc[0:10, ['a':'b']] # index 0 to 10 select column 'a' to 'b'
df.iloc[0:10, 3:5] # index 0 to 10 and column 3 to 5
df.iloc[3, 3:5] # index 3 of column 3 to 5
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.