Python 3.6+ 中基于单个值过滤多列行的更 pythonic 方式

A more pythonic way to filter rows across multiple columns based on single value in Python 3.6+

我正在寻求有关如何简化我的代码的帮助。 DataFrame 超过 100k 行,并且可以有多个包含字符串和整数混合的列。这是一个例子 df:

data = {
    "Area_1": [0, 100, 200, 0],
    "Area_2": [0, 0, 100, 100],
    "Area_3": [0, 0, 0, 100],
    "id": ["gene_x", "gene_y", "gene_z", "gene_i"],
}
df = pd.DataFrame(data, columns=["id", "Area_1", "Area_2", "Area_3"])

这是我认为可以简化大量有效但只能处理 3 列的代码的代码。如果所有列都包含整数 0,我现在想接受任意数量的列和过滤行。

预期输出: DataFrame 中的所有内容,但包含 gene_x.

的行除外

当前代码:

cut=r'^Area'
blade = df.columns.str.contains(cut)
df[(df.loc[:,blade] > 0).any(axis=1)]

数据框示例:

目前,此代码执行无误,但 returns df 未按预期进行过滤。 我的期望是删除任何不包含值 >0

的行

可以尝试以下方法。

创建数据框

import pandas as pd

data = {
    "Area_1": [0, 100, 200, 0],
    "Area_2": [0, 0, 100, 100],
    "Area_3": [0, 0, 0, 100],
    "id": ["gene_x", "gene_y", "gene_z", "gene_i"],
}
df = pd.DataFrame(data, columns=["id", "Area_1", "Area_2", "Area_3"])
df = df.set_index("id")
print(df)

输出:

        Area_1  Area_2  Area_3
id                            
gene_x       0       0       0
gene_y     100       0       0
gene_z     200     100       0
gene_i       0     100     100

创建一个布尔掩码来指示我们想要的行

# Subset the columns we are interested in.
df_tmp = df.filter(regex="^Area_", axis="columns")
mask = df_tmp == 0
print(mask.head())

# Collapse across columns
all_cols_zero = mask.all(axis=1)
print(all_cols_zero)

输出:

        Area_1  Area_2  Area_3
id                            
gene_x    True    True    True
gene_y   False    True    True
gene_z   False   False    True
gene_i    True   False   False

id
gene_x     True
gene_y    False
gene_z    False
gene_i    False
dtype: bool

将布尔掩码应用于我们的原始数据帧

# Keep rows where at least one column is non-zero.
# The ~ gets the inverse. So True becomes False.
df.loc[~all_cols_zero, :]

输出:

        Area_1  Area_2  Area_3
id                            
gene_y     100       0       0
gene_z     200     100       0
gene_i       0     100     100