合并列并删除重复与Pandas

时间:2017-03-29 13:37:01

标签: python pandas merge duplicates

我需要合并相似的列并删除重复项(具有相同日期的条目)。数据框:

     Albumin  C-reactive protein    CRP  Ferritin  Haemoglobin     Hb  Iron  Nancy Index  Plasma  Platelets  Transferrin saturation %  Transferrin saturations  UCEIS (0 to 8)    WCC  White Cell Count           test_date
0        NaN                 NaN    NaN       NaN          NaN    NaN   NaN          NaN     NaN        NaN                       NaN                      NaN             NaN    NaN             12.35 2016-04-17 23:00:00              
1        NaN                 NaN    NaN       NaN        133.0    NaN   NaN          NaN     NaN        NaN                       NaN                      NaN             NaN    NaN               NaN 2016-04-17 23:00:00              
2        NaN                 NaN    NaN       NaN          NaN    NaN   NaN          NaN     NaN      406.0                       NaN                      NaN             NaN    NaN               NaN 2016-04-17 23:00:00              
3        NaN                 NaN    NaN       NaN          NaN    NaN   NaN          NaN     NaN      406.0                       NaN                      NaN             NaN    NaN               NaN 2016-04-17 23:00:00              
4        NaN                32.2    NaN       NaN          NaN    NaN   NaN          NaN     NaN        NaN                       NaN                      NaN             NaN    NaN               NaN 2016-04-17 23:00:00             
5       36.0                 NaN    NaN       NaN          NaN    NaN   NaN          NaN     NaN        NaN                       NaN                      NaN             NaN    NaN               NaN 2016-04-17 23:00:00              
6        NaN                 NaN    NaN      99.7          NaN    NaN   NaN          NaN     NaN        NaN                       NaN                      NaN             NaN    NaN               NaN 2016-04-17 23:00:00              
7        NaN                 NaN    NaN       NaN          NaN    NaN   NaN          NaN     NaN        NaN                      25.0                      NaN             NaN    NaN               NaN 2016-04-17 23:00:00              
12      36.0                 NaN   32.2      99.7          NaN  133.0   NaN          NaN     NaN      406.0                       NaN                     25.0             NaN  12.35               NaN 2016-04-17 23:00:00              
14       NaN                 NaN    NaN       NaN          NaN    NaN   NaN          NaN     NaN        NaN                       NaN                      NaN             7.0    NaN               NaN 2016-04-25 23:00:00              
79      34.0                 NaN    5.4      55.9          NaN  133.0   NaN          NaN     NaN      372.0                       NaN                     28.0             NaN   7.99               NaN 2016-06-12 23:00:00              

我需要得到:

     Albumin    CRP  Ferritin     Hb  Nancy Index  Plasma  Platelets  Transferrin saturations  UCEIS (0 to 8)    WCC           test_date
12      36.0   32.2      99.7  133.0          NaN     NaN      406.0                     25.0             NaN  12.35 2016-04-17 23:00:00
14       NaN    NaN       NaN    NaN          NaN     NaN        NaN                      NaN             7.0    NaN 2016-04-25 23:00:00
79      34.0    5.4      55.9  133.0          NaN     NaN      372.0                     28.0             NaN   7.99 2016-06-12 23:00:00

因此,色谱柱'C反应蛋白'应与'CRP','血红蛋白'与'Hb','转铁蛋白饱和度%'与'转铁蛋白饱和度'合并。

我可以使用 .drop_duplicates()轻松删除重复项,但诀窍不仅是删除具有相同日期的行,而且还要确保同一列中的值是重复的。例如,行'4'处的'C-反应蛋白'具有与'12'行中'CRP'相同的值,此外,它们都具有相同的输入日期。鉴于这一切,我需要只有'CRP'列,其值为32.2,日期为'2016-04-17'(加上其他唯一列)。

修改

有些条目实际上是重复的(完全相同,由于系统故障),例如(最后三行,2016-06-20,索引'803'和'122')。下面的解决方案是否能够删除这些相同的行?

P.S。感谢复制但不完全相同的条目的惊人和通用的解决方案。

     Albumin  C-reactive protein  CRP  Ferritin  Haemoglobin     Hb  Iron  Nancy Index  Plasma  Platelets  Transferrin saturation %  Transferrin saturations  UCEIS (0 to 8)   WCC  White Cell Count          setName           test_date
735     39.0                 NaN  0.4      52.0          NaN  144.0   NaN          NaN     NaN      197.0                       NaN                     25.0             NaN  4.88               NaN           Bloods 2016-05-31 23:00:00
803     40.0                 NaN  0.2      81.0          NaN  147.0   NaN          NaN     NaN      234.0                       NaN                     35.0             NaN  8.47               NaN           Bloods 2016-06-20 23:00:00
347      NaN                 NaN  NaN       NaN          NaN    NaN   NaN          NaN     1.0        NaN                       NaN                      NaN             NaN   NaN               NaN  Research Bloods 2016-06-20 23:00:00
122     40.0                 NaN  0.2      81.9          NaN  147.0   NaN          NaN     NaN      234.0                       NaN                     35.0             NaN  8.47               NaN           Bloods 2016-06-20 23:00:00

2 个答案:

答案 0 :(得分:2)

