根据条件更改数字中的数字

Changing digits in numbers based on a conditions

在挪威,我们有一种叫做 D 和 S 号码的东西。这些是修改出生日期或月份的国民身份证号码。

D-number
[d+4]dmmyy

S-number
dd[m+5]myy

我有一个包含日期的列,其中一些是正常的 (ddmmyy),一些是格式化为 D 或 S 数字。也缺少前导零。

df = pd.DataFrame({'dates': [241290,  #24.12.90
                             710586,  #31.05.86
                             105299,  #10.02.99
                              56187]  #05.11.87
                  })

    dates
0  241290
1  710586
2  105299
3   56187

我编写了这个函数来添加前导零并转换日期,但是这个解决方案感觉不是很好

def func(s):
    s = s.astype(str)
    res = []
    for index, value in s.items():
        
        # Make sure all dates have 6 digits (add leading zero)
        if len(value) == 5:
            value = ('0' + value)
        
        # Convert S- and D-dates to regular dates
        if int(value[0]) > 3:
            
            # substract 4 from the first digit
            res.append(str(int(value[0]) - 4) + value[1:])
        
        elif int(value[2]) > 1:
            # subtract 5 from the third digit
            res.append(value[:2] + str(int(value[2]) - 5) + value[3:])
        
        else:
            res.append(value)
            
    return pd.Series(res)

是否有更流畅、更快速的方法来实现相同的结果?

您可以将 Series 保留为整数,直到最后一步。以下方法的缺点是偏移量与规格不符,可能需要更多的脑力才能理解:

def func2(s):
    # In mathematical operations, digits are counted from right
    # so "first digit" becomes sixth and "third digit" becomes
    # fourth in a 6-digit number
    delta = np.select(
        [s // 10**5 % 10 > 3, s // 10**3 % 10 > 1],
        [4 *  10**5         , 5 *  10**3         ],
        0
    )
    return (s - delta).astype('str').str.pad(6, fillchar='0')

通过用 0 填充来标准化日期,然后分解为 3 列两位数(日、月、年)。应用您的规则并将列合并为 DateTimeIndex:

# Suggested by @HenryEcker
# Changed: .pad(6, fillchar='0')  to  .zfill(6)
dates = df['dates'].astype(str).str.zfill(6).str.findall('(\d{2})') \
                   .apply(pd.Series).astype(int) \
                   .rename(columns={0: 'day', 1: 'month', 2: 'year'}) \
                   .agg({'day': lambda d: d if d <= 31 else d - 40,
                         'month': lambda m: m if m <= 12 else m - 50,
                         'year': lambda y: 1900 + y})

df['dates2'] = pd.to_datetime(dates)

输出:

>>> df
    dates     dates2
0  241290 1990-12-24
1  710586 1986-05-31
2  105299 1999-02-10
3   56187 1987-11-05

>>> dates
   day  month  year
0   24     12  1990
1   31      5  1986
2   10      2  1999
3    5     11  1987