pandas 在另一个 Dataframe 中搜索列对的更快方法

xytpbqjk  于 2023-04-10  发布在  其他
关注(0)|答案(2)|浏览(107)

我有一个名为df的大 Dataframe ,大约有4500万行,如下所示。

gene1   gene2     score
0       PIGA  ATF7IP1 -0.047236
1       PIGB  ATF7IP2 -0.047236
2       PIGC  ATF7IP3 -0.047236
3       PIGD  ATF7IP4 -0.047236
4       PIGE  ATF7IP5 -0.047236

我有一个名为terms的小 Dataframe ,大小约为3k行。

id                                gene_set
1                                 {HDAC4, BCL6}
2                                 {HDAC5, BCL6}
3                                 {HDAC7, BCL6}
4                 {NCOA3, KAT2B, EP300, CREBBP}
5            {NCAPD2, NCAPH, NCAPG, SMC4, SMC2}
                         ...                   
2912                              {FOXO1, ESR1}
2913                               {APP, FOXO3}
2914                               {APP, FOXO1}
2915                               {APP, FOXO4}
2916    {MAP3K20, MAPK14, AKAP13, MAP2K3, PKN1}

对于每行,我检查terms数据集中是否存在gene1,gene2对。
我的代码工作正常,但我想问的是,有什么更快的想法吗?
我已经尝试了几个代码,但运行时间大致相同。

def search(g1,g2):
    # search gene pair in the go terms
    return sum(terms.gene_set.map(set([g1,g2]).issubset))

代码示例1

np.sum(np.vectorize(search)(df.gene1,df.gene2))

代码示例2

[search(g1, g2) for g1, g2 in zip(df.gene1,df.gene2)]

代码示例3

df[['gene1','gene2']].apply(lambda x: search(x.gene1,x.gene2), axis=1 )
pdkcd3nj

pdkcd3nj1#

我看到了一个简单的方法,可以通过将set([g1,g2])修改为{g1,g2}.issubset来加快search函数的运行速度。由于不再需要将列表转换为集合,因此可以避免大量的工作。
这里有一个简单的测试用例

In [4]: %timeit set([1,2]).issubset({1,2,3})

184 ns ± 2.08 ns per loop (mean ± std. dev. of 7 runs, 10,000,000 loops each)

In [5]: %timeit {1,2}.issubset({1,2,3})
120 ns ± 0.607 ns per loop (mean ± std. dev. of 7 runs, 10,000,000 loops each)

你也可以在函数中传递terms Dataframe ,这样解释器就不需要在函数作用域之外寻找它,也许你可以使用pd.Series.sum()函数而不是调用Python函数(这也应该加快速度)。

def search(g1, g2, terms):
    # search gene pair in the go terms
    return terms.gene_set.map({g1,g2}.issubset).sum()

除此之外,您可以尝试使用PolarsDaskdf.apply()方法,以获得更大的速度提升。

qmb5sa22

qmb5sa222#

如果你.explode较小的术语dataframe摆脱集。

long_terms = terms.explode('gene_set')
>>> long_terms
   id gene_set
0   1     BCL6
0   1    HDAC4
1   2     BCL6
1   2    HDAC5
2   3    HDAC7
2   3     BCL6
3   4    KAT2B
3   4   CREBBP
3   4    NCOA3
3   4    EP300
4   5     SMC2
4   5    NCAPH
4   5     SMC4
4   5   NCAPD2
4   5    NCAPG
5   6  ATF7IP2
5   6        A
6   7     PIGB
6   7        B
7   8     PIGB
7   8        C
7   8  ATF7IP2

然后可以使用.isin

same_row = (
   long_terms.gene_set.isin(df.gene1).groupby(level=0).any()
   &
   long_terms.gene_set.isin(df.gene2).groupby(level=0).any()
)

found = long_terms.loc[same_row]
>>> found
   id gene_set
7   8     PIGB
7   8        C
7   8  ATF7IP2

要查找相应的匹配项,请执行以下操作:

>>> df.gene1.isin(found.gene_set) & df.gene2.isin(found.gene_set)
0    False
1     True
2    False
3    False
4    False
dtype: bool
>>> df[df.gene1.isin(found.gene_set) & df.gene2.isin(found.gene_set)]
  gene1    gene2     score
1  PIGB  ATF7IP2 -0.047236

所用样品:

>>> df
  gene1    gene2     score
0  PIGA  ATF7IP1 -0.047236
1  PIGB  ATF7IP2 -0.047236
2  PIGC  ATF7IP3 -0.047236
3  PIGD  ATF7IP4 -0.047236
4  PIGE  ATF7IP5 -0.047236
>>> terms
   id                            gene_set
0   1                       {BCL6, HDAC4}
1   2                       {BCL6, HDAC5}
2   3                       {HDAC7, BCL6}
3   4       {KAT2B, CREBBP, NCOA3, EP300}
4   5  {SMC2, NCAPH, SMC4, NCAPD2, NCAPG}
5   6                        {ATF7IP2, A}
6   7                           {PIGB, B}
7   8                  {PIGB, C, ATF7IP2}
terms = pd.DataFrame({
   "id": [1, 2, 3, 4, 5, 6, 7, 8], 
   "gene_set": [
      {"HDAC4", "BCL6"},
      {"HDAC5", "BCL6"},
      {"HDAC7", "BCL6"},
      {"NCOA3", "KAT2B", "EP300", "CREBBP"},
      {"NCAPD2", "NCAPH", "NCAPG", "SMC4", "SMC2"},
      {"A", "ATF7IP2"},
      {"B", "PIGB"},
      {"C", "ATF7IP2", "PIGB"},
   ]
})

相关问题