更快的收集-计数器-类似熊猫系列的操作

时间:2019-04-12 22:55:50

标签: python pandas performance numpy

嗨,我目前正在执行以下操作,以在几个熊猫系列中找到所有唯一的物品:

vscode.uri("c:\\some\\path")

由于真实数据很大,有什么方法可以加快速度。

谢谢。

反馈意见

代码:

In [44]: data = [Series([1,2,7,4]), Series([2,5,3,1]), Series([3, 2, 4])]
In [45]: counts = Counter(chain.from_iterable(data))
In [46]: unique_occurrences = [item for item, count in counts.items() if count == 1]
In [47]: unique_occurrences
Out[47]: [7, 5]

Spyder会话:

def uniq_0(data):       # Original
    counts = Counter(chain.from_iterable(data))
    return [item for item, count in counts.items() if count == 1]

def uniq_1(data):       # Divakar #1
    a = np.concatenate(data)
    unq,c = np.unique(a, return_counts=1)
    return unq[c==1]

def uniq_2(data):       # Divakar #2
    a = np.concatenate(data)
    return np.flatnonzero(np.bincount(a)==1)

def uniq_3(data):       # Divakar #3
    counts = Counter(chain.from_iterable(data))
    k = np.array(list(counts.keys()))
    v = np.array(list(counts.values()))
    return k[v==1]

def uniq_4(data):       # Divakar #4
    L = max([i.max() for i in data])+1
    return np.flatnonzero(np.sum([np.bincount(i,minlength=L) 
                                  for i in data],axis=0)==1)

def uniq_5(data):       # Divakar #5
    L = max([i.max() for i in data])+1
    sums = np.zeros(L,dtype=int)
    for i in data:
        sums += np.bincount(i,minlength=L)
    return np.flatnonzero(sums==1)

def uniq_6(data):       # Erfan 
    v = pd.concat(data).value_counts()
    return v.index[v == 1]

if __name__ == '__main__':
    data = [Series([1,2,7,4]), Series([2,5,3,1]), Series([3, 2, 4])]
    funcs = [uniq_0, uniq_1, uniq_2, uniq_3, uniq_4, uniq_5, uniq_6]
    answers = [f(data) for f in funcs]
    golden = set(answers[0])
    check = [set(a) == golden for a in answers]
    for n, a in enumerate(answers):
        if set(a) != golden:
            print(f'  Error with uniq_{n}(data)')
        else:
            print(f'  Confirmed uniq_{n}(data) == golden')

评论

非常感谢您。我的实际数据较大,但无法在这台笔记本电脑上使用,但是我觉得我现在有足够的选择来做到这一点。 再次感谢

2 个答案:

答案 0 :(得分:3)

方法1

这是一个基于NumPy的数组-

a = np.concatenate(data)
unq,c = np.unique(a, return_counts=1)
out = unq[c==1]

方法2(用于正整数数据)

对于正整数数据,我们可以使用np.bincount直接从out获得a-

out = np.flatnonzero(np.bincount(a)==1) # a from app#1

方法3

如果我们要使用counts,在处理大量序列时可能更喜欢,因为在这种情况下串联可能会更慢-

k = np.array(list(counts.keys()))
v = np.array(list(counts.values()))
out = k[v==1]

方法4(用于正整数数据)

由于大量的序列包含正整数,因此我们可以在每个序列上使用bincount,从而避免串联-

L = max([i.max() for i in data])+1
out = np.flatnonzero(np.sum([np.bincount(i,minlength=L) for i in data],axis=0)==1)

方法5(用于正整数数据)

可以像这样进一步改善内存效率-

L = max([i.max() for i in data])+1
sums = np.zeros(L,dtype=int)
for i in data:
    sums += np.bincount(i,minlength=L)
out = np.flatnonzero(sums==1)

答案 1 :(得分:2)

我们可以结合使用pd.concatvalue_counts并应用布尔索引:

v = pd.concat(data).value_counts()
v.index[v == 1].to_numpy()

哪个产量

array([7, 5], dtype=int64)

注意
如果您的熊猫版本为<0.24.0,请改用:

v.index[v == 1].values

了解更多here