在Python3中将出生日期数据框拆分为3个不同的列

在Python3中将出生日期数据框拆分为3个不同的列,python,regex,python-3.x,pandas,Python,Regex,Python 3.x,Pandas,有一个包含3种不同类型出生日期的数据框: df_dob=pd.DataFrame( [ {'date':'DOB 19 Jun 1951'}, {'date':'DOB Jun 1951'}, {'date':'DOB 1951'} ] ) 我正试图编写一个像上面这样的函数,以便将上面的数据帧转换为 3列: 第一栏可以容纳1951-06-19 00:00:00 第二栏可以容纳1951-06年 第三纵队可以容纳1951人 期望输出: df_dob['date'].apply(transform_

有一个包含3种不同类型出生日期的数据框:

df_dob=pd.DataFrame(
[
{'date':'DOB 19 Jun 1951'},
{'date':'DOB Jun 1951'},
{'date':'DOB 1951'}
]
)
我正试图编写一个像上面这样的函数,以便将上面的数据帧转换为

3列:

第一栏可以容纳1951-06-19 00:00:00

第二栏可以容纳1951-06年

第三纵队可以容纳1951人

期望输出:

df_dob['date'].apply(transform_date) 
以下是我的代码,有两个问题:

(1) 正则表达式无法处理“DOB Jun 1951”,因此返回“TypeError:type'NoneType'的对象没有len()

如本文所述:

(2) 如果我们从输入中删除“DOB Jun 1951”,我们将得到以下错误

57 df_dob[“日期”]。应用(转换日期)

“TypeError:无效的类型升级”

不知是否有更好的解决办法?谢谢

1951-06-19 00:00:00, NaN, NaN
NaN,1951-06,NaN
NaN,NaN,1951
重新导入
从datetime导入datetime,timedelta
def转换_日期(x):
如果len(x.split(“;”)>0:
regex=r“\bDOB((?:(?:3[01]|[12][0-9]|[0-9])[A-Za-z]+)?\d{4})\b”
#“DOB(.*)”
l=len(关于findall(regex,x.split(';')[0]))
如果l>0:
#new=re.findall('DOB(.*),x.split(';')[0])[0]

#而我认为你可以提取日期并跳过日期:

import re
from datetime import datetime, timedelta

def transform_date(x):

    if len(x.split(';')) > 0:

        regex = r"\bDOB ((?:(?:3[01]|[12][0-9]|0?[1-9]) [A-Za-z]+ )?\d{4})\b"
        #'DOB (.*)'

        l = len(re.findall(regex, x.split(';')[0]))

        if l > 0:

            # new = re.findall('DOB (.*)', x.split(';')[0])[0]



            # while l <= len(re.findall('DOB (.*)', x.split(';')[0])):

            new = re.findall(regex, x.split(';')[0])[l - 1]

            print(new)

                # print(type(new))

                # l = l+1

            if len(new) == 11:

                print(datetime.strptime(new, '%d %b %Y'))
                return pd.Series([datetime.strptime(new, '%d %b %Y'), np.nan, np.nan])

            elif len(new) == 4:

                print(datetime.strptime(new, '%Y').year)

                return pd.Series([np.nan, np.nan, datetime.strptime(new, '%Y').year])

            else:

                print(str(datetime.strptime(new, '%b %Y').year)) + '-' + str(datetime.strptime(new, '%b %Y').month)

                mmyyyy=str(datetime.strptime(new, '%b %Y').year) + '-' + str(datetime.strptime(new, '%b %Y').month)

                return pd.Series([np.nan, mmyyyy, np.nan])
pattern=r“(?P\d{2}\s[A-Za-z]{3}\s\d{4})|(?P[A-Za-z]{3}\s\d{4})|(?P\d{4})”
dates=df[“date”].str[3:][.str.extract(模式)
日期[[“date1”,“date2”]=日期[[“date1”,“date2”]]。适用(pd.to_datetime)
打印(日期)
日期1日期2日期3
0 1951-06-19纳南
1 NaT 1951-06-01南
2 NaT NaT 1951年

再次感谢您@叶亨利!如果我想保留原始日期栏,我该怎么做
dates=pd.concat(df[“date”],df[“date”].str[3:][.str.extract(pattern))
返回
TypeError:第一个参数必须是pandas对象的iterable,您传递了一个类型为“Series”的对象
我想我已经搞定了
df[[“date1”,“date2”,“date3”]=df[“date”].str[3:].str.extract(pattern,expand=True),
Hi@Henry Yik:我刚刚发现日期列不是很干净。可能有“1951年6月19日DOB;埃及POB Giza;护照1084010(埃及);替代护照19820215;圣战组织的作战和军事领导人。”在您的解决方案中,我发现模式也与护照匹配,如
ort 19820215
。想知道是否有任何方法可以避免在这里提取passort,而只提取DOB后面的字符串?谢谢您可以使用
str.split
首先按“;”进行拆分
df[“date”].str.split(;”).str[0]
应该为您提供第一个元素@Chubaka。
pattern = r"(?P<date1>\d{2}\s[A-Za-z]{3}\s\d{4})|(?P<date2>[A-Za-z]{3}\s\d{4})|(?P<date3>\d{4})"

dates = df["date"].str[3:].str.extract(pattern)
dates[["date1","date2"]] = dates[["date1","date2"]].apply(pd.to_datetime)
print (dates)

       date1      date2 date3
0 1951-06-19        NaT   NaN
1        NaT 1951-06-01   NaN
2        NaT        NaT  1951