使用pandas/python对MultiIndex数据框应用函数

6
我有一个DataFrame,我希望对它进行一些日期范围计算。我想选择数据框中的行,其中唯一个人(来自sample_date)的样本之间的日期差小于8周,并保留最早的日期行(即第一个样本)。
以下是一个示例数据集。实际数据集可能超过200,000条记录。
labno   name    sex dob         id     location  sample_date
1       John A  M   12/07/1969  12345  A         12/05/2112
2       John B  M   10/01/1964  54321  B         6/12/2010
3       James   M   30/08/1958  87878  A         30/04/2012
4       James   M   30/08/1958  45454  B         29/04/2012
5       Peter   M   12/05/1935  33322  C         15/07/2011
6       John A  M   12/07/1969  12345  A         14/05/2012
7       Peter   M   12/05/1935  33322  A         23/03/2011
8       Jack    M   5/12/1921   65655  B         15/08/2011
9       Jill    F   6/08/1986   65459  A         16/02/2012
10      Julie   F   4/03/1992   41211  C         15/09/2011
11      Angela  F   1/10/1977   12345  A         23/10/2006
12      Mark A  M   1/06/1955   56465  C         4/04/2011
13      Mark A  M   1/06/1955   45456  C         3/04/2011
14      Mark B  M   9/12/1984   55544  A         13/09/2012
15      Mark B  M   9/12/1984   55544  A         1/01/2012

唯一的个体就是具有相同姓名和出生日期的人。例如,约翰A、詹姆斯、马克A和马克B都是唯一的人。但是,马克A具有不同的ID值。

通常我使用R进行此过程,并基于姓名/出生日期组合生成数据框列表,并按样本日期对每个数据框进行排序。然后,我会使用列表应用函数来确定每个数据框内第一个和最后一个索引之间的日期差异,以确定是否应返回最旧的日期,如果该日期距最近日期少于8周。这需要很长时间。

我希望能够得到一些关于如何在Python / Pandas中尝试此操作的指导。我首先通过name/dob/id创建了一个MultiIndex。外观与我想要的相似。我需要做的是尝试应用一些我在R中使用的函数来选择出我需要的行。我尝试了使用df.xs()进行选择,但没有取得太多进展。

这里是一个数据字典,可以轻松地加载到Pandas中(尽管列顺序不同)。

{'dob': {0: '1969年12月7日', 1: '1964年10月1日', 2: '1958年8月30日', 3: '1958年8月30日', 4: '1935年5月12日', 5: '1969年12月7日', 6: '1935年5月12日', 7: '1921年5月12日', 8: '1986年6月8日', 9: '1992年4月3日', 10: '1977年1月10日', 11: '1955年1月6日', 12: '1955年1月6日', 13: '1984年9月12日', 14: '1984年9月12日'}, 'id': {0: 12345, 1: 54321, 2: 87878, 3: 45454, 4: 33322, 5: 12345, 6: 33322, 7: 65655, 8: 65459, 9: 41211, 10: 12345, 11: 56465, 12: 45456, 13: 55544, 14: 55544}, 'labno': {0: 1, 1: 2, 2: 3, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15}, 'location': {0: 'A', 1: 'B', 2: 'A', 3: 'B', 4: 'C', 5: 'A', 6: 'A', 7: 'B', 8: 'A', 9: 'C', 10: 'A', 11: 'C', 12: 'C', 13: 'A', 14: 'A'}, 'name': {0: '约翰·A', 1: '约翰·B', 2: '詹姆斯', 3: '詹姆斯', 4: '彼得', 5: '约翰·A', 6: '彼得', 7: '杰克', 8: '吉尔', 9: '朱莉', 10: '安吉拉', 11: '马克·A', 12: '马克·A', 13: '马克·B', 14: '马克·B'}, 'sample_date': {0: '2112年12月5日', 1: '2010年6月12日', 2: '2012年4月30日', 3: '2012年4月29日', 4: '2011年7月15日', 5: '2012年5月14日', 6: '2011年3月23日', 7: '2011年8月15日', 8: '2012年2月16日', 9: '2011年9月15日', 10: '2006年10月23日', 11: '2011年4月4日', 12: '2011年3月4日', 13: '2012年9月13日', 14: '2012年1月1日'}, 'sex': {0: '男', 1: '男', 2: '男', 3: '男', 4: '男', 5: '男', 6: '男', 7: '男', 8: '女', 9: '女', 10: '女', 11: '男', 12: '男', 13: '男', 14: '男'}}

假设Mark A有六个样本。前三个样本相隔六周,然后间隔四个月,接着后三个样本也相隔六周。你想保留哪些行呢?(也就是说,我不确定“样本日期之间的差异”的范围。) - DSM
很好的观点 @DSM。如果 Mark A 的最旧样本和最近的一组样本之间的日期差异超过8周,我想把其他 Mark A 组视为新的样本组。也就是说,如果两个样本之间的日期差异 > 8周,则将每个样本集视为独立的。 - John
1个回答

6
我认为您可能在寻找的是:
def differ(df):
    delta = df.sample_date.diff().abs()  # only care about magnitude
    cond = delta.notnull() & (delta < np.timedelta64(8, 'W'))
    return df[cond].max()

delta = df.groupby(['dob', 'name']).apply(differ)

根据您是否想要保留没有超过1个样本的人,您可以调用 delta.dropna(how='all') 来删除他们。

请注意,我认为您需要 numpy >= 1.7 才能使 timedelta64 的比较正常工作,因为在 numpy < 1.7 中存在大量与 timedelta64/datetime64 相关的问题。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接