import logging import re import numpy as np from .enrichment import Enrichment component_logger = logging.getLogger().getChild("enrichment.enrich_name") class EnrichName(Enrichment): source_attribute_ids = [1, 2, 5] # userEmail # userFirstName # userFullName result_attribute_ids = [49] # enrUserFirstName data_gathering_rule = "strict" def __init__(self, collection_id: int, schema: str, user_id: str, default_value: str = "unknown", **kwargs): super().__init__(collection_id, schema, user_id, default_value) def _run(self): """ Main enrichment method """ source_df = self.available_data["source"] """ Attempts to parse userFirstName field""" if len(source_df) > 1000 and hasattr(source_df, "parallel_applymap"): source_df["enrUserName1"] = source_df[["2"]].parallel_applymap(self._normalize_name) else: source_df["enrUserName1"] = source_df[["2"]].applymap(self._normalize_name) """ Attempts to parse userFullName field for remaining null values (or all values when doing parallel) """ condition = source_df["enrUserName1"].isna() & ~source_df["5"].isna() if len(source_df) > 1000 and hasattr(source_df, "parallel_applymap"): source_df["enrUserName2"] = source_df[["5"]].parallel_applymap(self._normalize_name) else: source_df["enrUserName2"] = source_df[condition][["5"]].applymap(self._normalize_name) """ Attempts to parse userEmail field for remaining null values (or all values when doing parallel) """ condition = source_df["enrUserName1"].isna() & source_df["enrUserName2"].isna() if len(source_df) > 1000 and hasattr(source_df, "parallel_applymap"): source_df["enrUserName3"] = source_df[["1"]].parallel_applymap(self._parse_email) else: source_df["enrUserName3"] = source_df[condition][["1"]].applymap(self._parse_email) """ Gets the first not null value from the columns""" source_df["enrUserFirstName"] = ( source_df[["enrUserName1", "enrUserName2", "enrUserName3"]].fillna(method="bfill", axis=1,).iloc[:, 0] ) source_df["enrUserFirstName"].fillna(value=self.default_value, inplace=True) source_df = source_df[["fan_id", "enrUserFirstName"]] self.result_df = source_df self._deduplicate_result_data() @staticmethod def _normalize_name(first_name): """ Normalizes first name """ if first_name == np.nan or str(first_name) == "nan" or first_name is None: return np.nan try: # component_logger.info(f"======== {first_name}") if "," in first_name: """ We assume that in case comma-separated names, second part is firstname. Also strip leading and trailing spaces so next if won't conflict with our logic """ first_name_split = first_name.split(",") first_name = first_name_split[1].strip() # It can happen (like in ticketing demo set) the 2nd part is empty altogether.. then take first part if first_name == "": first_name = first_name_split[0].strip() if " " in first_name: # We normalize and take only the first part when there are 2 parts in a firstname first_name = first_name.split(" ")[0] # How should we handle single letters # if len(normalized_name) == 1: # normalized_name = None # Make it lower case and remove trailing and leading spaces normalized_name = first_name.lower().strip() # Remove all symbols and numbers from name normalized_name = re.sub(r"\W+|[0-9]", "", normalized_name) return normalized_name except Exception as e: return np.nan def _parse_email(self, email): if email: regex = r"(.*?)\..*@" name = re.search(regex, email) if name: name = name.group(1) else: name = "" if len(name) > 1: return self._normalize_name(name) return np.nan