Pandas 一个热编码数据帧上的聚合
假设我有一个包含10000部电影的数据集,其中一个ERPT是Pandas 一个热编码数据帧上的聚合,pandas,group-by,pivot-table,Pandas,Group By,Pivot Table,假设我有一个包含10000部电影的数据集,其中一个ERPT是 tt0111161 The Shawshank Redemption (1994) 1994 9.2 619479 142 mins. Crime|Drama tt0110912 Pulp Fiction (1994) 1994 9.0 490065 154 mins. Crime|Thriller tt0137523 Fight Club (1999) 1999 8.8
tt0111161 The Shawshank Redemption (1994) 1994 9.2 619479 142 mins. Crime|Drama
tt0110912 Pulp Fiction (1994) 1994 9.0 490065 154 mins. Crime|Thriller
tt0137523 Fight Club (1999) 1999 8.8 458173 139 mins. Drama|Mystery|Thriller
tt0133093 The Matrix (1999) 1999 8.7 448114 136 mins. Action|Adventure|Sci-Fi
tt1375666 Inception (2010) 2010 8.9 385149 148 mins. Action|Adventure|Sci-Fi|Thriller
tt0109830 Forrest Gump (1994) 1994 8.7 368994 142 mins. Comedy|Drama|Romance
tt0169547 American Beauty (1999) 1999 8.6 338332 122 mins. Drama
tt0499549 Avatar (2009) 2009 8.1 336855 162 mins. Action|Adventure|Fantasy|Sci-Fi
tt0108052 Schindler's List (1993) 1993 8.9 325888 195 mins. Biography|Drama|History|War
tt0080684 Star Wars: Episode V - The Empire Strikes Back (1980) 1980 8.8 320105 124 mins. Action|Adventure|Family|Sci-Fi
tt0372784 Batman Begins (2005) 2005 8.3 316613 140 mins. Action|Crime|Drama|Thriller
tt0114814 The Usual Suspects (1995) 1995 8.7 306624 106 mins. Crime|Mystery|Thriller
tt0102926 The Silence of the Lambs (1991) 1991 8.7 293081 118 mins. Crime|Thriller
tt0120338 Titanic (1997) 1997 7.4 284245 194 mins. Adventure|Drama|History|Romance
我有这段代码的要点,可以加载我的数据集并对其执行一些更改
import pandas as pd
import numpy as np
headers = ['imdbID', 'title', 'year', 'score', 'votes', 'runtime', 'genres']
movies = pd.read_csv("imdb_top_10000.txt", sep="\t", header=None, names=headers, encoding='UTF-8')
movies.head()
one_hot_encoding = movies["genres"].str.get_dummies(sep='|')
movies = pd.concat([movies, one_hot_encoding], axis=1)
movies_top_250 = movies.sort_values('score', ascending=False).head(250)
鉴于此
- 我们想从前250个最佳收视率的作品中找出最好的三种类型
- 还有这些类型电影的平均水平
- 此外,我们还想了解这组电影中三种最差评级类型的平均得分
pd.pivot_table(movies_top_250, values=['votes', 'Action', 'Adult'], index='title', aggfunc=np.sum).sort_values('votes', ascending=False)
Action Adult votes
title
The Shawshank Redemption (1994) 0 0 619479
The Dark Knight (2008) 1 0 555122
Pulp Fiction (1994) 0 0 490065
The Godfather (1972) 0 0 474189
Fight Club (1999) 0 0 458173
The Lord of the Rings: The Fellowship of the Ri... 1 0 451263
The Matrix (1999) 1 0 448114
The Lord of the Rings: The Return of the King (... 1 0 428791
Inception (2010) 1 0 385149
The Lord of the Rings: The Two Towers (2002) 1 0 383113
Forrest Gump (1994) 0 0 368994
但这并不能说明哪一种流派拥有多数选票。也
movies.groupby('genres').score.mean()
返回类似于
genres
Action 5.837500
Action|Adventure 6.152381
Action|Adventure|Animation|Comedy|Family|Fantasy 7.500000
Action|Adventure|Animation|Family|Fantasy|Sci-Fi 6.100000
Action|Adventure|Biography|Crime|History|Western 6.300000
Action|Adventure|Biography|Drama|History 7.700000
Genre mean_score votes_sum
Action 7.837500 103237
Adventure 6.152381 103226
Animation 5.500000 103275
所以我真的无法理解这件事。对于第一个问题,我想得到
genres
Action 5.837500
Action|Adventure 6.152381
Action|Adventure|Animation|Comedy|Family|Fantasy 7.500000
Action|Adventure|Animation|Family|Fantasy|Sci-Fi 6.100000
Action|Adventure|Biography|Crime|History|Western 6.300000
Action|Adventure|Biography|Drama|History 7.700000
Genre mean_score votes_sum
Action 7.837500 103237
Adventure 6.152381 103226
Animation 5.500000 103275
安装程序
和一个有用的函数
def arg_nlargest(x, n, use_index=True):
if isinstance(x, pd.Series):
x = x.values
return np.argpartition(-x, n)[:n]
250部顶级电影中有3种顶级电影类型
首先获得前250部电影:
top250_iloc = arg_nlargest(movies['score'], 250)
movies250 = movies.iloc[top250_iloc]
接下来,我们将每部电影的类型扩展为指标,正如您所做的那样
movies250_genre_inds = movies250["genres"].str.get_dummies(sep='|')
最简单的方法是循环指示器列,收集每种类型的集合
genre_agg = {}
for genre in movies250_genre_inds.columns:
mask = movies250_genre_inds[genre].astype(bool)
aggregates = movies250.loc[mask].agg({'score': 'mean', 'votes': 'sum'})
genre_agg[genre] = aggregates.tolist()
genre_agg = pd.DataFrame.from_dict(genre_agg, orient='index', columns=['score_mean', 'votes_sum'])
genre3_iloc = arg_nlargest(genre_agg['score_mean'], 3)
genre3 = genre_agg.iloc[genre3_iloc].sort_values('score_mean', ascending=False)
您可以使用此oneline解决方案(仅针对漂亮格式转义换行符): 说明: 主要的问题是在类型上的
one\u hot\u编码过程产生的多个True
值。一部电影可以指定一种或多种类型。因此,不能按类型正确使用聚合方法。另一方面,按原样使用genres
字段将消除问题中显示的多性别结果:
genres
Action 5.837500
Action|Adventure 6.152381
Action|Adventure|Animation|Comedy|Family|Fantasy 7.500000
Action|Adventure|Animation|Family|Fantasy|Sci-Fi 6.100000
Action|Adventure|Biography|Crime|History|Western 6.300000
Action|Adventure|Biography|Drama|History 7.700000
解决方法是在找到多个性别时复制行。通过将split
与expand
方法组合设置为True
,您可以创建多个数据帧,然后将它们堆叠起来。例如,具有2种类型的电影将出现在结果数据帧的2个中,其中每个数据帧表示分配给每个类型的电影。最后,在解析之后,您可以使用多个函数按性别聚合。我会逐步解释:
1.获得前250部电影(按分数)
加载数据:
import pandas as pd
import numpy as np
headers = ['imdbID', 'title', 'year', 'score', 'votes', 'runtime', 'genres']
movies = pd.read_csv("imdb_top_10000.txt", sep="\t", header=None, names=headers, encoding='UTF-8')
请注意,genres
字段中有空值:
imdbID title year score votes runtime genres
7917 tt0990404 Chop Shop (2007) 2007 7.2 2104 84 mins. NaN
由于使用Pandas的聚合方法将忽略具有任何空值的行,并且此字段上只有一部具有空值的电影,因此可以手动设置(在Imdb上检查):
现在,正如您已经展示的,我们需要按分数排列的前250部电影:
movies = movies.sort_values('score', ascending=False).head(250)
2.使用“拆分并展开”从流派创建流派字段
2.1. 集合索引
仅保留“类型”字段作为列,保留其他字段作为索引。这是为了便于对体裁进行操作
movies = movies.set_index(movies.columns.drop('genres',1).tolist())
genres
imdbID title year score votes runtime
tt0111161 The Shawshank Redemption (1994) 1994 9.2 619479 142 mins. Crime|Drama
tt0068646 The Godfather (1972) 1972 9.2 474189 175 mins. Crime|Drama
tt0060196 The Good, the Bad and the Ugly (1966) 1966 9.0 195238 161 mins. Western
tt0110912 Pulp Fiction (1994) 1994 9.0 490065 154 mins. Crime|Thriller
tt0252487 Outrageous Class (1975) 1975 9.0 9823 87 mins. Comedy|Drama
(250, 1)
2.2. 按流派划分
这将从拆分的N次迭代中创建N个数据帧
movies = movies.genres.str.split('|',expand=True)
0 \
imdbID title year score votes runtime
tt0111161 The Shawshank Redemption (1994) 1994 9.2 619479 142 mins. Crime
tt0068646 The Godfather (1972) 1972 9.2 474189 175 mins. Crime
tt0060196 The Good, the Bad and the Ugly (1966) 1966 9.0 195238 161 mins. Western
tt0110912 Pulp Fiction (1994) 1994 9.0 490065 154 mins. Crime
tt0252487 Outrageous Class (1975) 1975 9.0 9823 87 mins. Comedy
1 \
imdbID title year score votes runtime
tt0111161 The Shawshank Redemption (1994) 1994 9.2 619479 142 mins. Drama
tt0068646 The Godfather (1972) 1972 9.2 474189 175 mins. Drama
tt0060196 The Good, the Bad and the Ugly (1966) 1966 9.0 195238 161 mins. None
tt0110912 Pulp Fiction (1994) 1994 9.0 490065 154 mins. Thriller
tt0252487 Outrageous Class (1975) 1975 9.0 9823 87 mins. Drama
...
2.3. 堆栈
现在,每个电影都有一个唯一的流派值,其中一部电影可以有多行。如果分配了多个流派,则可以堆叠数据帧集。请注意,现在我们有250多行(662行),但有250个不同的电影
movies = movies.stack()
imdbID title year score votes runtime
tt0111161 The Shawshank Redemption (1994) 1994 9.2 619479 142 mins. 0 Crime
1 Drama
tt0068646 The Godfather (1972) 1972 9.2 474189 175 mins. 0 Crime
1 Drama
tt0060196 The Good, the Bad and the Ugly (1966) 1966 9.0 195238 161 mins. 0 Western
dtype: object
(662,)
3.作语法分析
在聚合之前获取合适的数据结构:
# Multiple index to columns
movies = movies.reset_index()
# Name the new column for genre
movies = movies.rename(columns={0:'genre'})
# Only wanted fields to be aggregated
movies = movies.loc[:,['genre','score','votes']]
genre score votes
0 Crime 9.2 619479
1 Drama 9.2 619479
2 Crime 9.2 474189
3 Drama 9.2 474189
4 Western 9.0 195238
(662, 3)
4.总数的
根据您的要求,分数必须按平均值进行汇总,投票数必须按总和进行汇总:
movies = movies.groupby('genres').agg({'score':['mean'], 'votes':['sum']})
score votes
mean sum
genre
Action 8.425714 7912508
Adventure 8.430000 7460632
Animation 8.293333 1769806
Biography 8.393750 2112875
Comedy 8.341509 3166269
(21, 2)
我已经在问题中添加了原始数据。我的坏,我认为这是没有必要的。
movies = movies.groupby('genres').agg({'score':['mean'], 'votes':['sum']})
score votes
mean sum
genre
Action 8.425714 7912508
Adventure 8.430000 7460632
Animation 8.293333 1769806
Biography 8.393750 2112875
Comedy 8.341509 3166269
(21, 2)