【问题标题】:Fill pd.Series from list of values if value exist in another df.Series description如果值存在于另一个 df.Series 描述中,则从值列表中填充 pd.Series
【发布时间】:2022-01-27 03:22:55
【问题描述】:

我需要解决棘手的问题,并尽量减少大 O 表示法问题。

我有两个熊猫数据框:

第一个df是这样的:

| source | searchTermsList |

|:---- |:------:|

| A  | [t1, t2, t3,...tn] |
| B  | [t4, t5, t6,...tn] |
| C  | [t7, t8, t9,...tn] |

第一列是字符串,第二列是不重复的字符串列表,只有唯一值。

第二个数据框,我需要创建一个新的 pd.Series,如果 searchTerm 列表中的术语存在第一列 (df1.source),则存在于后面的 df2.Series 中,称为“描述”。

Example.
| objID | dataDescr |

|:---- |:------:|

| 1  | The first description name has t2 | 
| 2  | The second description name has t6 and t7| 
| 3  | The third description name has t8, t1, t9| 

预期结果

| objID | dataDescr | source |

|:---- |:------:| -----:|

| 1  | The first description name    | A |
| 2  | The second description name    | B |
| 3  | The third description name    | C |

说明

  • 第一个描述有t2,所以用A填充列,因为t2出现在术语列表中。

  • 第二个描述有两个术语,t6 和 t7,在这种情况下,只有第一个与第二个列表匹配,所以源将被填充 B

  • 第三个描述有三个词,如上,只获取第一个带有列表的,源将用C填充。

我的方法

如果我拆分descrName,最后在所有列表中搜索那个词,可能计算成本会非常大。 map 的想法行不通,因为没有排序的数据框,第一个只有 10-20 行,只有唯一值,第二个将与每个术语匹配 n 次。

有什么建议吗?

【问题讨论】:

  • df1, df2 的大小是多少?列表的大小是多少?
  • df1 有最小值。 8 行。 (最多 20 个)。每个列表有 n 个词,里面没有重复,是存储的搜索词,所以每个词都可以出现在另一个词列表中。

标签: python pandas dataframe dictionary


【解决方案1】:

DataFrame.explodesearchTermsList 的索引创建Series 以首先进行映射:

s = df1.explode('searchTermsList').set_index('searchTermsList')['source']
print (s)
t1    A
t2    A
t3    A
t4    B
t5    B
t6    B
t7    C
t8    C
t9    C
Name: source, dtype: object

然后将s.index 的值与| 连接起来,对于正则表达式or\b\b 是单词边界。获取第一个匹配值使用Series.str.extract,然后通过Series.map映射:

pat = r"\b({})\b".format("|".join(s.index))

df2['searchTermsList'] = df2['dataDescr'].str.extract(pat, expand=False).map(s)
print (df2)
   objID                                  dataDescr searchTermsList
0      1          The first description name has t2               A
1      2  The second description name has t6 and t7               B
2      3  The third description name has t8, t1, t9               C

另一种解决方案是通过re.findall提取单词并通过Series.get进行映射:

import re
s = df1.explode('searchTermsList').set_index('searchTermsList')['source']

f = lambda x: next((s.get(y) for y in re.findall(r'\b\w+\b',x) if y in s), np.nan)
df2['searchTermsList'] = df2['dataDescr'].apply(f)
print (df2)
   objID                                  dataDescr searchTermsList
0      0                    The first description n             NaN
1      1          The first description name has t2               A
2      2  The second description name has t6 and t7               B
3      3  The third description name has t8, t1, t9               C
      

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-10-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-12-19
    • 1970-01-01
    • 2022-08-18
    相关资源
    最近更新 更多