熊猫一次替换多个列的内容以适应多个条件

Posted

技术标签:

【中文标题】熊猫一次替换多个列的内容以适应多个条件【英文标题】:pandas replace contents of multiple columns at a time for multiple conditions 【发布时间】:2017-12-26 06:40:04 【问题描述】:

我有一个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'列表中的字符串。

下一个挑战是如何解析填充示例列其他部分的变量字符串。我尝试过使用拆分功能:

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 个样本列。

【问题讨论】:

查看 pandas 系列中的各种.str 方法和pd.Series.replace() 方法。例如:df.loc[:, ['SRR4216489', 'SRR4216675', 'SRR4216480']].replace("./.", 0.5, inplace=True) 【参考方案1】:

您可以通过使用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
...

【讨论】:

谢谢你,我怎么能自动在列中输入呢?如果我尝试为函数添加列参数,那么在调用函数时将参数提供给函数不起作用? 更新了我的答案,使您要修改的列更通用。 非常感谢!该解决方案有效,尽管任何进一步的加快速度的建议都很好,尽管不是必需的。运行 1 条染色体大约需要 5 分钟,但我可以忍受(有 24 条染色体可以运行)。再次感谢! 更新了一个明显更快的选项。希望对您有所帮助!

以上是关于熊猫一次替换多个列的内容以适应多个条件的主要内容,如果未能解决你的问题,请参考以下文章

是否可以将多个管道组合到 Neuraxle 或 sklearn 中的单个估计器中以创建多输出分类器并一次性适应

如何在 BigQuery 中将多个列的空值替换为 0?

在使用条件聚合进行分组时选择多个第 n 个值 - 熊猫

queryList 一次抓取多个网页内容的方法--目前只有用循环 替换页码或者给出url循环进行 queryList没有像python一样的yied迭代方法 queryList 实现多个实例抓取

如何查询函数 Google 电子表格 - 基于多个条件的数据过滤(一次检查多个列)

Java一次替换字符串中的多个不同子字符串(或以最有效的方式)