【发布时间】:2016-11-01 17:23:27
【问题描述】:
我有一个值列表(事先不知道,在 Python 列表中),我的 Panda DataFrame 中的列不能对所有行都有。
网络上的所有食谱(如this one)都展示了如何只排除一个值,但我有多个值要排除。我该怎么做?
请注意,我无法硬编码要在我的代码中排除的值。
谢谢!
【问题讨论】:
标签: python pandas filter dataframe
我有一个值列表(事先不知道,在 Python 列表中),我的 Panda DataFrame 中的列不能对所有行都有。
网络上的所有食谱(如this one)都展示了如何只排除一个值,但我有多个值要排除。我该怎么做?
请注意,我无法硬编码要在我的代码中排除的值。
谢谢!
【问题讨论】:
标签: python pandas filter dataframe
你可以做否定的isin()索引:
In [57]: df
Out[57]:
a b c
0 1 2 2
1 1 7 0
2 3 7 1
3 3 2 7
4 1 3 1
5 3 4 2
6 0 7 1
7 5 4 3
8 6 1 0
9 3 2 0
In [58]: my_list = [1, 7, 8]
In [59]: df.loc[~df.b.isin(my_list)]
Out[59]:
a b c
0 1 2 2
3 3 2 7
4 1 3 1
5 3 4 2
7 5 4 3
9 3 2 0
或使用query()函数:
In [60]: df.query('@my_list not in b')
Out[60]:
a b c
0 1 2 2
3 3 2 7
4 1 3 1
5 3 4 2
7 5 4 3
9 3 2 0
【讨论】:
您也可以使用np.in1d。来自https://stackoverflow.com/a/38083418/2336654
对于您的用例:
df[~np.in1d(df.b, my_list)]
from string import ascii_letters, ascii_lowercase, ascii_uppercase
df = pd.DataFrame({'lower': list(ascii_lowercase), 'upper': list(ascii_uppercase)}).head(6)
exclude = list(ascii_uppercase[:6:2])
print df
lower upper
0 a A
1 b B
2 c C
3 d D
4 e E
5 f F
print exclude
['A', 'C', 'E']
print df[~np.in1d(df.upper, exclude)]
lower upper
1 b B
3 d D
5 f F
各种方法
显然,isin 和 query 在这种情况下可以更好地扩展。
【讨论】:
np.in1d under the hood。看起来他们优化了它使用np.in1d,只有当它通常是有益的时,这是在大型数据集上。它在您的小型示例数据集上稍快一些,但是当我在具有 6k 行且不包括 6 个字母的类似数据上尝试它时,isin 的速度几乎快了一倍。
ix 稍微减慢了速度。我将重新运行大型数据集并排除 ix。
np.in1d,因为它通常在其他情况下也很有用。
np.in1d() 对于字符串非常很慢,但对于所有数字搜索它都会胜出...
我决定添加另一个答案,其中包含不同方法和不同数据类型的时间 - 一个答案太长了......
针对以下 dtype 的 1M 行 DF 的计时:int32、int64、float64、对象(字符串):
In [207]: result
Out[207]:
int32 int64 float string
method
df[~np.in1d(df.col, excl)] 249 271 307 2420
df[~df.col.isin(excl)] 414 210 514 189
df.ix[~df.col.isin(excl)] 399 212 553 189
df.query('@excl not in col') 415 228 563 206
In [208]: result.T
Out[208]:
method df[~np.in1d(df.col, excl)] df[~df.col.isin(excl)] df.ix[~df.col.isin(excl)] df.query('@excl not in col')
int32 249 414 399 415
int64 271 210 212 228
float 307 514 553 563
string 2420 189 189 206
原始结果:
int32:
In [159]: %timeit df[~np.in1d(df.int32, exclude_int32)]
1 loop, best of 3: 249 ms per loop
In [160]: %timeit df[~df.int32.isin(exclude_int32)]
1 loop, best of 3: 414 ms per loop
In [161]: %timeit df.ix[~df.int32.isin(exclude_int32)]
1 loop, best of 3: 399 ms per loop
In [162]: %timeit df.query('@exclude_int32 not in int32')
1 loop, best of 3: 415 ms per loop
int64:
In [163]: %timeit df[~np.in1d(df.int64, exclude_int64)]
1 loop, best of 3: 271 ms per loop
In [164]: %timeit df[~df.int64.isin(exclude_int64)]
1 loop, best of 3: 210 ms per loop
In [165]: %timeit df.ix[~df.int64.isin(exclude_int64)]
1 loop, best of 3: 212 ms per loop
In [166]: %timeit df.query('@exclude_int64 not in int64')
1 loop, best of 3: 228 ms per loop
float64:
In [167]: %timeit df[~np.in1d(df.float, exclude_float)]
1 loop, best of 3: 307 ms per loop
In [168]: %timeit df[~df.float.isin(exclude_float)]
1 loop, best of 3: 514 ms per loop
In [169]: %timeit df.ix[~df.float.isin(exclude_float)]
1 loop, best of 3: 553 ms per loop
In [170]: %timeit df.query('@exclude_float not in float')
1 loop, best of 3: 563 ms per loop
对象/字符串:
In [171]: %timeit df[~np.in1d(df.string, exclude_str)]
1 loop, best of 3: 2.42 s per loop
In [172]: %timeit df[~df.string.isin(exclude_str)]
10 loops, best of 3: 189 ms per loop
In [173]: %timeit df.ix[~df.string.isin(exclude_str)]
10 loops, best of 3: 189 ms per loop
In [174]: %timeit df.query('@exclude_str not in string')
1 loop, best of 3: 206 ms per loop
结论:
np.in1d() - 赢得(int32 和 float64)搜索,但它是 大约。搜索字符串时(与其他人相比)慢 10 倍,因此不要将其用于 object(字符串)和 int64 dtypes!
设置:
df = pd.DataFrame({
'int32': np.random.randint(0, 10**6, 10),
'int64': np.random.randint(10**7, 10**9, 10).astype(np.int64)*10,
'float': np.random.rand(10),
'string': np.random.choice([c*10 for c in string.ascii_uppercase], 10),
})
df = pd.concat([df] * 10**5, ignore_index=True)
exclude_str = np.random.choice([c*10 for c in string.ascii_uppercase], 100).tolist()
exclude_int32 = np.random.randint(0, 10**6, 100).tolist()
exclude_int64 = (np.random.randint(10**7, 10**9, 100).astype(np.int64)*10).tolist()
exclude_float = np.random.rand(100)
In [146]: df.shape
Out[146]: (1000000, 4)
In [147]: df.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 1000000 entries, 0 to 999999
Data columns (total 4 columns):
float 1000000 non-null float64
int32 1000000 non-null int32
int64 1000000 non-null int64
string 1000000 non-null object
dtypes: float64(1), int32(1), int64(1), object(1)
memory usage: 26.7+ MB
In [148]: df.head()
Out[148]:
float int32 int64 string
0 0.221662 283447 6849265910 NNNNNNNNNN
1 0.276834 455464 8785039710 AAAAAAAAAA
2 0.517846 618887 8653293710 YYYYYYYYYY
3 0.318897 363191 2223601320 PPPPPPPPPP
4 0.323926 777875 5357201380 QQQQQQQQQQ
【讨论】: