2014-11-06 65 views
4

我如何计算一个人的年龄(基于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'] 

但是,收到以下错误:

类型错误:不支持的操作类型为 - :'datetime.datetime'和'str'

回答

13
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_table(io.BytesIO(content), sep='\s{2,}') 
df['dob'] = df['dob'].apply('{:06}'.format) 

now = pd.Timestamp(DT.datetime.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因为这可能不是 希瑟诺埃尔的birthyear,让我们减去百年从dob 每当dobnow更大。您可能希望在条件df['dob'] < now减去几年now,因为它可能会稍微更可能有A 101岁的工人超过1岁的工人...
  3. 您可以从now减去dob获得timedelta64[ns]。若要将 转换为年,请使用astype('<m8[Y]')astype('timedelta64[Y]')
+0

在.py文件中运行时,出现以上代码中的以下错误。这是什么意思 SettingWithCopyWarning:一个值试图在DataFrame的一个切片副本上设置。 尝试使用.loc [row_index,col_indexer] =值代替 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']。其中(df1 [ dob'] david 2014-11-08 00:00:31

+0

该警告不是错误,但它是警告,代码*可能*被分配给数据而不是DataFrame中的原始数据。见[这个答案](http://stackoverflow.com/a/21463854/190597)和[文档](http://pandas.pydata.org/pandas-docs/dev/indexing.html#why-does-在-赋值时,使用链索引失效)。我认为这是上述代码中的虚惊,但我不确定为什么你会看到警告,因为当我运行上面的代码时,我看不到任何警告。当你运行上面的代码时,你看到警告了吗? – unutbu 2014-11-08 01:01:34

+0

对不起,我得到了上面代码的ValueError。 – david 2014-11-08 17:12:20

2

首先想到的是,你的岁月是两位数字,在这个时代这是一个不太好的选择。无论如何,我要假设像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())) 
+0

unutbu的答案一定会比我的答案快,因为它使用了我没有打扰学习的numpy日期磁贴。 – 2014-11-06 21:20:26