开发者社区> 问答> 正文

如何在引用某些其他行上的数据时对DF中的每一行执行计算?

我正在寻找一种有效的方法来计算新列数据(对于每一行),使用可能存在于其他行上的信息。

这是一个示例性子集:

df = pd.DataFrame({'baseSeq': {0: 'ADTPICR', 1: 'ADTPICR', 2: 'AVALFAED', 3: 'AVALFAED', 4: 'AVALFAED', 5: 'AVALFAED', 6: 'AVALFAED', 7: 'AVALFAED'}, 'modSeq': {0: 'ADT[+16]PICR', 1: 'ADTPICR', 2: 'AVALFAED[+16]', 3: 'AVALFAE[+16]D', 4: 'AVALFAED', 5: 'AVALFAED[-30]', 6: 'AVALFAED', 7: 'AVALFAED'}, 'charge': {0: 2, 1: 2, 2: 2, 3: 2, 4: 2, 5: 3, 6: 3, 7: 4}, 'modType': {0: 'hydoxy', 1: 'UNMOD', 2: 'hydroxy', 3: 'hydroxy', 4: 'UNMOD', 5: 'decarbox', 6: 'UNMOD', 7: 'UNMOD'}, 'area_0': {0: 1862, 1: 22737, 2: 40060, 3: 40131, 4: 21962, 5: 12, 6: 21885, 7: 2116}, 'area_25': {0: 2472, 1: 30966, 2: 2423, 3: 2407, 4: 34387, 5: 16, 6: 35444, 7: 3072}, 'area_50': {0: 3015, 1: 24660, 2: 3553, 3: 3577, 4: 29860, 5: 40, 6: 33511, 7: 2974}})

 baseSeq          modSeq  charge    modType  area_0  area_25  area_50

0 ADTPICR ADT[+16]PICR 2 hydoxy 1862 2472 3015
1 ADTPICR ADTPICR 2 UNMOD 22737 30966 24660
2 AVALFAED AVALFAED[+16] 2 hydroxy 40060 2423 3553
3 AVALFAED AVALFAE[+16]D 2 hydroxy 40131 2407 3577
4 AVALFAED AVALFAED 2 UNMOD 21962 34387 29860
5 AVALFAED AVALFAED[-30] 3 decarbox 12 16 40
6 AVALFAED AVALFAED 3 UNMOD 21885 35444 33511
7 AVALFAED AVALFAED 4 UNMOD 2116 3072 2974
具体来说,我想计算每个修改序列(基本上每行)的“未修改分数”的新列,然后在多个“区域”列中展开它。

fracUnmod =(1-(area_modified /(area_modified + area_unmodified)))

“area_unmodified”值必须来自不同的行,所以我似乎无法找到使用类似df.concat()或函数的方法df.insert()。正确的“area_unmodified”值是从共享相同“baseSeq”和“charge”值的行确定的,但没有任何修改(为方便起见,我包括了一个列'modType')。

我没有为未修改的行计算fracUnmod,但我不想从我的结果输出中删除这些行(只留下fracUnmod = 0.5,这很好)。

有时行中没有找到未修改的版本(未显示),但是我把它们排除了,因为我知道我在一个单独的帖子中提出了二级问题的偏好,而且我已经能够手动过滤它们了。 Excel中。

我一直在做这样的事情,循环到每一行:

for X in df.columns[df.columns.str.contains('area')].tolist():

df[X.replace('area', 'fracUnmod')] = ''

for row in df.index:

for X in df.columns[df.columns.str.contains('area')].tolist():
    Y = X.replace('area', 'fracUnmod')
    df[Y].iloc[row] = (1 - ((df.iloc[row][X]) / ((df.iloc[row][X]) + (df[(df.baseSeq==df.iloc[row].baseSeq) & (df.charge==df.iloc[row].charge) & (df.baseSeq==df.modSeq)][X].item()))))

它可以工作,但是我的完整数据集需要很长时间(~10分钟)(“行”为“行”为650行,“X”为“循环”为10“区域”列)。

我也提出那个讨厌的“SettingWithCopyWarning” - 我是否通过附加.ascopy()到我最后一行的“链式分配”来避免这种情况?我从来没有弄明白这一点。

我已多次读过应尽可能避免循环,所以我猜这是问题所在。有更干净,更快捷的方法吗?

'modSeq'和'charge'的每个组合都是独一无二的,所以也许我想用df.groupby()or 做什么df.merge(),并使用临时DF?

我经常遇到这种情况,所以我想学习如何在不使用循环的情况下做这种事情(或者至少提高速度)。

