Python 根据另一列是否包含列表中的名称在列表中设置列

Python 根据另一列是否包含列表中的名称在列表中设置列,python,pandas,Python,Pandas,我已经为这个问题挣扎了一段时间,所以我想是时候问一下了 我有一份名单: names = ["john", "sally", "tom"] 我有一个df,其中一列是action。 操作有许多不同的功能,例如: “和汤姆去散步” “带萨莉去商店” 我想创建一个名为partner的新列,并将其设置为action中的名称。 我已经设置了这个列,它已经填充了一些日志,但不是所有日志 我试过: for name in names:

我已经为这个问题挣扎了一段时间,所以我想是时候问一下了

我有一份名单:

names = ["john", "sally", "tom"]
我有一个df,其中一列是
action
操作
有许多不同的功能,例如:

  • “和汤姆去散步”
  • “带萨莉去商店”
我想创建一个名为
partner
的新列,并将其设置为
action
中的名称。 我已经设置了这个列,它已经填充了一些日志,但不是所有日志

我试过:

for name in names:
    df['partner'] =  np.where(df.action.str.contains(name), name, df['partner'] )
但我得到了这个错误:

TypeError:第一个参数必须是字符串或编译模式

我这样做对吗?有更好的方法吗?任何帮助都将不胜感激

编辑:要制作我的df样本,您可以使用:

names = ["john", "sally", "tom"]
d = {'name': ['mark','rick','mark','jon', 'lenny'], 'action': ['Went for a walk with tom', 'Took sally to the store', 'Went for a walk with john', 'Went racing with tom and lost', 'Took john to the store'],
    'partner': ['tom', '', 'john', '', 'john']}
df = pd.DataFrame(data=d)
df
列表“names”包含字符串中可能存在的所有名称,因此我认为最简单的方法是找到字符串中的名称并将其设置为partners列

以下是我得到的完整错误:


TypeError回溯(最近一次调用)
在()
11
12对于合作伙伴中的合作伙伴:
--->13 EscrowLogs.loc[EscrowLogs.action.str.contains(partner),'partner']=partner
14
15
包含中的~\Anaconda3\lib\site packages\pandas\core\strings.py(self、pat、case、flags、na、regex)
2415 def包含(self、pat、case=True、flags=0、na=np.nan、regex=True):
2416 result=str\u包含(self.\u数据,pat,case=case,flags=flags,na=na,
->2417正则表达式=正则表达式)
2418返回自包装结果(结果)
2419
str_中的~\Anaconda3\lib\site packages\pandas\core\strings.py包含(arr、pat、case、flags、na、regex)
385标志|=重新忽略案例
386
-->387 regex=re.compile(pat,flags=flags)
388
389如果regex.groups>0:
编译中的~\Anaconda3\lib\re.py(模式、标志)
232 def编译(模式,标志=0):
233“编译正则表达式模式,返回模式对象。”
-->234返回编译(模式、标志)
235
236 def清除():
编译中的~\Anaconda3\lib\re.py(模式、标志)
283返回模式
284如果不是sre_compile.isstring(模式):
-->285 raise TypeError(“第一个参数必须是字符串或编译模式”)
286 p=sre_compile.compile(模式、标志)
287如果不是(标志和调试):
TypeError:第一个参数必须是字符串或编译模式

我需要一个可验证的数据样本来确定,但使用布尔索引应该可以:

for name in names:
     df.loc[df.action.str.contains(name), 'partner'] = name

在我的评论之后,您可以编写一个函数来迭代数据帧的行,并捕获产生错误/异常的值

例如,如果无法解析操作字段,可以使用此函数返回空值:

names = ["john", "sally", "tom"]

def get_partner(p, a):
    # if row already contains partner value, leave as is
    if p:
        return p
    # otherwise, extract partner name from the action column
    else:
        try:
            for name in names:
                if name in a:
                    return name
        # for any problematic action strings, return null value
        # (can be replaced with some other string that you can later check)
        except:
            return None
您还可以使用这个不需要在名称上循环的函数。它将每个句子拆分为一个单词列表,并删除在名称列表中找不到的所有单词,只留下名称值。如果有多个名称,它将使用逗号分隔符分隔它们

names = ["john", "sally", "tom"]

def get_partner(p, a):
    # if row already contains partner value, leave as is
    if p:
        return p
    # otherwise, extract partner name(s) from the action column
    else:
        try:
            return ",".join([i for i in a.split() if i in names])
        # for any problematic action strings, return null value
        # (can be replaced with some other string that you can later check)
        except:
            return None
然后使用
.apply()
在数据帧上运行函数:

df['partner'] = df.apply(lambda x: get_partner(x['partner'], x['action']), axis=1)

能否添加格式化为数据帧的数据样本?谢谢。
.str.contains
方法不是矢量化的,因此您需要仔细考虑此处的迭代,尽管我不愿意这么说;这可能是
apply
和一些正则表达式根据dict获得匹配的一个例子。我不是那种把它作为答案的人。但是,为了公平起见,您至少只需要通过df行一次,这取决于数据的大小。我的直觉是,它可能相当小,而应用正则表达式则是过火了。@k_n_c如果你的直觉是错误的,我已经可以看到时间复杂性在这个问题上爆炸了。把句子分解不容易,我怀疑它涉及到许多不同的方法。我在这方面也犯了同样的错误。我将尝试使用我的df样本进行更新。
df['partner'] = df.apply(lambda x: get_partner(x['partner'], x['action']), axis=1)