【问题标题】:Join dataframes based on partial string-match between columns基于列之间的部分字符串匹配连接数据帧
【发布时间】:2019-02-15 08:07:25
【问题描述】:

我有一个数据框,我想比较它们是否存在于另一个 df 中。

after_h.sample(10, random_state=1)

             movie           year   ratings
108 Mechanic: Resurrection   2016     4.0
206 Warcraft                 2016     4.0
106 Max Steel                2016     3.5
107 Me Before You            2016     4.5

我想比较上述电影是否存在于另一个 df 中。

              FILM                   Votes
0   Avengers: Age of Ultron (2015)   4170
1   Cinderella (2015)                 950
2   Ant-Man (2015)                   3000 
3   Do You Believe? (2015)            350
4   Max Steel (2016)                  560 

我想要这样的东西作为我的最终输出:

    FILM              votes
0  Max Steel           560

【问题讨论】:

  • 如果将复合字符串列 df2['FILM'] 转换为其两个组成列 movie_title (year),则可以与 pd.merge() 连接

标签: python pandas join string-matching partial


【解决方案1】:

有两种方式:

  1. 获取部分匹配的行索引:FILM.startswith(title)FILM.contains(title)。两者之一:

    df1[ df1.movie.apply( lambda title: df2.FILM.str.startswith(title) ).any(1) ]

    df1[ df1['movie'].apply(lambda title: df2['FILM'].str.contains(title)).any(1) ]

     movie      year      ratings
106  Max Steel  2016      3.5
  1. 或者,如果将复合字符串列 df2['FILM'] 转换为其两个组成列 movie_title (year),则可以使用 merge()

.

# see code at bottom to recreate your dataframes
df2[['movie','year']] = df2.FILM.str.extract('([^\(]*) \(([0-9]*)\)')
# reorder columns and drop 'FILM' now we have its subfields 'movie','year'
df2 = df2[['movie','year','Votes']]
df2['year'] = df2['year'].astype(int)

df2.merge(df1)
       movie  year  Votes  ratings
0  Max Steel  2016    560      3.5

(感谢 @user3483203 在这里和 Python 聊天室提供的很多帮助)

重新创建数据框的代码:

import pandas as pd
from pandas.compat import StringIO

dat1 = """movie           year   ratings
108  Mechanic: Resurrection   2016     4.0
206  Warcraft                 2016     4.0
106  Max Steel                2016     3.5
107  Me Before You            2016     4.5"""

dat2 = """FILM                   Votes
0   Avengers: Age of Ultron (2015)   4170
1   Cinderella (2015)                 950
2   Ant-Man (2015)                   3000
3   Do You Believe? (2015)            350
4   Max Steel (2016)                  560"""

df1 = pd.read_csv(StringIO(dat1), sep='\s{2,}', engine='python', index_col=0)
df2 = pd.read_csv(StringIO(dat2), sep='\s{2,}', engine='python')

【讨论】:

  • df2[df1['movie'].apply(lambda movie_title: df2['FILM'].str.contains(movie_title)).any(0)]
  • 部分匹配可能不适合续集:)
  • @jpp:Teehee。向汤姆克鲁斯或乔治卢卡斯投诉... 是的,严格来说,df2['FILM'] 已格式化并在括号中包含标题和(年份)。我应该展示如果我们解决了这个问题,我们可以对标题进行简单的连接。
【解决方案2】:

给定输入数据帧df1df2,您可以通过pd.Series.isin 使用布尔索引。要对齐电影字符串的格式,您需要首先从df1 连接电影和年份:

s = df1['movie'] + ' (' + df1['year'].astype(str) + ')'

res = df2[df2['FILM'].isin(s)]

print(res)

               FILM  VOTES
4  Max Steel (2016)    560

【讨论】:

    【解决方案3】:

    smci 的选项 1 差不多了,以下对我有用:

    df1['Votes'] = ''
    df1['Votes']=df1['movie'].apply(lambda title: df2[df2['FILM'].str.startswith(title)]['Votes'].any(0))
    

    解释:

    在 df1 中创建一个投票列

    对 df1 中的每个电影字符串应用 lambda

    lambda 查找 df2,选择 df2 中 Film 以电影标题开头的所有行

    选择结果 df2 子集的 Votes 列

    用any(0)取该列的第一个值

    【讨论】:

      猜你喜欢
      • 2021-08-22
      • 2019-09-02
      • 2021-01-16
      • 1970-01-01
      • 2020-11-28
      • 2020-08-31
      • 2022-10-19
      • 2021-01-29
      • 1970-01-01
      相关资源
      最近更新 更多