计算熊猫数据框中特定时间特定字符串的出现次数

时间:2020-04-06 13:59:22

标签: python pandas

我有一个类似于以下内容的数据框:

virus_RNA                             specie   id       date
XXYGHS, ZZYRSC, Mk4RRE                human     1      04.08.2010
XXYGHS, KRSTYC, ZZQERT                human     2      02.06.2007
Mk4RRE, TTYCY3, WEQ478                bat       3      03.04.2002
Mk4RRE, XXYGHS, ZZQ478, 23RTYB        rat       4      01.01.2001  
VYsr67, XXYGHS, ZZQ478, 23RTYB        rat       5      01.01.2001  
XXYRTC, RTyy7u, MZrgTY                human     6      01.03.2004
Mk4RRE, SfjB23, ZrtY6V, XXYGHS        dog       7     01.12.1993  
XXRSHS, KFK22C, ZZYRSC                human     8      02.06.2003

我想实现两件事: 首先:我想计算在给定日期之前,物种中已观察到所有病毒RNA序列的次数,并创建一个新的数据框。例如,如果我们将第一行作为基准:

virus_RNA  date           human    bat   rat dog
XXYGHS     04.08.2010       1       0    2    1
ZZYRSC     04.08.2010       1       0    0    0
Mk4RRE     04.08.2010       0       1    1    1

第二:我需要回到原始数据框,并添加与病原体相同但与病原体不同的物种中每种病毒RNA以前所有出现的总和。遵循前面的示例:

Occurrence in human specie (as the focal specie) : XXYGHS and ZZYRSC have been observed in human while Mk4RRE has not been observed (1 + 1 + 0 = 2).  

Occurrence in different species (different than the human) : bat (0 + 0 + 1 = 1); rat (2 + 0 + 1 = 3); dog (1 + 0 + 1= 2) and sum = 6

如果我们将其添加回原始数据框:

virus_RNA              specie    date       same_specie different_specie id
XXYGHS, ZZYRSC, Mk4RRE human     04.08.2010         2              6      1

1 个答案:

答案 0 :(得分:2)

[为了更好地回答您的问题而编辑,希望我不会引入任何错误!]

我认为我可以提供帮助。让我们首先生成DataFrame:

df = pd.DataFrame({"virus_RNA": 
                   [
                       "XXYGHS, ZZYRSC, Mk4RRE"         , 
                       "XXYGHS, KRSTYC, ZZQERT",  
                       "Mk4RRE, TTYCY3, WEQ478",  
                       "Mk4RRE, XXYGHS, ZZQ478, 23RTYB",  
                       "VYsr67, XXYGHS, ZZQ478, 23RTYB ",  
                       "XXYRTC, RTyy7u, MZrgTY",  
                       "Mk4RRE, SfjB23, ZrtY6V, XXYGHS",  
                       "XXRSHS, KFK22C, ZZYRSC", 
                   ],
                  "specie":
                   [ 
                       "human",
                       "human",
                       "bat",   
                       "rat",   
                       "rat",   
                       "human", 
                       "dog",   
                       "human",
                   ],
                   "date":
                   [
                       "04.08.2010",
                       "02.06.2007",
                       "03.04.2002",
                       "01.01.2001", 
                       "01.01.2001", 
                       "01.03.2004",
                       "01.12.1993", 
                       "02.06.2003",
                   ]
                  })

我要做的第一件事是为每个病毒RNA创建一行,因为我的答案将基于分组依据:

# Start by creating a list from the strings after having removed the spaces
df.loc[:, "virus_RNA"] = df.loc[:, "virus_RNA"].str.replace(" ", "").str.split(",")
# Explode: one row per element of the list (I changed the previous code to solve the memory error here please confirm this works)
df = df.explode("virus_RNA")

您将得到:

>>> df.head()

    date        specie  virus_RNA
0   04.08.2010  human   XXYGHS
1   04.08.2010  human   ZZYRSC
2   04.08.2010  human   Mk4RRE
3   02.06.2007  human   XXYGHS
4   02.06.2007  human   KRSTYC

然后给定您以后需要的焦点,我将添加一个带有焦点的物种名称的列,然后使用熊猫的get_dummies获得一热编码的specie变量版本。这样我们就可以按总和进行分组。

df["focal"] = df.loc[:, "specie"]
df = pd.get_dummies(df, columns=["specie"], prefix="", prefix_sep="")

这给我们:

