在列中统计项,还是为什么我的代码只统计字符串中的一个项?
这是对 昨天的问题 的延续。
我需要统计一个词(基因名)在一行中出现的次数(细菌样本)。我想看看有多少对重复拷贝的基因。
自昨天起,我决定把包含基因名的所有列合并成一列:
df3['AMRs'] = df3[df3.columns[0:]].apply(lambda x: ','.join(x.dropna().astype(str)),axis=1)
得到的列像这样:
0 fosX,vga(G)
1 fosX,vga(G)
2 fosX,vga(G)
3 fosX,vga(G)
4 fosX,vga(G)
...
#number of samples/rows is 18022.
现在我试着统计每个基因:
y= {} # dict
for X in genenames:
y[X] = df2["AMRs"].str.count(X)
for key in list(y.keys()):
print(key, ':', y[key])
其中genenames是:
['fosX', 'vga(G)', 'emrC', 'tet(M)', ... , 'vga', 'vga=HMM'] #there are 100 genes
但没有为fosX和 vga(G) 得到1(或2),我得到的是:
{'fosX': 0 1
1 1
2 1
3 1
4 1
..
'vga(G)': 0 0
1 0
2 0
3 0
4 0
..
如果你查看那一列,两个基因都应该有1,但vga(G) 没有被计入。
奇怪的是,在列表末尾的“vga”是除了fosX之外唯一得到1 的基因,但我知道这些样本并不拥有这个基因。
我到底做错了什么?是正则表达式的问题吗?
解决方案
问题在于 ( ) 在 vga(G) 中具有特殊含义,而 .str.count() 在 pandas 中使用的是正则表达式。
它可能需要将 ( 替换为 \(,将 ) 替换为 \),或者更简单地使用 re.escape()
y[X] = df["AMRs"].str.count( X.replace("(", r"\(").replace(")", r"\)") )
y[X] = df["AMRs"].str.count( re.escape(X) )
最终使用 apply(),配合标准的 str.count()
y[X] = df["AMRs"].apply(lambda text: text.count(X))
但正则表达式还有另一个问题:count("vga") 也会把 vga(G)/vga=HMM 计为 vga。它需要使用 ^vga$。
使用 .eq().sum() 时,vga(G)/vga=HMM 会被当作与 vga 不同的元素。
而且不需要把所有列都转换成一个字符串。
for X in genenames:
# no need to use `df[df.columns[0:]]`
y[X] = df.eq(X).sum(axis=1)
顺便说一句:要在随机数据上测试,可以使用 random.choices()
import random
#random.seed(0) # to have always the same random data
genenames = ["fosX", "vga(G)", "emrC", "tet(M)", "vga", "vga=HMM"]
cols = 20
rows = 5
df = pd.DataFrame([
random.choices(genenames, k=cols)
for _ in range(rows)
])
用于测试的最小可运行代码:
import pandas as pd
import io
import re
import random
random.seed(0) # to have always the same random data
text = """
0,fosX,vga(G)
1,fosX,vga(G)
2,fosX,vga(G)
3,fosX,vga(G)
4,fosX,vga(G)
"""
genenames = ["fosX", "vga(G)", "emrC", "tet(M)", "vga", "vga=HMM"]
# --- create dataframe ---
df = pd.read_csv(io.StringIO(text), header=None)
cols = 5
rows = 3
df = pd.DataFrame([random.choices(genenames, k=cols) for _ in range(rows)])
print("--- df ---")
print(df)
# --- .str.count() ---
# no need to use `df[df.columns[0:]]`
df["AMRs"] = df.apply(
lambda row: ",".join(row.dropna().astype(str)), axis=1
)
y = pd.DataFrame()
for X in genenames:
# y[X] = df["AMRs"].str.count(X)
# y[X] = df["AMRs"].str.count(X.replace("(", r"\(").replace(")", r"\)"))
y[X] = df["AMRs"].str.count(re.escape(X))
# y[X] = df["AMRs"].apply(lambda text: text.count(X))
print("--- .str.count() ---")
print(pd.DataFrame(y))
# --- .eq().sum() ---
y = pd.DataFrame()
for X in genenames:
# no need to use `df[df.columns[0:]]`
y[X] = df.eq(X).sum(axis=1)
# y[X] = (df == X).sum(axis=1)
print("--- .eq().sum() ---")
print(y)
结果:
(列 vga 对 .str.count() 和 .eq().sum() 的结果不同
--- df ---
0 1 2 3 4
0 vga=HMM vga emrC vga(G) tet(M)
1 emrC vga vga(G) emrC tet(M)
2 vga=HMM tet(M) vga(G) vga tet(M)
--- .str.count() ---
fosX vga(G) emrC tet(M) vga vga=HMM
0 0 1 1 1 3 1
1 0 1 2 1 2 0
2 0 1 0 2 3 1
--- .eq().sum() ---
fosX vga(G) emrC tet(M) vga vga=HMM
0 0 1 1 1 1 1
1 0 1 2 1 1 0
2 0 1 0 2 1 1
站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。