展开
收起
一码平川MACHEL 2019-01-23 14:27:18 2152 0
1 条回答
写回答
取消 提交回答
  • 如果我们创建一些临时列,可以对数学运算进行矢量化,这应该会大大减少时间量。之后我们可以删除临时列。

    使用您给出的示例,它看起来像这样:

    我们从一个df看起来像这样的开头:

    baseSeq    modSeq        charge     modType   area_0  area_25   area_50

    0 ADTPICR ADT[+16]PICR 2 hydoxy 1862 2472 3015
    1 ADTPICR ADTPICR 2 UNMOD 22737 30966 24660
    2 AVALFAED AVALFAED[+16] 2 hydroxy 40060 2423 3553
    3 AVALFAED AVALFAE[+16]D 2 hydroxy 40131 2407 3577
    4 AVALFAED AVALFAED 2 UNMOD 21962 34387 29860
    5 AVALFAED AVALFAED[-30] 3 decarbox 12 16 40
    6 AVALFAED AVALFAED 3 UNMOD 21885 35444 33511
    7 AVALFAED AVALFAED 4 UNMOD 2116 3072 2974
    创建所有“区域”列的列表:

    area_cols = df.columns[df.columns.str.contains('area')].tolist()

    以下5行代码创建一个临时df,其中包含每个/ combo 的未修改区域:baseSeqcharge

    temp_df = df[['baseSeq'] + ['charge'] + ['modType'] + area_cols].groupby(['baseSeq', 'charge', 'modType'], axis=0).sum()
    temp_df = temp_df.reset_index(level=2)
    temp_df = temp_df[temp_df['modType'] == 'UNMOD']
    temp_df = temp_df.drop('modType', axis=1)
    temp_df.rename(columns = lambda x: 'unmod_' + x, inplace=True)
    这是临时df在这一点上的样子:

                unmod_area_0    unmod_area_25   unmod_area_50

    baseSeq charge
    ADTPICR 2 22737 30966 24660
    AVALFAED 2 21962 34387 29860

              3        21885            35444          33511
              4         2116             3072           2974

    然后,我们将此临时数据帧连接回主数据框,以便为每个baseSeq/ charge组合显示适当数量的未修改区域的列:

    df = df.join(temp_df, on=['baseSeq', 'charge'])

    此时,我们的数据框如下所示:

    baseSeq     modSeq       charge  modType    area_0  area_25 area_50 unmod_area_0    unmod_area_25   unmod_area_50

    0 ADTPICR ADT[+16]PICR 2 hydoxy 1862 2472 3015 22737 30966 24660
    1 ADTPICR ADTPICR 2 UNMOD 22737 30966 24660 22737 30966 24660
    2 AVALFAED AVALFAED[+16] 2 hydroxy 40060 2423 3553 21962 34387 29860
    3 AVALFAED AVALFAE[+16]D 2 hydroxy 40131 2407 3577 21962 34387 29860
    4 AVALFAED AVALFAED 2 UNMOD 21962 34387 29860 21962 34387 29860
    5 AVALFAED AVALFAED[-30] 3 decarbox 12 16 40 21885 35444 33511
    6 AVALFAED AVALFAED 3 UNMOD 21885 35444 33511 21885 35444 33511
    7 AVALFAED AVALFAED 4 UNMOD 2116 3072 2974 2116 3072 2974
    现在主要部分:我们遍历每个“区域”列并计算所需的分数。该计算在列的每一行上进行矢量化,并且应该大大加快速度。
    for col in area_cols:

    num = col.split('_')[1]
    df['fracUnmod_' + num] = 1 - (df[col] / (df[col] + df['unmod_' + col]))

    要清理一下,让我们通过删除显示未修改区域的临时列来完成,并删除我们的临时数据帧。

    df = df.drop(['unmod_' + c for c in area_cols], axis=1)

    del(temp_df)

    最终的数据框如下所示:

    baseSeq     modSeq       charge  modType    area_0  area_25 area_50 fracUnmod_0  fracUnmod_25   fracUnmod_50

    0 ADTPICR ADT[+16]PICR 2 hydoxy 1862 2472 3015 0.924306 0.926072 0.891057
    1 ADTPICR ADTPICR 2 UNMOD 22737 30966 24660 0.500000 0.500000 0.500000
    2 AVALFAED AVALFAED[+16] 2 hydroxy 40060 2423 3553 0.354100 0.934175 0.893664
    3 AVALFAED AVALFAE[+16]D 2 hydroxy 40131 2407 3577 0.353695 0.934582 0.893023
    4 AVALFAED AVALFAED 2 UNMOD 21962 34387 29860 0.500000 0.500000 0.500000
    5 AVALFAED AVALFAED[-30] 3 decarbox 12 16 40 0.999452 0.999549 0.998808
    6 AVALFAED AVALFAED 3 UNMOD 21885 35444 33511 0.500000 0.500000 0.500000
    7 AVALFAED AVALFAED 4 UNMOD 2116 3072 2974 0.500000 0.500000 0.500000
    这与原始嵌套for循环生成的输出相同。

    2019-07-17 23:26:37
    赞同 展开评论 打赏
问答地址:
问答排行榜
最热
最新

相关电子书

更多
低代码开发师(初级)实战教程 立即下载
冬季实战营第三期:MySQL数据库进阶实战 立即下载
阿里巴巴DevOps 最佳实践手册 立即下载