每个唯一 ID 的每一行中最常用的描述

Most commonly used description use in each row for each unique id

我有问题。我有文章,这些文章有一个独特的 id。然而,问题是 article 描述又名 article - 这不是唯一的。 我想尝试更改 article 描述 article 的名称,以便只剩下一个描述。我总是想使用最常出现的 article 名称。

我已经尝试了一些东西,但是我不知道如何使用 .apply(lambda x: ... 访问它并将最常用的项目写给我,然后将其设置为名称。

如何更改文章的描述,以便仅包含最常提及的文章描述?

    id  article            cost
0   1   Bendge             15.30
1   1   Bendge             15.30
2   1   Bendge V2          15.30
3   1   Bendge - volumne 2 15.30
4   5   SEF                14.89
5   1   Bendge             15.30
6   2   DFH                 4.56
7   2   DFH                 4.56
8   2   DFH V2              4.56
9   2   DFH - volumne 2     4.56
10  2   DFH                 4.56

代码

d = {'id': [1, 1, 1, 1, 5, 1, 2, 2, 2, 2, 2],
     'article': ['Bendge', 'Bendge', 'Bendge V2', 'Bendge - volumne 2', 'SEF', 'Bendge',
                 'DFH', 'DFH', 'DFH V2', 'DFH - volumne 2', 'DFH'],
     'cost': [15.30, 15.30, 15.30, 15.30, 14.89, 15.30,
              4.56, 4.56, 4.56, 4.56, 4.56],
    }
df = pd.DataFrame(data=d)
display(df)

df.loc[df['id'] == 1, ['id','article']].value_counts().head(1)
[OUT]
id  article
1   Bendge     3
dtype: int64

df['article'] = df.apply(lambda x: x[['id','article']].value_counts().head(1))
[OUT]
KeyError: "None of [Index(['id', 'article'], dtype='object')] are in the [index]"

我想要的

    id  article cost
0   1   Bendge  15.30
1   1   Bendge  15.30
2   1   Bendge  15.30
3   1   Bendge  15.30
4   5   SEF     14.89
5   1   Bendge  15.30
6   2   DFH      4.56
7   2   DFH      4.56
8   2   DFH      4.56
9   2   DFH      4.56
10  2   DFH      4.56

使用GroupBy.transform with lambda function with Series.value_counts和第一个索引:

df['article'] =  df.groupby('id')['article'].transform(lambda x: x.value_counts().index[0])
print (df)
    id article   cost
0    1  Bendge  15.30
1    1  Bendge  15.30
2    1  Bendge  15.30
3    1  Bendge  15.30
4    5     SEF  14.89
5    1  Bendge  15.30
6    2     DFH   4.56
7    2     DFH   4.56
8    2     DFH   4.56
9    2     DFH   4.56
10   2     DFH   4.56

第一个值为 Series.mode 的另一个解决方案:

df['article'] = df.groupby('id')['article'].transform(lambda x: x.mode().iat[0])
print (df)
    id article   cost
0    1  Bendge  15.30
1    1  Bendge  15.30
2    1  Bendge  15.30
3    1  Bendge  15.30
4    5     SEF  14.89
5    1  Bendge  15.30
6    2     DFH   4.56
7    2     DFH   4.56
8    2     DFH   4.56
9    2     DFH   4.56
10   2     DFH   4.56

您可以使用 value_counts 来获取计数; reset_index + pivot + idxmax 得到每个 id 最常见的 article;然后 map 回到 id:

mapping = df.value_counts(['id','article']).reset_index().pivot('id','article', 0).idxmax(axis=1)
df['article'] = df['id'].map(mapping)

输出:

    id article   cost
0    1  Bendge  15.30
1    1  Bendge  15.30
2    1  Bendge  15.30
3    1  Bendge  15.30
4    5     SEF  14.89
5    1  Bendge  15.30
6    2     DFH   4.56
7    2     DFH   4.56
8    2     DFH   4.56
9    2     DFH   4.56
10   2     DFH   4.56

您可以使用 mode:

df['article'] = df['id'].map(df.groupby('id')['article'].agg(pd.Series.mode))

或者如果有平局的可能性:

df['article'] = df['id'].map(df.groupby('id')['article'].agg(lambda s: s.mode(s).iloc[0]))

输出:

    id article   cost
0    1  Bendge  15.30
1    1  Bendge  15.30
2    1  Bendge  15.30
3    1  Bendge  15.30
4    5     SEF  14.89
5    1  Bendge  15.30
6    2     DFH   4.56
7    2     DFH   4.56
8    2     DFH   4.56
9    2     DFH   4.56
10   2     DFH   4.56

使用:

#preparing data
string = """    c id  article            cost
0   1   Bendge             15.30
1   1   Bendge             15.30
2   1   BendgeV2          15.30
3   1   Bendge-volumne2 15.30
4   5   SEF                14.89
5   1   Bendge             15.30
6   2   DFH                 4.56
7   2   DFH                 4.56
8   2   DFHV2              4.56
9   2   DFH-volumne2     4.56
10  2   DFH                 4.56"""

data = [x.split() for x in string.split('\n')]
import pandas as pd
df = pd.DataFrame(data[1:], columns  = data[0])

#solution
df['article'] = df.groupby('id')['article'].transform(lambda x: x.value_counts().index[0])

输出:

c   id  article cost
0   0   1   Bendge  15.30
1   1   1   Bendge  15.30
2   2   1   Bendge  15.30
3   3   1   Bendge  15.30
4   4   5   SEF 14.89
5   5   1   Bendge  15.30
6   6   2   DFH 4.56
7   7   2   DFH 4.56
8   8   2   DFH 4.56
9   9   2   DFH 4.56
10  10  2   DFH 4.56

第二种解决方案:

from collections import Counter
df.groupby('id')['article'].transform(lambda x: Counter(x).most_common()[0][0])