Pandas:根据多个列值删除行

时间:2016-07-22 22:09:37

标签: python pandas

我有一个包含A,B,C列的数据框。我有一个像[(x1,y1), (x2,y2), ...]这样的元组列表。我想删除满足以下条件的所有行: (B=x1 && C=y1) | (B=x2 && C=y2) | ...我怎么能在熊猫中做到这一点?我想使用isin函数,但不确定是否可以,因为我的列表中有元组。我可以这样做:

for x,y in tuples:   
    df = df.drop(df[df.B==x && df.C==y].index)

也许有一种更简单的方法。

3 个答案:

答案 0 :(得分:6)

使用pandas索引

undefined

时序

df.set_index(list('BC')).drop(tuples, errors='ignore').reset_index()

10行,1个元组

def linear_indexing_based(df, tuples):
    idx = np.array(tuples)
    BC_arr = df[['B','C']].values
    shp = np.maximum(BC_arr.max(0)+1,idx.max(0)+1)
    BC_IDs = np.ravel_multi_index(BC_arr.T,shp)
    idx_IDs = np.ravel_multi_index(idx.T,shp)
    return df[~np.in1d(BC_IDs,idx_IDs)]

def divakar(df, tuples):
    idx = np.array(tuples)
    mask = (df.B.values == idx[:, None, 0]) & (df.C.values == idx[:, None, 1])
    return df[~mask.any(0)]

def pirsquared(df, tuples):
    return df.set_index(list('BC')).drop(tuples).reset_index()

enter image description here

10,000行,500个元组

np.random.seed([3,1415])
df = pd.DataFrame(np.random.choice(range(10), (10, 3)), columns=list('ABC'))
tuples = [tuple(row) for row in np.random.choice(range(10), (1, 2))]

enter image description here

答案 1 :(得分:4)

方法#1

这是使用NumPy's broadcasting -

的矢量化方法
def broadcasting_based(df, tuples):
    idx = np.array(tuples)
    mask = (df.B.values == idx[:, None, 0]) & (df.C.values == idx[:, None, 1])
    return df[~mask.any(0)]

示例运行 -

In [224]: df
Out[224]: 
   A  B  C
0  6  4  4
1  2  0  3
2  8  3  4
3  7  8  3
4  6  7  8
5  3  3  2
6  5  4  2
7  2  4  7
8  6  1  6
9  1  1  1

In [225]: tuples = [(3,4),(7,8),(1,6)]

In [226]: broadcasting_based(df,tuples)
Out[226]: 
   A  B  C
0  6  4  4
1  2  0  3
3  7  8  3
5  3  3  2
6  5  4  2
7  2  4  7
9  1  1  1

方法#2:涵盖通用数量的列

对于这样的情况,可以将来自不同列的信息折叠成一个表示所有列中唯一性的单个条目。这可以通过将每一行视为索引元组来实现。因此,基本上每行将成为一个条目。类似地,要匹配的元组列表中的每个条目可以简化为1D数组,每个元组变为一个标量。最后,我们使用np.in1d查找对应关系,获取有效掩码并删除所需的行数据帧,因此,实现将是 -

def linear_indexing_based(df, tuples):
    idx = np.array(tuples)
    BC_arr = df[['B','C']].values
    shp = np.maximum(BC_arr.max(0)+1,idx.max(0)+1)
    BC_IDs = np.ravel_multi_index(BC_arr.T,shp)
    idx_IDs = np.ravel_multi_index(idx.T,shp)
    return df[~np.in1d(BC_IDs,idx_IDs)]

答案 2 :(得分:0)

use boolean indexing可能比对DataFrame.drop的一堆调用更有效。这是因为Pandas不必在每次循环迭代中重新分配内存。

m = pd.Series(False, index=df.index)
for x,y in tuples:
    m |= (df.B == x) & (df.C == y)
df = df[~m]