我有一个 df 如下:
CHROM POS SRR4216489 SRR4216675 SRR4216480
0 1 127536 ./. ./. ./.
1 1 127573 ./. 0/1:0,5:5:0:112,1,10 ./.
2 1 135032 ./. 1/1:13,0:13:3240:0,30,361 0/0:13,0:13:3240:0,30,361
3 1 135208 ./. 0/0:5,0:5:3240:0,20,160 0/1:5,0:5:3240:0,20,160
4 1 138558 1/1:5,0:5:3240:0,29,177 0/0:0,5:5:0:112,1,10 ./.
我想根据某些条件替换示例列的内容。示例列为 SRR4216489、SRR4216675、SRR4216480。我正在寻找替换“./.” 0.5,以 0/0 开头的任何内容都以 0.0 开头,任何以 0/1 或 1/1 开头的内容都以 1.0 开头。我知道这涉及多个过程,其中大部分我可以独立完成,但我不知道将它们结合在一起的语法。例如,我可以对示例 SRR4216480 执行此操作:
df['SRR4216675'][df.SRR4216675 == './.'] = 0.5
这很好用,courtesy of here ,但我不确定如何将其同时应用于所有示例列。我想使用循环:
sample_cols = df.columns[2:]
for s in sample_cols:
df[s][df.s =='./.'] = 0.5
但这首先看起来并不是很随意,而且它也不接受“df.s”列表中的字符串。
下一个挑战是如何解析填充示例列其他部分的变量字符串。我尝试过使用 split 函数:
df=df['SRR4216675'][df.SRR4216675.split(':') == '0/0' ] = 0.0
但我得到:
TypeError: 'float' object is not subscriptable
我确信解决这个问题的一个好方法是使用 lambda,例如 this但作为 pandas 和 lambdas 的新手,我发现这很棘手,我来到这里:
col=df['SRR4216675'][df.SRR4216675.apply(lambda x: x.split(':')[0])]
看起来几乎就在那里,但需要进一步处理来替换该值,而且它看起来有 2 列,不允许我将其重新集成到现有的 df 中:
SRR4216675
./. NaN
0/1 NaN
1/1 NaN
0/0 NaN
0/0 NaN
df['SRR4216675'] = col
ValueError: cannot reindex from a duplicate axis
我明白这是 1 中的几个问题,但我是 pandas 的新手,并且真的很想解决它。我可以使用基本列表和循环以及 python 标准列表、迭代和字符串解析函数来解决这些问题,但从规模上看,这会非常慢,因为我的全尺寸 df 有数百万行长,包含超过 500 个示例列。
最佳答案
您可以通过使用 df.apply 并定义一个函数来完成此操作,如下所示:
In [10]: cols = ('SRR4216675', 'SRR4216480', 'SRR4216489')
In [11]: def replace_vals(row):
...: for col in cols:
...: if row[col] == './.':
...: row[col] = 0.5
...: elif row[col].startswith('0/0'):
...: row[col] = 0
...: elif row[col].startswith('0/1') or row[col].startswith('1/1'):
...: row[col] = 1
...: return row
...:
...:
In [12]: df.apply(replace_vals, axis=1)
Out[12]:
CHROM POS SRR4216480 SRR4216489 SRR4216675
0 1 127536 0.5 0.5 0.5
1 1 127573 0.5 0.5 1.0
2 1 135032 0.0 0.5 1.0
3 1 135208 1.0 0.5 0.0
4 1 138558 0.5 1.0 0.0
这是一种更快的方法:
首先,让我们创建一个更大的数据框,以便我们可以有意义地测量时间差异,然后导入一个计时器以便我们可以测量。
In [70]: from timeit import default_timer as timer
In [71]: long_df = pd.DataFrame()
In [72]: for i in range(10000):
...: long_df = pd.concat([long_df, df])
使用我们上面定义的函数,我们得到:
In [76]: start = timer(); long_df.apply(replace_vals, axis=1); end = timer()
In [77]: end - start
Out[77]: 8.662535898998613
现在,我们定义一个新函数(为了轻松计时),我们在其中循环列并应用与上面相同的替换逻辑,只不过我们使用矢量化的 str.startswith
每列的方法:
In [78]: def modify_vectorized():
...: start = timer()
...: for col in cols:
...: long_df.loc[long_df[col] == './.', col] = 0.5
...: long_df.loc[long_df[col].str.startswith('0/0', na=False), col] = 0
...: long_df.loc[long_df[col].str.startswith('0/1', na=False), col] = 1
...: long_df.loc[long_df[col].str.startswith('1/1', na=False), col] = 1
...: end = timer()
...: return end - start
我们重新创建大型数据帧,并在其上运行新函数,获得显着的加速:
In [79]: long_df = pd.DataFrame()
In [80]: for i in range(10000):
...: long_df = pd.concat([long_df, df])
...:
In [81]: time_elapsed = modify_vectorized()
In [82]: time_elapsed
Out[82]: 0.44004046998452395
生成的数据框如下所示:
In [83]: long_df
Out[83]:
CHROM POS SRR4216480 SRR4216489 SRR4216675
0 1 127536 0.5 0.5 0.5
1 1 127573 0.5 0.5 1
2 1 135032 0 0.5 1
3 1 135208 1 0.5 0
4 1 138558 0.5 1 0
0 1 127536 0.5 0.5 0.5
1 1 127573 0.5 0.5 1
2 1 135032 0 0.5 1
3 1 135208 1 0.5 0
4 1 138558 0.5 1 0
0 1 127536 0.5 0.5 0.5
1 1 127573 0.5 0.5 1
2 1 135032 0 0.5 1
3 1 135208 1 0.5 0
4 1 138558 0.5 1 0
0 1 127536 0.5 0.5 0.5
...
关于python - pandas 针对多种条件一次替换多列的内容,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45216862/