Pandas - 设置列值,基于在另一列上运行的函数

Pandas - Setting column value, based on a function that runs on another column

我到处都在尝试让它工作(数据科学的新手)。这显然是因为我不明白 Panda 的数据结构是如何工作的。

我有这个代码:

def getSearchedValue(identifier):
    full_str = anedf["Diskret data"].astype(str)
    value=""
    if full_str.str.find(identifier) <= -1:
        start_index = full_str.str.find(identifier)+len(identifier)+1
        end_index = full_str[start_index:].find("|")+start_index
        value = full_str[start_index:end_index].astype(str)
        return value

for col in anedf.columns:
    if col.count("#") > 0:
        anedf[col] = getSearchedValue(col)

我想做的是遍历我的专栏。我的数据框中有大约 260 个。如果它们包含字符 #,它应该尝试根据我的“Diskret 数据”列中的内容填充值。 “Diskret 数据”列中的数据完全混乱,但格式为 CCC#111~VALUE|DDD#222~VALUE| <- 直到没有更多的标识符 + 值。并非所有标识符都出现在每一行中,并且它们没有特定的顺序。 如果我 运行 它在常规 Python 文档中使用硬编码字符串,则该函数有效。但是对于数据框,我得到了各种错误,例如:

ValueError: The truth value of a Series is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all().

    Input In [119], in <cell line: 12>()
        12 for col in anedf.columns:
        13     if col.count("#") > 0:
---> 14         anedf[col] = getSearchedValue(col)

Input In [119], in getSearchedValue(identifier)
        4 full_str = anedf["Diskret data"].astype(str)
        5 value=""
----> 6 if full_str.str.find(identifier) <= -1:
        7     start_index = full_str.str.find(identifier)+len(identifier)+1
        8     end_index = full_str[start_index:].find("|")+start_index

我想这是因为它针对所有行(系列)进行评估,这显然会提供一些错误和正确的错误。但是我怎样才能进行评估和分配,所以它是这样评估+分配的:

Diskret data CCC#111 JJSDJ#1234
CCC#111~1IBBB#2323~2234 1 (copied from "Diskret data") 0
JJSDJ#1234~Heart attack 0 (or skipped since the row does not contain a value for the identifier) Heart attack

计划是在分配完成后删除“Diskret 数据”,这样我的数据就更有条理了。

---更新--- 根据要求:

我附上了一张图片,展示了我如何想象这个问题,以及我似乎无法做到的事情。

Problem visualisation

使用正则表达式,您可以执行以下操作:

def map_(list_) -> pd.Series:
    if list_:
        idx, values = zip(*list_)
        return pd.Series(values, idx)
    else:
        return pd.Series(dtype=object)

series = pd.Series(
    ['CCC#111~1|BBB#2323~2234', 'JJSDJ#1234~Heart attack']
)
reg_series = series.str.findall(r'([^~|]+)~([^~|]+)')
reg_series.apply(map_)

分解:

通过运行在每一行上创建一个映射,将长字符串变成元组列表来创建一个新系列

通过 运行 在每一行上创建一个映射,将长字符串变成元组列表来创建一个新系列。

reg_series = series.str.findall(r'([^~|]+)~([^~|]+)')
reg_series
# output:
# 0    [(CCC#111, 1), (BBB#2323, 2234)]
# 1        [(JJSDJ#1234, Heart attack)]

然后我们创建一个map_函数。此函数获取 reg_series 的每一行并将其映射到两行:第一行仅包含“键”,另一行仅包含“值”。然后我们创建一系列这样的索引作为键和值作为值。

编辑: 我们在 if/else 语句中添加了检查列表是否存在的语句。如果没有,我们 return 一个空系列的类型对象。

def map_(list_) -> pd.Series:
    if list_:
        idx, values = zip(*list_)
        return pd.Series(values, idx)
    else:
        return pd.Series(dtype=object)
...
print(idx, values)  # first row
# output:
# ('CCC#111', 'BBB#2323') (1, 2234)

最后,我们 运行 apply 在该系列中创建一个数据框,该数据框从 map_ 获取每一行的输出,并以柱状格式将它们压缩在一起。

reg_series.apply(map_)

# output: 
#   CCC#111 BBB#2323    JJSDJ#1234
# 0       1     2234           NaN
# 1     NaN      NaN  Heart attack