我试图总结/聚合一个框架如下。虽然代码给出了正确的结果,但它非常重复,我想避免这种情况。我认为我需要使用像groupby
,agg
,apply
,等等,但找不到这样做的方法。目标是在最后计算df_summ
。我认为我使用了太多的中间嵌套,选择了行,而且太多的merge
s把结果拼在一起,我觉得一定有更简单的方法,但是想不出来。
真实的df_stats
输入字符串有数百万行,而df_summ
输出字符串有几十列。下面显示的输入只是一个最小的可复制示例。
import io
import pandas as pd
TESTDATA="""
enzyme regions N length
AaaI all 10 238045
AaaI all 20 170393
AaaI all 30 131782
AaaI all 40 103790
AaaI all 50 81246
AaaI all 60 62469
AaaI all 70 46080
AaaI all 80 31340
AaaI all 90 17188
AaaI captured 10 292735
AaaI captured 20 229824
AaaI captured 30 193605
AaaI captured 40 163710
AaaI captured 50 138271
AaaI captured 60 116122
AaaI captured 70 95615
AaaI captured 80 73317
AaaI captured 90 50316
AagI all 10 88337
AagI all 20 19144
AagI all 30 11030
AagI all 40 8093
AagI all 50 6394
AagI all 60 4991
AagI all 70 3813
AagI all 80 2759
AagI all 90 1666
AagI captured 10 34463
AagI captured 20 19220
AagI captured 30 15389
AagI captured 40 12818
AagI captured 50 10923
AagI captured 60 9261
AagI captured 70 7753
AagI captured 80 6201
AagI captured 90 4495
"""
df_stats = pd.read_csv(io.StringIO(TESTDATA), sep='\s+')
df_cap_N90 = df_stats[(df_stats['N'] == 90) & (df_stats['regions'] == 'captured')].drop(columns=['regions', 'N'])
df_cap_N50 = df_stats[(df_stats['N'] == 50) & (df_stats['regions'] == 'captured')].drop(columns=['regions', 'N'])
df_all_N50 = df_stats[(df_stats['N'] == 50) & (df_stats['regions'] == 'all') ].drop(columns=['regions', 'N'])
df_summ_cap_N50_all_N50 = pd.merge(df_cap_N50, df_all_N50, on='enzyme', how='inner', suffixes=('_cap_N50', '_all_N50'))
df_summ_cap_N50_all_N50['cap_N50_all_N50'] = (df_summ_cap_N50_all_N50['length_cap_N50'] -
df_summ_cap_N50_all_N50['length_all_N50'])
print(df_summ_cap_N50_all_N50)
df_summ_cap_N90_all_N50 = pd.merge(df_cap_N90, df_all_N50, on='enzyme', how='inner', suffixes=('_cap_N90', '_all_N50'))
df_summ_cap_N90_all_N50['cap_N90_all_N50'] = df_summ_cap_N90_all_N50['length_cap_N90'] - df_summ_cap_N90_all_N50['length_all_N50']
print(df_summ_cap_N90_all_N50)
df_summ = pd.merge(df_summ_cap_N50_all_N50.drop(columns=['length_cap_N50', 'length_all_N50']),
df_summ_cap_N90_all_N50.drop(columns=['length_cap_N90', 'length_all_N50']),
on='enzyme', how='inner')
print(df_summ)
字符串
印刷品:
enzyme length_cap_N50 length_all_N50 cap_N50_all_N50
0 AaaI 138271 81246 57025
1 AagI 10923 6394 4529
enzyme length_cap_N90 length_all_N50 cap_N90_all_N50
0 AaaI 50316 81246 -30930
1 AagI 4495 6394 -1899
enzyme cap_N50_all_N50 cap_N90_all_N50
0 AaaI 57025 -30930
1 AagI 4529 -1899
型
本问题背后的生物信息学背景说明:
- (可以跳过这里,它描述了python代码背后的领域知识)*
上面的代码是一个多步骤生物信息学项目中的一个步骤,在这个项目中,我试图根据它们切割DNA的方式找到最佳的限制性内切酶。
作为此步骤的输入,我有一个包含限制性内切酶的表(其名称存储在列enzyme
中)。我想根据切割DNA方式的统计特性对酶进行排名。列regions
存储两种不同的DNA区域类型,我想用这些酶来区分。列N
是统计量的名称,它测量DNA被切割的精细程度(N10,...,N90),length
是此统计量的值。N
统计量总结了DNA片段长度分布,以核苷酸为单位测量,在精神上与分位数相似(10%,...,90%)。当我比较酶时,我想做简单的运算,如cap_N90_all_N50 = { captured N90 } - { all N50 }
等。然后我按cap_N50_all_N50
等的组合对酶进行排名。
4条答案
按热度按时间qcbq4gxm1#
你没有描述逻辑,我不明白为什么你不计算
df_all_N90
。也就是说,要获得预期的输出,您可以尝试
pivot
/sub
:字符串
输出量:
型
3phpmpom2#
Groupby和Aggregate
我们首先按多个列进行分组- 'enzyme','regions','N'。这将每个酶,区域和N值的所有统计数据分组到一个聚合行中。
.agg()通过只取每个组的第一个值来聚合长度列。我们不再需要前面的重复过滤。所有数据都是预先分组的。
字符串
枢轴比较
统计数据框中的每个统计数据都有一行。为了便于比较,我们将其透视到列中:
型
现在,所有长度值都按列对齐,按N和区域分割。
矢量化列操作
我们可以直接在枢轴上取列差:
型
在一次向量化操作中对FULL列进行差分,避免了行循环。
最终汇总输出
我们只将所需的差异列输出到一个干净的摘要框架中:
型
输出量:
型
uqzxnwby3#
另一种方法是将
df_stats
转换为MultiIndex Series,过滤相关的行,并从过滤的行中减去enzyme
的regions='all'
和N=50
值。然后剩下的就是将Series解栈回一个嵌套框。字符串
该框架将经历以下转换:
的数据
x8diyxa74#
另一种可能性。找到每个酶的
all
区域N50
值,从captured
值中减去这些值,然后将结果旋转回每个组合的列:字符串
输出量:
型