基于 pandas.DataFrame 其他特征构建一个函数来衍生新列哈希值。

3

我有一个包含医疗保险信息的pandas DataFrame,包括姓名、地址、出生日期等。

我编写了一个针对单行数据的函数:

    
def make_hash(partner: str, df: pd.DataFrame) -> str:
  """
  For Partner A, df (pd.DataFrame) must contain:
    health_plan_id: str 
    date_of_birth: dt.Timestamp
    first_name: str
  Other partners will have different feature names for hash input and require a new elif block, below.
  """
  if partner == 'Partner A':
    health_plan_id = str(df.loc[:,'ID'].item()).strip().encode()
    date_of_birth = str(dt.date(df.loc[:,'Date of Birth'].item())).encode()
    first_name = str(df.loc[:,'Member Name'].item()).split(",")[1].strip().encode()

    hash_input = health_plan_id + date_of_birth + first_name
    h = hashlib.sha256(string=hash_input).hexdigest()
    print(f"Input: {hash_input}. Result: {h}.\n")
    return h
  else:
    print("No hashing strategy defined for that partner.")

输出结果(PII值已更改):

make_hash(partner="Partner A", df=df)

Input: b'B88845204081984-06-11MickeyMouse'. Result: 4d578e1acd7c670193448b84362095383cc13a24249f6c8c92816d79ec3c48d8.
Out[60]: '4d578e1acd7c670193448b84362095383cc13a24249f6c8c92816d79ec3c48d8'

理想情况下,它应该生成一个新列 (ID),并将 '4d578e1acd...' 值添加到其中。如果我尝试在具有> 1行的 DataFrame 上使用此函数,则会出现错误:

ValueError: can only convert an array of size 1 to a Python scalar

我希望该函数可以在lambda中使用,能够处理具有任意行数的pd.DataFrame,并期望输出为另一个pd.DataFrame,其行数相同,但特征数增加1(新的ID列)。

这可行吗?我看到了几个类似的问题,但我不确定是否可以在整个pd.Series上执行此操作,因为上述函数将具有一些依赖于partner值的数据清理步骤...

4个回答

2

您需要进行一些小的更改,才能使用lambda函数。

function make_partnerhash(datarow, partner : str):

   h = 'a_default_value_like_Partner_has_no_hashing_strategy'

   if partner == "Partner A":
      id = datarow['ID']
      ... calculate hash etc ...
   return h

你可以像这样从 Lambda 中调用该函数:

df['HASH_COLUMN_NAME'] = df.apply(lambda x: make_parnerhash(x, 'Partner A'), axis=1)

因为你对大部分列进行了encode()和strip()操作,所以可以将需要的每个字段打包到一个列表中,在列表推导式中对字段进行encode()和strip()操作,最后使用str.join()方法将所有值连接起来,就像这样:

def make_partnerhash(row, partner: str):
    h = 'NO_HASH_DEFINED_FOR_THIS_PARTNER'
    if partner == 'Partner A':
        values_to_hash = [row['ID'],
                          pd.to_datetime(row['Date of Birth']),
                          row['Member Name'].split(",")[1]]
        
        hash_input = "".join( [ str(x).strip() for x in values_to_hash]).encode()
        h = hashlib.sha256(hash_input).hexdigest()
    
    return h


0

补充@Iñigo的答案,当函数的输出取决于外部状态时,我更喜欢创建一个可调用类。

class CallableHash:
    def __init__(self, partner):
        self.partner = partner
    
    def __call__(self, row):
        h = 'NO_HASH_DEFINED_FOR_THIS_PARTNER'
        if self.partner == 'Partner A':
            values_to_hash = [row['ID'],
                            pd.to_datetime(row['Date of Birth']),
                            row['Member Name'].split(",")[1]]
            
            hash_input = "".join( [ str(x).strip() for x in values_to_hash]).encode()
            h = hashlib.sha256(hash_input).hexdigest()
        # Add whatever you want to this function
        return h

你可以在类似于你之前使用的函数中使用这个

def make_hash(partner: str, df: pd.DataFrame) -> pd.DataFrame:
    new_df = df # Or copy.deepcopy it if you want a new df
    new_df["ID"] = new_df.apply(CallableHash(partner), axis=1)
    return new_df

0

我建议为每个合作伙伴创建一个单独的函数。
df更改为row,它适用于row
我没有改变处理方式。

def make_hash_Partner_A(row) -> str:
    health_plan_id = str(row['ID']).strip().encode()
    # date_of_birth = str(dt.date(row['Date of Birth'])).encode()
    # May be an error with `dt.date`. Replaced to `pd.datetime`
    date_of_birth = str(pd.to_datetime(row['Date of Birth'])).encode() 
    first_name = str(row['Member Name']).split(",")[1].strip().encode()

    hash_input = health_plan_id + date_of_birth + first_name
    h = hashlib.sha256(string=hash_input).hexdigest()
    return h

df['hash_Partner_A'] = df.apply(make_hash_Partner_A, axis=1)

0
考虑使用 Series.apply,避免使用Series.item()将 Series 中的字符串传入期望标量值的 hashlib.sha256。下面的操作将转换为在 Series 上运行而不是标量,因此需要多次调用Series.str
if partner == 'Partner A': 
    # CREATE PANDAS SERIES OBJECTS OR AS ADDED COLUMNS df[...] =
    health_plan_id = df['ID'].astype('str').str.strip().str.encode()
    date_of_birth = pd.to_datetime(df['Date of Birth']).astype('str').str.encode() 
    first_name = df['Member Name'].astype('str').str.split(",").str[1].str.strip().str.encode() 
    hash_input = health_plan_id + date_of_birth + first_name

    # ASSIGN NEW COLUMN OF ALL ROWS
    df['ID'] = hash_input.apply(lambda h: hashlib.sha256(string=h).hexdigest())
    return df
else:
    print("No hashing strategy defined for that partner.")

我不确定成员名称行中的.split(",").str[1]是否完全正确。应该是这样的:.split(",", 1, expand=True)[1] - suvayu

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