我认为您需要rename dictd = {'C-reactive protein':'CRP', 'Hemoglobin':'Hb', 'Transferrin saturation %':'Transferrin saturations'} df = df.groupby('test_date').max().rename(columns=d).groupby(axis=1, level=0).max() print (df) Albumin CRP Ferritin Haemoglobin Hb Iron \ test_date 2016-04-17 23:00:00 36.0 32.2 99.7 133.0 133.0 NaN 2016-04-25 23:00:00 NaN NaN NaN NaN NaN NaN 2016-06-12 23:00:00 34.0 5.4 55.9 NaN 133.0 NaN Nancy Index Plasma Platelets Transferrin saturations \ test_date 2016-04-17 23:00:00 NaN NaN 406.0 25.0 2016-04-25 23:00:00 NaN NaN NaN NaN 2016-06-12 23:00:00 NaN NaN 372.0 28.0 UCEIS (0 to 8) WCC White Cell Count test_date 2016-04-17 23:00:00 NaN 12.35 12.35 2016-04-25 23:00:00 7.0 NaN NaN 2016-06-12 23:00:00 NaN 7.99 NaN

DataFrame

更一般的解决方案是groupby重新整形,删除重复项,然后再创建d = {'C-reactive protein':'CRP', 'Hemoglobin':'Hb', 'Transferrin saturation %':'Transferrin saturations'} df = df.rename(columns=d).groupby(axis=1, level=0).max() df = pd.melt(df, id_vars='test_date').dropna(subset=['value']).drop_duplicates() df = df.groupby(['test_date','variable'])['value'] \ .apply(lambda x: pd.Series(x.values)) \ .unstack(1) \ .reset_index(level=1, drop=True) \ .reset_index() \ .rename_axis(None,axis=1) print (df) test_date Albumin CRP Ferritin Hb Platelets \ 0 2016-04-17 23:00:00 1000.0 32.2 99.7 1000.0 406.0 1 2016-04-17 23:00:00 36.0 NaN NaN 133.0 NaN 2 2016-04-25 23:00:00 NaN NaN NaN NaN NaN 3 2016-06-12 23:00:00 34.0 5.4 55.9 133.0 372.0 Transferrin saturations UCEIS (0 to 8) WCC White Cell Count 0 25.0 NaN 12.35 12.35 1 NaN NaN NaN NaN 2 NaN 7.0 NaN NaN 3 28.0 NaN 7.99 NaN

 public class Emp
{

    public int Id { get; set; }
    public string Name { get; set; }
    public int Amount { get; set; }

public IList<Emp> GetMasterDetails()
    {
        IList<Emp> masterList = new List<Emp>            
        {
            new Emp { Id = 952491, Name = "Z005HY11", Amount = 500 },
            new Emp { Id = 952491, Name = "Z005H717", Amount = 500 },
            new Emp { Id = 1191676, Name = "Z005H717", Amount = 400 }                
        };
        return masterList;
    }

    public IList<Emp> GetNonMasterDetails()
    {
        IList<Emp> nonMasterList = new List<Emp>            
        {
            new Emp { Id = 952491, Name = "Z005H717", Amount = 500 },
            new Emp { Id = 1191676, Name = "Z005H717", Amount = 500 },
            new Emp { Id = 1227997, Name = "Z005HY11", Amount = 400 }
        };
        return nonMasterList;
    }


}

 Emp obj = new Emp();
        IList<Emp> masterList = obj.GetMasterDetails();
        IList<Emp> nonMasterList = obj.GetNonMasterDetails();
        var first = masterList.Where(p => !nonMasterList.Any(l => p.Id == l.Id || p.Name ==l.Name)).ToList();
        var second = nonMasterList.Where(p => !masterList.Any(l => p.Id == l.Id || p.Name == l.Name)).ToList();

答案 1 :(得分:1)

@jezrael所说的是,如果您遇到以下情况:

     Albumin  C-reactive protein    CRP  test_date
0        NaN                 NaN    32       2016-04-17 23:00:00              
1        NaN                 8.0    NaN      2016-04-17 23:00:00

然后他的方法将删除8.0读数并仅保留32(这是因为他分两步(或3?),在这一行:df = df.groupby('test_date').max().rename(columns=d).groupby(axis=1, level=0).max()

df = df.groupby('test_date').max() # selects max of each column 
                                   # while collapsing 'test_date'

对于我的截断示例,它将给出:

         Albumin  C-reactive protein    CRP  test_date
0        NaN                 8.0    32       2016-04-17 23:00:00

然后重命名.rename(columns=d)给予:

         Albumin  CRP    CRP  test_date
0        NaN      8.0    32   2016-04-17 23:00:00

然后.groupby(axis=1, level=0).max()沿着行(而不是向下列)分组,它们给出了:

         Albumin  CRP  test_date
0        NaN      32   2016-04-17 23:00:00

这是您丢失数据的最大风险。

替代

我会先将原始数据分成两个帧

df1 = df[["C-reactive protein","Haemoglobin", ...]]
df2 = df[["CRP", "Hb"]]

# then rename

df2 = df2.rename(columns={"CRP":"C-reactive protein", "Hb":"Haemoglobin", ...})

# use concat to stack them on one another

df3 = pd.concat([df1, df2]) # i've run out of names

df3 = df3.drop_duplicates() # perhaps also drop NAs?

但只有在同一天有同一个测试的多个非重复条目时才需要这样做。