合并2个具有相同索引/列的SparseDataFrame

时间:2018-01-09 00:05:53

标签: python-3.x pandas

我的表格中有pandas.SparseDataFrame's

A = pd.SparseDataFrame(
    [[a,0,0,b],A
     [0,0,0,c],
     [0,0,0,0],
     [0,0,0,a]])

B = pd.SparseDataFrame(
    [[a,0,0,0],
     [0,0,c,0],
     [0,0,0,c],
     [0,0,0,0]])

那些是(标记的)来自同一图形的子图的邻接矩阵(因此在相同位置你可以找到0或相同的值: A [x] [y] = B [x] [y]每个值!= 0 )。换句话说,价值冲突是不可能的。

我想合并(性能明智)这些数据帧,结果应为:

[[a,0,0,b],
 [0,0,c,c],
 [0,0,0,c],
 [0,0,0,a]]

我不清楚pandas将2个Dataframes与相同列标签合并的方式。

我看到update()可以按我的意愿运行,但它会就地编辑调用DataFrame,我不希望这样。唯一的方法是使用update()进行深层复制然后合并?正如我所说,操作应该是性能方面的。

1 个答案:

答案 0 :(得分:2)

在方法1,2和3中,我们使用来自scipy.sparse的稀疏矩阵。有许多种稀疏矩阵scipy支持,而我实验{{ 1}},coo_matrixcsc_matrixcsr_matrix

首先,将您的功能/标签转换为数字,以便我们可以在此示例中使用一些数学属性:{a到1,b到2,以及c到3}。在方法4中,您不需要转换它。

方法1 :使用其中包含的dok_matrixdok_matrix方法。 update可以对每个元素进行迭代(idx,value)。

update

HOWEVER ,将它加载回熊猫需要很长时间才能合并!这对于方法1,2和3来说都是如此。因此,如果合并的速度是你的浓度,你可能希望坚持使用# to_coo() will make a sparse matrix | todok() will make coo_matrix a dok_matrix A = pd.SparseDataFrame([[1,0,0,2],[0,0,0,3],[0,0,0,0],[0,0,0,1]]).to_coo().todok() B = pd.SparseDataFrame([[1,0,0,0],[0,0,3,0],[0,0,0,3], [0,0,0,0]]).to_coo().todok() nz = B.nonzero() # non-zero's indeces from B # only update when B is non-zero A.update([((nz[0][i], nz[1][i]), B[nz[0][i], nz[1][i]]) for i in range(len(nz[0]))]) %timeit A.update([((nz[0][i], nz[1][i]), B[nz[0][i], nz[1][i]]) for i in range(len(nz[0]))]) 52.2 µs ± 4.38 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each) 超过scipy.sparse

pandas.SparseDataFrame

此外,%timeit pd.SparseDataFrame(A) 3.47 ms ± 319 µs per loop (mean ± std. dev. of 7 runs, 100 loops each) 在其他矩阵操作中可能会很慢。从我的试验中,dok_matrix在简单矩阵运算中速度很慢,稍后您将在方法2和3中看到。但是,只有dok_matrix具有函数dok_matrix。 (update是基于字典的。)虽然这种方法看起来很快,但我猜测如果你的矩阵密度更大,那么使用这种方法与下一种方法比较慢。

方法2 :在此方法中,我们将dok_matrix中大于0的部分与元素相乘B - A以获取{{1}中的部分而不是B。似乎比下面的方法4快位。

B

使用A会稍快一些。

# to_coo() will make a sparse matrix
A = pd.SparseDataFrame([[1,0,0,2],[0,0,0,3],[0,0,0,0],[0,0,0,1]]).to_coo()   
B = pd.SparseDataFrame([[1,0,0,0],[0,0,3,0],[0,0,0,3], [0,0,0,0]]).to_coo() 

D = ((-A + B) > 0).multiply(B) + A

%timeit D = ((-A + B) > 0).multiply(B) + A
645 µs ± 25.6 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

方法3 :此方法使用csc_matrixA = pd.SparseDataFrame([[1,0,0,2],[0,0,0,3],[0,0,0,0],[0,0,0,1]]).to_coo().tocsc() B = pd.SparseDataFrame([[1,0,0,0],[0,0,3,0],[0,0,0,3], [0,0,0,0]]).to_coo().tocsc() %timeit = ((-A + B) > 0).multiply(B) + A 434 µs ± 84.9 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each) 中的((B-A) + np.abs(B-A))/2相同但不在B中的相等内容。 (AA中的相同值将被抵消,差异将加倍。因此,我们将其除以2。)

B

使用C = ((B - A) + np.abs(B-A))/2 + A %timeit C = ((B - A) + np.abs(B-A))/2 + A 852 µs ± 25.3 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each) 可以加快结果

csc_matrix

方法4 :这是缓慢,缓慢,用于基准测试的目的。 使用此方法的另一个方案是,您不需要将每个标签与整数相匹配。正如您所提到的,我们只需要在{{1}时填写A = pd.SparseDataFrame([[1,0,0,2],[0,0,0,3],[0,0,0,0],[0,0,0,1]]).to_coo().tocsc() B = pd.SparseDataFrame([[1,0,0,0],[0,0,3,0],[0,0,0,3], [0,0,0,0]]).to_coo().tocsc() %timeit C = ((-A + B) + np.abs(B-A))/2 + A 598 µs ± 42.1 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each) 的值}}。因此,您可以尝试A,但它会返回密集矩阵。

B == 0

再次注意,如果你真的需要np.where(B == 0, A, B),前三种方法都需要将稀疏矩阵转换回A = pd.SparseDataFrame( [['a',0,0,'b'], [0,0,0,'c'], [0,0,0,0], [0,0,0,'a']]) B = pd.SparseDataFrame( [['a',0,0,0], [0,0,'c',0], [0,0,0,'c'], [0,0,0,0]]) pd.SparseDataFrame(np.where(B == 0, A, B)) %timeit pd.SparseDataFrame(np.where(B == 0, A, B)) 7.39 ms ± 454 µs per loop (mean ± std. dev. of 7 runs, 100 loops each) 。这将使前3种方法几乎与此方法4一样慢。

Takeaways:

  • 将稀疏矩阵转换为SparseDataFrame可能需要更长时间并且失去使用稀疏矩阵的优势。人们可以使用稀疏矩阵而不是SparseDataFrame。
  • 如果您的矩阵密集,您可能希望方法2优于方法1.(我的假设)

  • 在这种特殊情况下,请使用csc_matrixcsr_matrixdok_matrix而不是coo_matrix。但是,我认为不同的稀疏矩阵在不同的场景中会有用。为您特定的应用程序自己计时!

但我没有考虑从pd.SparseDataFrame转移到稀疏矩阵的时间。这不是微不足道的,将在这里讨论。

SparseDataFrame

从上面的实验中可以看出,SparseDataFrame占用了大部分时间,并且在所有1,2和3种方法中都使用了它。因此,它不会改变这些方法的整体速度比较。此外,这些仅在小数据中测试。请事先对数据进行测试,因为数据越大,行为应该不同。

相关问题