如何根据子ID拆分数据帧

时间:2019-08-12 17:57:13

标签: python pandas

我有一个包含3列的csv文件,其中包含图像数据集。第1列名称为``ID'',其中ID代表患者ID,第2列和第3列分别代表数据集的侧面和标签。我想将此数据帧拆分为根据患者ID进行测试和训练集,在这两个集合中都不会重复患者ID。我的意思是,测试集中不会出现火车ID。使用下面的代码

# Defining a function for spliting dataframe into train and test
df_Datacopy = df_Data.copy() # copy the df

#df_Datacopy= df_Datacopy.sort_values(by=['ID'])
df_Datacopy = df_Datacopy.sample(frac=1)

train_df = df_Datacopy.sample(frac=0.80, random_state=0) # train spliting size 80%

# sorted according to ID
train_df= train_df.sort_values(by=['ID'])

# test split and by removing train index
test_df = df_Datacopy.drop(train_df.index)

# sorted according to ID
test_df= test_df.sort_values(by=['ID'])

u1 = np.unique(train_df['ID'])
u2 = np.unique(test_df['ID'])
print(set(u1).union(set(u2)))

我试图拆分测试集和训练集,但是问题是我看到测试集和训练集中都存在一些ID。如果我得到包括代码示例在内的一些帮助,这将对我有很大的帮助。

2 个答案:

答案 0 :(得分:0)

我建议使用布尔掩码过滤数据集。 如果您想分割50/50,则可能需要检查ID是偶数还是不均匀。

由于您没有提供任何建议的数据或我建议的分割条件的详细信息,所以

train_df= df[df.ID % 2 == 0]
test_df = df[df.ID % 2 != 0]

这是您想要实现的目标吗? 如果无法提供,则可能会提供有关所需结果的更多信息。

答案 1 :(得分:0)

简单的 Python 列表方法

因此,我建议为此使用简单的 Python 列表作为首选且更简单的方法。自从您开始使用 Pandas,我将提供一种使用 Pandas 方法来实现类似但可能产生更糟结果的方法。

whole_dataset_list =df_copy.to_numpy().tolist()
patientid_list =df['ID'].to_numpy().tolist()
patientid_set =list(set(patientid_list))

import random as rand
rand.shuffle(patientid_set)

#Change the numbers as to represent a 80% slice of your dataset/10/10 respectively
train_set_by_patientID = patientid_set[0:800] # 80 
val_set_by_patientID = patientid_set[800:900] # 10
test_set_by_patientID = patientid_set[1000:] # 10

拆分这些列表后,您可以使用它们来获得最终的训练/测试/验证拆分。

for i in range(len(wholeDataset_list)):
    curr_pt_id = wholeDataset_list[i]
    if(curr_pt_id in train_set_by_patientID):
        train_set.append(wholeDataset_list[i])
    elif(curr_pt_id in val_set_by_patientID):
        val_set.append(wholeDataset_list[i])
    elif(curr_pt_id in test_set_by_patientID):
        test_set.append(wholeDataset_list[i])
    else:
        raise RuntimeError("Whole dataset does not contain given i ")

最后,如果您愿意,您可以回到数据框:

train_df = pd.DataFrame(train_set, columns=df_copy.columns)
val_df = pd.DataFrame(val_set, columns=df_copy.columns)
test_df = pd.DataFrame(test_set, columns=df_copy.columns)

仅使用 Pandas 的第二个选项:

这里的 sop_uid 是唯一索引。我正在使用训练/验证/测试拆分而不是训练/测试拆分,但可以轻松更改。

dff.sort_values(by="patient_id", axis=0, inplace=True)
count_study = dff.groupby_agg(by = 'patient_id', agg='count', agg_column_name='sop_uid', new_column_name="count_instances")
df_Datacopy = dict_dff

train_df = df_Datacopy.sample(frac=0.90, weights='count_study', random_state=0) # train spliting size 90%
train_df= train_df.sort_values(by=['count_instances'], ascending = False)
# test split and by removing train index
test_df = df_Datacopy.drop(train_df.index)
# sorted according to count_study
test_df= test_df.sort_values(by=['count_instances'], ascending = False)
#Sample 
train_df = train_df.sample(frac=0.89, weights='count_study', random_state=0) # train spliting size 80%
train_df= train_df.sort_values(by=['count_instances'], ascending = False)

val_df = df_Datacopy.drop(train_df.index.append(test_df.index))