【问题标题】:Pandas get the age from a date (example: date of birth)熊猫从日期获取年龄(例如:出生日期)
【发布时间】:2023-03-05 15:36:01
【问题描述】:

如何计算一个人的年龄(基于 dob 列)并使用新值向数据框中添加一列?

数据框如下所示:

    lname      fname     dob
0    DOE       LAURIE    03011979
1    BOURNE    JASON     06111978
2    GRINCH    XMAS      12131988
3    DOE       JOHN      11121986

我尝试了以下操作:

now = datetime.now()
df1['age'] = now - df1['dob']

但是,收到以下错误:

TypeError: 不支持的操作数类型 -: 'datetime.datetime' 和 'str'

【问题讨论】:

    标签: python pandas


    【解决方案1】:

    首先想到的是你的年龄是两位数,在这个时代这不是一个很好的选择。无论如何,我将假设像05 这样的所有年份实际上都是1905。这可能不正确(!),但提出正确的规则很大程度上取决于您的数据。

    from datetime import date
    
    def age(date1, date2):
        naive_yrs = date2.year - date1.year
        if date1.replace(year=date2.year) > date2:
            correction = -1
        else:
            correction = 0
        return naive_yrs + correction
    
    df1['age'] = df1['dob'].map(lambda x: age(date(int('19' + x[-2:]), int(x[:2]), int(x[2:-2])), date.today()))
    

    【讨论】:

    • unutbu 的答案肯定会比我的更快,因为它使用了我懒得学习的 numpy 日期魔法。
    【解决方案2】:
    import datetime as DT
    import io
    import numpy as np
    import pandas as pd
    
    pd.options.mode.chained_assignment = 'warn'
    
    content = '''     ssno        lname         fname    pos_title             ser  gender  dob 
    0    23456789    PLILEY     JODY        BUDG ANAL             0560  F      031871 
    1    987654321   NOEL       HEATHER     PRTG SRVCS SPECLST    1654  F      120852
    2    234567891   SONJU      LAURIE      SUPVY CONTR SPECLST   1102  F      010999
    3    345678912   MANNING    CYNTHIA     SOC SCNTST            0101  F      081692
    4    456789123   NAUERTZ    ELIZABETH   OFF AUTOMATION ASST   0326  F      031387'''
    
    df = pd.read_csv(io.StringIO(content), sep='\s{2,}')
    df['dob'] = df['dob'].apply('{:06}'.format)
    
    now = pd.Timestamp('now')
    df['dob'] = pd.to_datetime(df['dob'], format='%m%d%y')    # 1
    df['dob'] = df['dob'].where(df['dob'] < now, df['dob'] -  np.timedelta64(100, 'Y'))   # 2
    df['age'] = (now - df['dob']).astype('<m8[Y]')    # 3
    print(df)
    

    产量

            ssno    lname      fname            pos_title   ser gender  \
    0   23456789   PLILEY       JODY            BUDG ANAL   560      F   
    1  987654321     NOEL    HEATHER   PRTG SRVCS SPECLST  1654      F   
    2  234567891    SONJU     LAURIE  SUPVY CONTR SPECLST  1102      F   
    3  345678912  MANNING    CYNTHIA           SOC SCNTST   101      F   
    4  456789123  NAUERTZ  ELIZABETH  OFF AUTOMATION ASST   326      F   
    
                      dob  age  
    0 1971-03-18 00:00:00   43  
    1 1952-12-08 18:00:00   61  
    2 1999-01-09 00:00:00   15  
    3 1992-08-16 00:00:00   22  
    4 1987-03-13 00:00:00   27  
    

    1. 您的dob 列当前似乎是字符串。第一的, 使用pd.to_datetime 将它们转换为Timestamps
    2. '%m%d%y' 格式将最后两位数字转换为年份,但 不幸的是,假设52 表示 2052。因为那可能不是 Heather Noel 的生日,让我们从dob 中减去 100 年 只要dob 大于now。您可能希望在 df['dob'] &lt; now 条件下将 now 减去几年,因为 101 岁的工人比 1 岁的工人更有可能...
    3. 你可以从now中减去dob得到timedelta64[ns]。到 将其转换为年,使用 astype('&lt;m8[Y]')astype('timedelta64[Y]')

    【讨论】:

    • 在 .py 文件中运行时,我从上面的代码中收到以下错误。这是什么意思 SettingWithCopyWarning: 试图在 DataFrame 的切片副本上设置一个值。尝试使用 .loc[row_index,col_indexer] = value 代替 df1['dob'] = pd.to_datetime(df1['dob'], format='%m%d%y') c:\users\davidl~1\ appdata\local\temp\1\tmpxt4mqz.py:37:尝试使用 .loc[row_index,col_indexer] = value 代替 df1['dob'] = df1['dob'].where(df1['dob']
    • 该警告不是错误,而是代码可能分配给数据副本而不是DataFrame中的原始数据的警告。请参阅 this answerthe docs。我认为在上述代码的上下文中这是一个误报,但我不确定你为什么会看到警告,因为当我运行上面的代码时,我没有看到任何警告。当你运行上面的代码时,你看到警告了吗?
    • 对不起,上面的代码出现 ValueError。
    • 当我在你发布的 CSV 数据上运行你的代码时,我得到了正确的结果,没有错误。
    • 我没有 Python2 和 pandas 来测试这个了,但如果我没记错的话,read_tableread_csv 都需要 BytesIO 并且如果通过 @987654343 会引发一些错误@.
    【解决方案3】:

    我找到了更简单的解决方案:

    import pandas as pd
    from datetime import datetime
    from datetime import date
    
    d = {'col0': [1, 2, 6], 
         'col1': [3, 8, 3], 
         'col2': ['17.02.1979', '11.11.1993', '01.08.1961']}
    
    df = pd.DataFrame(data=d)
    
    def calculate_age(born):
        born = datetime.strptime(born, "%d.%m.%Y").date()
        today = date.today()
        return today.year - born.year - ((today.month, today.day) < (born.month, born.day))
    
    df['age'] = df['col6'].apply(calculate_age)
    print(df)
    

    输出:

         col0  col1  col3        age
    0       1     3  17.02.1979   39
    1       2     8  11.11.1993   24
    2       6     3  01.08.1961   57
    

    【讨论】:

    • 在这个日期不能正常工作,例如'20-03-2020'
    【解决方案4】:
    # Data setup
    df
    
        lname   fname        dob
    0     DOE  LAURIE 1979-03-01
    1  BOURNE   JASON 1978-06-11
    2  GRINCH    XMAS 1988-12-13
    3     DOE    JOHN 1986-11-12
    
    # Make sure to parse all datetime columns in advance
    df['dob'] = pd.to_datetime(df['dob'], errors='coerce')
    

    如果您只想要年龄的年份部分,请使用@unutbu's solution。 . .

    now = pd.to_datetime('now')
    now
    # Timestamp('2019-04-14 00:00:43.105892')
    
    (now - df['dob']).astype('<m8[Y]') 
    
    0    40.0
    1    40.0
    2    30.0
    3    32.0
    Name: dob, dtype: float64
    

    另一种选择是减去年份部分并使用

    (now.year - df['dob'].dt.year) - ((now.month - df['dob'].dt.month) < 0)
    
    0    40
    1    40
    2    30
    3    32
    Name: dob, dtype: int64
    

    如果您想要(几乎)精确的年龄(包括小数部分),请查询 total_seconds 并除以。

    (now - df['dob']).dt.total_seconds() / (60*60*24*365.25)
    
    0    40.120446
    1    40.840501
    2    30.332630
    3    32.418872
    Name: dob, dtype: float64
    

    【讨论】:

      【解决方案5】:

      下面的解决方案怎么样:

      import datetime as dt
      import numpy as np
      import pandas as pd
      from dateutil.relativedelta import relativedelta
      
      df1['age'] = [relativedelta(pd.to_datetime('now'), d).years for d in df1['dob']]
      

      【讨论】:

        【解决方案6】:

        当您尝试从出生日期列中查找当前年份的年龄时,请使用这一行

        import pandas as pd
        
        df["dob"] = pd.to_datetime(data["dob"])
        
        df["age"] = df["dob"].apply(lambda x : (pd.datetime.now().year - x.year))
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2012-04-17
          • 2021-11-09
          • 1970-01-01
          • 2018-12-31
          • 2020-12-29
          • 1970-01-01
          • 2022-11-16
          相关资源
          最近更新 更多