>>> df.head()

    date        virus_RNA   focal   bat dog human   rat
0   04.08.2010  XXYGHS      human   0   0   1       0
1   04.08.2010  ZZYRSC      human   0   0   1       0
2   04.08.2010  Mk4RRE      human   0   0   1       0
3   02.06.2007  XXYGHS      human   0   0   1       0
4   02.06.2007  KRSTYC      human   0   0   1       0

现在我们可以做几个分组依据。 对于第一个问题,您可以按日期和总和进行分组,这将为您提供之前创建的假人的总和:

df.groupby(["virus_RNA", "date"]).sum()

具有以下输出:

>>> df.groupby(["virus_RNA", "date"]).sum().head()

                    bat dog human   rat
virus_RNA   date                
23RTYB  01.01.2001  0   0   0       2
KFK22C  02.06.2003  0   0   1       0
KRSTYC  02.06.2007  0   0   1       0
MZrgTY  01.03.2004  0   0   1       0
Mk4RRE  01.01.2001  0   0   0       1

对于第二个问题,我将针对每种病毒RNA计算每个物种的病例数。为此,您可以将总和与分组,然后将其放回第一个数据帧:

df_grouped = df.groupby(["virus_RNA"]).sum().reset_index()
df = df.drop(columns=["bat", "dog", "human", "rat"]).merge(df_grouped, on="virus_RNA").drop_duplicates()

给出结果:

>>> df.head()

    date        virus_RNA   focal   bat dog human   rat
0   04.08.2010  XXYGHS      human   0   1   2       2
1   02.06.2007  XXYGHS      human   0   1   2       2
2   01.01.2001  XXYGHS      rat     0   1   2       2
4   01.12.1993  XXYGHS      dog     0   1   2       2
5   04.08.2010  ZZYRSC      human   0   0   2       0

我们可以通过删除日期并删除重复项来减少数据量,但是我们需要日期来重新创建初始数据框。

我们现在可以在数据帧上使用Apply为“ different_specie”创建一列,为“ same_specie”创建一列:

df["different_specie"] = df.apply(lambda row: sum([val for key, val in row.items() 
                                   if key not in ["virus_RNA", "date", "focal"] 
                                   and row["focal"] != key]),
                  axis=1)
df["same_specie"] = df.apply(lambda row: row[row["focal"]],
                  axis=1)
df = df.loc[:, ["virus_RNA", "focal", "different_specie", "same_specie", "date"]]

这给我们:

>>> df.head()

    virus_RNA   focal   different_specie    same_specie date
0   XXYGHS      human   3                   2           04.08.2010
1   XXYGHS      human   3                   2           02.06.2007
2   XXYGHS      rat     3                   2           01.01.2001
4   XXYGHS      dog     4                   1           01.12.1993
5   ZZYRSC      human   0                   2           04.08.2010

然后,我们需要重新创建初始数据框。我们可以按日期将日期分组,因为您的日期似乎是唯一的,但是随后我们需要连接virus_RNA,这将为我们提供一个缺少几列的临时数据框。然后,我们可以将其与第一个数据帧合并回去,并删除重复项。

temp = df.groupby(["date"])["virus_RNA"].apply(','.join).reset_index()
df = df.merge(temp, on="date").drop("virus_RNA_x", axis=1).drop_duplicates()

哪个给我们:

>>> df.head()


    focal   different_specie    same_specie date        virus_RNA_y
0   human   3                   2           04.08.2010  XXYGHS,ZZYRSC,Mk4RRE
1   human   0                   2           04.08.2010  XXYGHS,ZZYRSC,Mk4RRE
2   human   3                   1           04.08.2010  XXYGHS,ZZYRSC,Mk4RRE
3   human   3                   2           02.06.2007  XXYGHS,KRSTYC,ZZQERT
4   human   0                   1           02.06.2007  XXYGHS,KRSTYC,ZZQERT

但是,virus_RNA中的顺序可能有所不同,您可以通过在开始时对ID进行排序和创建来克服它们。您还需要清除一些内容,例如virus_RNA_y名称。

要获取累计金额,您可以按日期排序,也可以按聚焦点和病毒rna分组:

df[["cumsum_different", "cumsum_same"]] = df.groupby(["virus_RNA_y", "focal"]).cumsum()

我认为您实际上不希望根据结果重新合并数据框?

我希望这会有所帮助。另外,这是我的第一个答案,希望这个网站的格式和其他要求都可以。