熊猫:加入/合并/合并两个数据框

时间:2020-07-24 13:04:34

标签: python pandas

问题:计算针对多个主题发表论文的人数

示例:

  1. "pm"有两篇论文,它们仅与Poo相关,并且由于只有一个主题,因此不被认为是
  2. Physics的一篇论文包含两(2)个主题(AmyPhysics),因此应该算在内
  3. Economics有两篇论文,每篇论文都有不同的主题,因此应该算在内

示例数据框:

Baa
|   | id  | name | has_published_papers                    |
|---|-----|------|-----------------------------------------|
| 0 | 100 | Amy  | pp3524172                               |
| 1 | 101 | Bla  | pp0120888,pp0343660,pp0151738,pp0120631 |
| 2 | 102 | Foo  | pp0134084,pp1262416,pp0120082,pp0117571 |
| 3 | 103 | Boo  | pp0274558,pp0108872,pp1796960,pp0117509 |
| 4 | 104 | Soo  | pp0120338,pp0993846,pp1375666,pp0407887 |
| 5 | 111 | Poo  | pp0152095,pp1234567                     |
| 6 | 112 | Baa  | pp0237474,pp0152095                     |

修改 理想的输出是| | paper_id | name | topics | |----|-----------|-------------|--------------------| | 30 | pp3524172 | research A | Physics, Economics | | 40 | pp0189076 | research B | Math, Physics | | 55 | pp0237474 | research C | Education | | 68 | pp2729488 | research D | Physics, Math | | 79 | pp0152095 | research Z | Physics | | 99 | pp1234567 | research X | Physics | ,代表针对多个主题发表论文的人数

2 个答案:

答案 0 :(得分:5)

您需要一些步骤来合并这些数据集。

您要做的第一件事是将has_published_papers列拆分并扩展为多列:

authors_df = pd.DataFrame({
  'id': [100, 101],
  'name': ['Amy', 'Bla'],
  'has_published_papers': ['pp3524172', 'pp0120888,pp0343660,pp0151738,pp0120631']
})
authors_df.has_published_papers.str.split(',', expand=True)

这将输出

           0          1          2          3
0  pp3524172       None       None       None
1  pp0120888  pp0343660  pp0151738  pp0120631

然后,您可以将其连接到原始数据帧并融化它:

authors_papers_df = (
    pd.concat([
        authors_df.drop(columns=['has_published_papers']),
        authors_df.has_published_papers.str.split(',', expand=True)
    ], axis=1)
    .melt(['id', 'name'], value_name='paper_id')
    .dropna(subset=['paper_id']))

这将输出准备好合并的漂亮数据框:

    id name variable   paper_id
0  100  Amy        0  pp3524172
1  101  Bla        0  pp0120888
3  101  Bla        1  pp0343660
5  101  Bla        2  pp0151738
7  101  Bla        3  pp0120631

您可以执行完全相同的拆分/扩展/融化管道来创建papers_topics数据框。

papers_topics_df = (
    pd.concat([
        papers_df.drop(columns=['topics']),
        papers_df.topics.str.split(', ', expand=True)
    ], axis=1)
    .melt(['paper_id', 'name'], value_name='topic')
    .dropna(subset=['topic'])
)

然后您可以在paper_id上进行合并。

authors_papers_topics_df = authors_papers_df.merge(papers_topics_df, on='paper_id')

现在您有了一个与主题,论文和作者相关的数据框。

要计算每个作者的独特主题,您可以使用:

authors_papers_topics_df.groupby('id')['topics'].nunique()

看到您的修改。要获取具有多个主题的作者数量,请使用:

np.sum(authors_papers_topics_df.groupby('id')['topics'].nunique() > 1)

答案 1 :(得分:2)

首先转换两个数据框:

  1. 您的第一个DataFrame( df )到具有单独行的DataFrame 对于每篇论文,并将论文ID作为索引:

     paper = df.set_index('name').has_published_papers.str.split(',')\
         .explode().reset_index(name='id').set_index('id')
    

    结果是:

               name
     id            
     pp3524172  Amy
     pp0120888  Bla
     pp0343660  Bla
     pp0151738  Bla
     pp0120631  Bla
     pp0134084  Foo
     pp1262416  Foo
     pp0120082  Foo
     pp0117571  Foo
     pp0274558  Boo
     pp0108872  Boo
     pp1796960  Boo
     pp0117509  Boo
     pp0120338  Soo
     pp0993846  Soo
     pp1375666  Soo
     pp0407887  Soo
     pp0152095  Poo
     pp1234567  Poo
     pp0237474  Baa
     pp0152095  Baa
    
  2. 您的第二个DataFrame( df2 )归为Series,将每个主题行划分为 分成单独的元素,再以纸张ID作为索引:

     topic = df2.set_index('paper_id').topics.str.split(', ').explode()
    

    结果是:

     paper_id
     pp3524172      Physics
     pp3524172    Economics
     pp0189076         Math
     pp0189076      Physics
     pp0237474    Education
     pp2729488      Physics
     pp2729488         Math
     pp0152095      Physics
     pp1234567      Physics
     Name: topics, dtype: object
    

然后:

  • 加入他们两个,
  • 删除重复项(以消除有人拥有更多论文的情况 在同一个主题上)
  • 名称分组并计算每个人的主题。

执行此操作的代码是:

result = paper.join(topic).dropna().reset_index(drop=True)\
    .drop_duplicates().groupby('name').count().reset_index()

获取:

  name  topics
0  Amy       2
1  Baa       2
2  Poo       1

要获得真正的最终结果,请检索具有 topics> 1 的行 并仅获取 name 列:

result.query('topics > 1').name

最终结果是:

0    Amy
1    Baa
Name: name, dtype: object

或者,如果您想获取简单的 pythonic 列表(而不是 Series ), 将.tolist()添加到上述说明中,这次将得到:

['Amy', 'Baa']