Select rows from a DataFrame based on values in a column in pandas
如何根据熊猫图中某些列的值从数据框中选择行?在SQL中,我将使用:
1 | select * from table where colume_name = some_value. |
我试图查看熊猫的文档,但没有立即找到答案。
要选择列值等于标量
1 | df.loc[df['column_name'] == some_value] |
要选择列值在可ITerable(
1 | df.loc[df['column_name'].isin(some_values)] |
将多种条件与
1 | df.loc[(df['column_name'] >= A) & (df['column_name'] <= B)] |
注意括号。由于python的操作符优先规则,
1 | df['column_name'] >= A & df['column_name'] <= B |
被解析为
1 | df['column_name'] >= (A & df['column_name']) <= B |
导致序列真值的是模糊误差。
要选择列值不等于
1 | df.loc[df['column_name'] != some_value] |
1 | df.loc[~df['column_name'].isin(some_values)] |
例如,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | import pandas as pd import numpy as np df = pd.DataFrame({'A': 'foo bar foo bar foo bar foo foo'.split(), 'B': 'one one two three two two one three'.split(), 'C': np.arange(8), 'D': np.arange(8) * 2}) print(df) # A B C D # 0 foo one 0 0 # 1 bar one 1 2 # 2 foo two 2 4 # 3 bar three 3 6 # 4 foo two 4 8 # 5 bar two 5 10 # 6 foo one 6 12 # 7 foo three 7 14 print(df.loc[df['A'] == 'foo']) |
产量
1 2 3 4 5 6 | A B C D 0 foo one 0 0 2 foo two 2 4 4 foo two 4 8 6 foo one 6 12 7 foo three 7 14 |
如果要包含多个值,请将它们放入列出(或更一般地说,任何一个都可以)并使用
1 | print(df.loc[df['B'].isin(['one','three'])]) |
产量
1 2 3 4 5 6 | A B C D 0 foo one 0 0 1 bar one 1 2 3 bar three 3 6 6 foo one 6 12 7 foo three 7 14 |
但是,请注意,如果您希望多次这样做,那么先做一个索引,然后用
1 2 | df = df.set_index(['B']) print(df.loc['one']) |
产量
1 2 3 4 5 | A C D B one foo 0 0 one bar 1 2 one foo 6 12 |
或者,要包含索引中的多个值,请使用
1 | df.loc[df.index.isin(['one','two'])] |
产量
1 2 3 4 5 6 7 8 | A C D B one foo 0 0 one bar 1 2 two foo 2 4 two foo 4 8 two bar 5 10 one foo 6 12 |
DR
大熊猫相当于
1 | select * from table where column_name = some_value |
是
1 | table[table.column_name == some_value] |
多种条件:
1 | table[(table.column_name == some_value) | (table.column_name2 == some_value2)] |
或
1 | table.query('column_name == some_value | column_name2 == some_value2') |
代码示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | import pandas as pd # Create data set d = {'foo':[100, 111, 222], 'bar':[333, 444, 555]} df = pd.DataFrame(d) # Full dataframe: df # Shows: # bar foo # 0 333 100 # 1 444 111 # 2 555 222 # Output only the row(s) in df where foo is 222: df[df.foo == 222] # Shows: # bar foo # 2 555 222 |
在上面的代码中,根据列值给出行的是行
还可能出现多种情况:
1 2 3 4 | df[(df.foo == 222) | (df.bar == 444)] # bar foo # 1 444 111 # 2 555 222 |
但是在那一点上,我建议使用查询函数,因为它不那么冗长,并且产生相同的结果:
1 | df.query('foo == 222 | bar == 444') |
从熊猫数据帧中选择行有几种基本方法。好的。
对于每种基本类型,我们可以通过限制自己使用pandas API来保持简单,或者我们可以在API之外冒险,通常是进入
我将向您展示每种方法的示例,并指导您何时使用某些技术。好的。
安装程序首先,我们需要确定一个条件,作为选择行的标准。手术室提供
向@unutbu借款:好的。
1 2 3 4 5 | import pandas as pd, numpy as np df = pd.DataFrame({'A': 'foo bar foo bar foo bar foo foo'.split(), 'B': 'one one two three two two one three'.split(), 'C': np.arange(8), 'D': np.arange(8) * 2}) |
假设我们的标准是EDOCX1列(2)=EDOCX1列(3)好的。
1。布尔索引要求找到每行的
1 | mask = df['A'] == 'foo' |
然后我们可以使用这个掩码对数据帧进行切片或索引。好的。
1 2 3 4 5 6 7 8 | df[mask] A B C D 0 foo one 0 0 2 foo two 2 4 4 foo two 4 8 6 foo one 6 12 7 foo three 7 14 |
这是完成这项任务最简单的方法之一,如果性能或直觉不是问题,这应该是您选择的方法。但是,如果性能是一个问题,那么您可能需要考虑创建
2。位置索引有其用例,但这不是其中之一。为了确定切片的位置,我们首先需要执行与上面所做的相同的布尔分析。这就需要我们执行一个额外的步骤来完成相同的任务。好的。
1 2 3 4 5 6 7 8 9 10 | mask = df['A'] == 'foo' pos = np.flatnonzero(mask) df.iloc[pos] A B C D 0 foo one 0 0 2 foo two 2 4 4 foo two 4 8 6 foo one 6 12 7 foo three 7 14 |
三。标签索引可以非常方便,但在这种情况下,我们再次做了更多的工作,没有任何好处。好的。
1 2 3 4 5 6 7 8 | df.set_index('A', append=True, drop=False).xs('foo', level=1) A B C D 0 foo one 0 0 2 foo two 2 4 4 foo two 4 8 6 foo one 6 12 7 foo three 7 14 |
4。
1 2 3 4 5 6 7 8 | df.query('A =="foo"') A B C D 0 foo one 0 0 2 foo two 2 4 4 foo two 4 8 6 foo one 6 12 7 foo three 7 14 |
我倾向于使用
实际的改进可以通过修改我们创建
方案1使用底层的
1 | mask = df['A'].values == 'foo' |
我将在最后展示更多完整的时间测试,但只需看看我们使用示例数据框架获得的性能提升。首先,我们看看创建
1 2 3 4 5 | %timeit mask = df['A'].values == 'foo' %timeit mask = df['A'] == 'foo' 5.84 μs ± 195 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each) 166 μs ± 4.45 μs per loop (mean ± std. dev. of 7 runs, 10000 loops each) |
使用
接下来,我们来看看用一个
1 2 3 4 5 6 7 | mask = df['A'].values == 'foo' %timeit df[mask] mask = df['A'] == 'foo' %timeit df[mask] 219 μs ± 12.3 μs per loop (mean ± std. dev. of 7 runs, 1000 loops each) 239 μs ± 7.03 μs per loop (mean ± std. dev. of 7 runs, 1000 loops each) |
业绩的增长并没有那么明显。我们将看看这是否能支持更健壮的测试。好的。
我们要做的不是
1 | pd.DataFrame(df.values[mask], df.index[mask], df.columns).astype(df.dtypes) |
如果数据帧是混合类型,我们的例子是,那么当我们得到
1 2 3 4 5 | %timeit df[m] %timeit pd.DataFrame(df.values[mask], df.index[mask], df.columns).astype(df.dtypes) 216 μs ± 10.4 μs per loop (mean ± std. dev. of 7 runs, 1000 loops each) 1.43 ms ± 39.6 μs per loop (mean ± std. dev. of 7 runs, 1000 loops each) |
但是,如果数据帧不是混合类型,这是一种非常有用的方法。好的。
鉴于好的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | np.random.seed([3,1415]) d1 = pd.DataFrame(np.random.randint(10, size=(10, 5)), columns=list('ABCDE')) d1 A B C D E 0 0 2 7 3 8 1 7 0 6 8 6 2 0 2 0 4 9 3 7 3 2 4 3 4 3 6 7 7 4 5 5 3 7 5 9 6 8 7 6 4 7 7 6 2 6 6 5 8 2 8 7 5 8 9 4 7 6 1 5 |
1 2 3 4 5 | %%timeit mask = d1['A'].values == 7 d1[mask] 179 μs ± 8.73 μs per loop (mean ± std. dev. of 7 runs, 10000 loops each) |
对战好的。
1 2 3 4 5 | %%timeit mask = d1['A'].values == 7 pd.DataFrame(d1.values[mask], d1.index[mask], d1.columns) 87 μs ± 5.12 μs per loop (mean ± std. dev. of 7 runs, 10000 loops each) |
我们把时间缩短了一半。好的。
1 2 3 4 5 6 7 8 9 | mask = df['A'].isin(['foo']) df[mask] A B C D 0 foo one 0 0 2 foo two 2 4 4 foo two 4 8 6 foo one 6 12 7 foo three 7 14 |
然而,和以前一样,我们可以利用
1 2 3 4 5 6 7 8 9 | mask = np.in1d(df['A'].values, ['foo']) df[mask] A B C D 0 foo one 0 0 2 foo two 2 4 4 foo two 4 8 6 foo one 6 12 7 foo three 7 14 |
计时我将在其他文章中提到其他概念,供参考。下面的代码好的。
此表中的每一列表示一个不同长度的数据帧,在该数据帧上我们测试每个函数。每列显示所用的相对时间,其中最快的函数给定的基本索引为
1 2 3 4 5 6 7 8 9 10 11 | res.div(res.min()) 10 30 100 300 1000 3000 10000 30000 mask_standard 2.156872 1.850663 2.034149 2.166312 2.164541 3.090372 2.981326 3.131151 mask_standard_loc 1.879035 1.782366 1.988823 2.338112 2.361391 3.036131 2.998112 2.990103 mask_with_values 1.010166 1.000000 1.005113 1.026363 1.028698 1.293741 1.007824 1.016919 mask_with_values_loc 1.196843 1.300228 1.000000 1.000000 1.038989 1.219233 1.037020 1.000000 query 4.997304 4.765554 5.934096 4.500559 2.997924 2.397013 1.680447 1.398190 xs_label 4.124597 4.272363 5.596152 4.295331 4.676591 5.710680 6.032809 8.950255 mask_with_isin 1.674055 1.679935 1.847972 1.724183 1.345111 1.405231 1.253554 1.264760 mask_with_in1d 1.000000 1.083807 1.220493 1.101929 1.000000 1.000000 1.000000 1.144175 |
你会注意到最快的时间似乎是由
1 | res.T.plot(loglog=True) |
好的。
功能好的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | def mask_standard(df): mask = df['A'] == 'foo' return df[mask] def mask_standard_loc(df): mask = df['A'] == 'foo' return df.loc[mask] def mask_with_values(df): mask = df['A'].values == 'foo' return df[mask] def mask_with_values_loc(df): mask = df['A'].values == 'foo' return df.loc[mask] def query(df): return df.query('A =="foo"') def xs_label(df): return df.set_index('A', append=True, drop=False).xs('foo', level=-1) def mask_with_isin(df): mask = df['A'].isin(['foo']) return df[mask] def mask_with_in1d(df): mask = np.in1d(df['A'].values, ['foo']) return df[mask] |
测试好的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | res = pd.DataFrame( index=[ 'mask_standard', 'mask_standard_loc', 'mask_with_values', 'mask_with_values_loc', 'query', 'xs_label', 'mask_with_isin', 'mask_with_in1d' ], columns=[10, 30, 100, 300, 1000, 3000, 10000, 30000], dtype=float ) for j in res.columns: d = pd.concat([df] * j, ignore_index=True) for i in res.index:a stmt = '{}(d)'.format(i) setp = 'from __main__ import d, {}'.format(i) res.at[i, j] = timeit(stmt, setp, number=50) |
特殊时机当我们有一个单一的非对象
1 2 3 4 5 6 | spec.div(spec.min()) 10 30 100 300 1000 3000 10000 30000 mask_with_values 1.009030 1.000000 1.194276 1.000000 1.236892 1.095343 1.000000 1.000000 mask_with_in1d 1.104638 1.094524 1.156930 1.072094 1.000000 1.000000 1.040043 1.027100 reconstruct 1.000000 1.142838 1.000000 1.355440 1.650270 2.222181 2.294913 3.406735 |
事实证明,经过几百行重建是不值得的。好的。
1 | spec.T.plot(loglog=True) |
好的。
功能好的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | np.random.seed([3,1415]) d1 = pd.DataFrame(np.random.randint(10, size=(10, 5)), columns=list('ABCDE')) def mask_with_values(df): mask = df['A'].values == 'foo' return df[mask] def mask_with_in1d(df): mask = np.in1d(df['A'].values, ['foo']) return df[mask] def reconstruct(df): v = df.values mask = np.in1d(df['A'].values, ['foo']) return pd.DataFrame(v[mask], df.index[mask], df.columns) spec = pd.DataFrame( index=['mask_with_values', 'mask_with_in1d', 'reconstruct'], columns=[10, 30, 100, 300, 1000, 3000, 10000, 30000], dtype=float ) |
测试好的。
1 2 3 4 5 6 | for j in spec.columns: d = pd.concat([df] * j, ignore_index=True) for i in spec.index: stmt = '{}(d)'.format(i) setp = 'from __main__ import d, {}'.format(i) spec.at[i, j] = timeit(stmt, setp, number=50) |
好啊。
我发现前面答案的语法是多余的,很难记住。熊猫在v0.13中介绍了
转载自http://pandas.pydata.org/pandas docs/version/0.17.0/indexing.html indexing query
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | In [167]: n = 10 In [168]: df = pd.DataFrame(np.random.rand(n, 3), columns=list('abc')) In [169]: df Out[169]: a b c 0 0.687704 0.582314 0.281645 1 0.250846 0.610021 0.420121 2 0.624328 0.401816 0.932146 3 0.011763 0.022921 0.244186 4 0.590198 0.325680 0.890392 5 0.598892 0.296424 0.007312 6 0.634625 0.803069 0.123872 7 0.924168 0.325076 0.303746 8 0.116822 0.364564 0.454607 9 0.986142 0.751953 0.561512 # pure python In [170]: df[(df.a < df.b) & (df.b < df.c)] Out[170]: a b c 3 0.011763 0.022921 0.244186 8 0.116822 0.364564 0.454607 # query In [171]: df.query('(a < b) & (b < c)') Out[171]: a b c 3 0.011763 0.022921 0.244186 8 0.116822 0.364564 0.454607 |
您还可以通过预先准备
1 2 | exclude = ('red', 'orange') df.query('color not in @exclude') |
使用numpy.where可以获得更快的结果。
例如,使用unubtu的设置-
1 2 3 4 5 6 7 8 | In [76]: df.iloc[np.where(df.A.values=='foo')] Out[76]: A B C D 0 foo one 0 0 2 foo two 2 4 4 foo two 4 8 6 foo one 6 12 7 foo three 7 14 |
时间比较:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | In [68]: %timeit df.iloc[np.where(df.A.values=='foo')] # fastest 1000 loops, best of 3: 380 μs per loop In [69]: %timeit df.loc[df['A'] == 'foo'] 1000 loops, best of 3: 745 μs per loop In [71]: %timeit df.loc[df['A'].isin(['foo'])] 1000 loops, best of 3: 562 μs per loop In [72]: %timeit df[df.A=='foo'] 1000 loops, best of 3: 796 μs per loop In [74]: %timeit df.query('(A=="foo")') # slowest 1000 loops, best of 3: 1.71 ms per loop |
下面是一个简单的例子
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | from pandas import DataFrame # Create data set d = {'Revenue':[100,111,222], 'Cost':[333,444,555]} df = DataFrame(d) # mask = Return True when the value in column"Revenue" is equal to 111 mask = df['Revenue'] == 111 print mask # Result: # 0 False # 1 True # 2 False # Name: Revenue, dtype: bool # Select * FROM df WHERE Revenue = 111 df[mask] # Result: # Cost Revenue # 1 444 111 |
我刚刚尝试编辑这个,但我没有登录,所以我不确定我的编辑去了哪里。我试图合并多种选择。所以我认为一个更好的答案是:
对于单个值,最直接的(人类可读的)可能是:
1 | df.loc[df['column_name'] == some_value] |
对于值列表,还可以使用:
1 | df.loc[df['column_name'].isin(some_values)] |
例如,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | import pandas as pd import numpy as np df = pd.DataFrame({'A': 'foo bar foo bar foo bar foo foo'.split(), 'B': 'one one two three two two one three'.split(), 'C': np.arange(8), 'D': np.arange(8) * 2}) print(df) # A B C D # 0 foo one 0 0 # 1 bar one 1 2 # 2 foo two 2 4 # 3 bar three 3 6 # 4 foo two 4 8 # 5 bar two 5 10 # 6 foo one 6 12 # 7 foo three 7 14 print(df.loc[df['A'] == 'foo']) |
产量
1 2 3 4 5 6 | A B C D 0 foo one 0 0 2 foo two 2 4 4 foo two 4 8 6 foo one 6 12 7 foo three 7 14 |
如果要针对多个条件进行选择,可以将它们放入列表中并使用"isin":
1 | print(df.loc[df['B'].isin(['one','three'])]) |
产量
1 2 3 4 5 6 | A B C D 0 foo one 0 0 1 bar one 1 2 3 bar three 3 6 6 foo one 6 12 7 foo three 7 14 |
但是,请注意,如果您希望多次这样做,那么首先创建索引,然后使用df.loc会更有效:
1 2 | df = df.set_index(['A']) print(df.loc['foo']) |
产量
1 2 3 4 5 6 | A B C D foo one 0 0 foo two 2 4 foo two 4 8 foo one 6 12 foo three 7 14 |
如果根据列中的某个整数查找行,则
1 | df.loc[df['column_name'] == 2017] |
如果要根据字符串查找值
1 | df.loc[df['column_name'] == 'string'] |
如果基于两者
1 | df.loc[(df['column_name'] == 'string') & (df['column_name'] == 2017)] |
对于在大熊猫中为给定值选择多个列中的特定列:
1 | select col_name1, col_name2 from table where column_name = some_value. |
选项:
1 | df.loc[df['column_name'] == some_value][[col_name1, col_name2]] |
或
1 | df.query['column_name' == 'some_value'][[col_name1, col_name2]] |
附加到这个著名的问题上(尽管有点晚):您也可以执行
1 2 3 4 5 6 7 8 9 10 | import pandas as pd df = pd.DataFrame({'A': 'foo bar foo bar foo bar foo foo'.split(), 'B': 'one one two three two two one three'.split()}) print("Original dataframe:") print(df) b_is_two_dataframe = pd.DataFrame(df.groupby('B').get_group('two').reset_index()).drop('index', axis = 1) #NOTE: the final drop is to remove the extra index column returned by groupby object print('Sub dataframe where B is two:') print(b_is_two_dataframe) |
运行如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | Original dataframe: A B 0 foo one 1 bar one 2 foo two 3 bar three 4 foo two 5 bar two 6 foo one 7 foo three Sub dataframe where B is two: A B 0 foo two 1 foo two 2 bar two |
1 2 3 4 5 6 7 8 9 10 11 12 | df = pd.DataFrame({'A': 'foo bar foo bar foo bar foo foo'.split(), 'B': 'one one two three two two one three'.split(), 'C': np.arange(8), 'D': np.arange(8) * 2}) df[df['A']=='foo'] OUTPUT: A B C D 0 foo one 0 0 2 foo two 2 4 4 foo two 4 8 6 foo one 6 12 7 foo three 7 14 |
如果您来这里是想通过包含列值不是任何值列表的值来选择数据框中的行,下面介绍如何绕过unutbu对上述值列表的回答:
1 | df.loc[~df['column_name'].isin(some_values)] |
(当然,为了不包含单个值,您只需使用正则不等于运算符
例子:
1 2 3 4 | import pandas as pd df = pd.DataFrame({'A': 'foo bar foo bar foo bar foo foo'.split(), 'B': 'one one two three two two one three'.split()}) print(df) |
给我们
1 2 3 4 5 6 7 8 9 | A B 0 foo one 1 bar one 2 foo two 3 bar three 4 foo two 5 bar two 6 foo one 7 foo three |
仅将列
1 | df.loc[~df['B'].isin(['one', 'three'])] |
产量
1 2 3 4 | A B 2 foo two 4 foo two 5 bar two |
1 | df.loc[df['column_name'] == some_value] |
您也可以使用。应用:
1 | df.apply(lambda row: row[df['B'].isin(['one','three'])]) |
它实际上是按行运行的(即,将函数应用于每一行)。
输出是
1 2 3 4 5 6 | A B C D 0 foo one 0 0 1 bar one 1 2 3 bar three 3 6 6 foo one 6 12 7 foo three 7 14 |
结果与@unutbu提到的相同
1 | df[[df['B'].isin(['one','three'])]] |