《利用Python进行数据分析》示例
点此下载数据集
1.MoviesLens 1M数据集
GroupLens实验室提供了一些从MoviesLens用户那里收集的20世纪90年代末到21世纪初的电影评分数据的集合。浙西额数据提供了电影的评分、流派、年份和观众数据(年龄、邮编、性别、职业)。 MovisLens1M数据集包含6000个用户对4000部电影的100万个评分。数据分布在三个表格之中:分别包含评分、用户信息和电影信息。
import pandas as pd
#文件皆位于根目录下
# 读取"users.dat"文件,它将列名设置为unames,并将分隔符设置为::。header=None参数表示文件中没有标题行,因此应使用unames中提供的列名。
unames = ["user_id", "gender", "age", "occupation", "zip"]
users = pd.read_table("datasets/movielens/users.dat", sep="::", header=None, names=unames, engine="python")# 读取"ratings.dat"文件
rnames = ["user_id", "movie_id", "rating", "timestamp"]
ratings = pd.read_table("datasets/movielens/ratings.dat", sep="::", header=None, names=rnames, engine="python")# 读取"movies.dat"文件
mnames = ["movie_id", "title", "genres"]
movies = pd.read_table("datasets/movielens/movies.dat", sep="::", header=None, names=mnames, engine="python")
#这段代码片段读取了三个文件("users.dat"、"ratings.dat"和"movies.dat"),
#并将它们分别存储在不同的pandas DataFrame中(users、ratings和movies),以便进一步分析或处理。
users.head(5)#输出用户DataFrame的前5行数据
ratings.head(5)# 输出评分DataFrame的前5行数据
movies.head(5)# 输出电影DataFrame的前5行数据
ratings# 输出完整的ratings DataFrame
user_id | movie_id | rating | timestamp | |
---|---|---|---|---|
0 | 1 | 1193 | 5 | 978300760 |
1 | 1 | 661 | 3 | 978302109 |
2 | 1 | 914 | 3 | 978301968 |
3 | 1 | 3408 | 4 | 978300275 |
4 | 1 | 2355 | 5 | 978824291 |
... | ... | ... | ... | ... |
1000204 | 6040 | 1091 | 1 | 956716541 |
1000205 | 6040 | 1094 | 5 | 956704887 |
1000206 | 6040 | 562 | 5 | 956704746 |
1000207 | 6040 | 1096 | 4 | 956715648 |
1000208 | 6040 | 1097 | 4 | 956715569 |
1000209 rows × 4 columns
#使用pd.merge()函数将ratings、users和movies三个DataFrame合并为一个名为data的新DataFrame。
#这个新的data DataFrame将包含了三个原始DataFrame中的所有列和行,基于它们之间的共同列进行合并。
data = pd.merge(pd.merge(ratings, users), movies)
data#输出data DataFrame合并后的所有数据
data.iloc[0]#输出data DataFrame中的第一行数据
user_id 1 movie_id 1193 rating 5 timestamp 978300760 gender F age 1 occupation 10 zip 48067 title One Flew Over the Cuckoo's Nest (1975) genres Drama Name: 0, dtype: object
#使用pivot_table()函数基于data DataFrame创建了一个名为mean_ratings的新DataFrame,
#该DataFrame计算了每个电影标题(title)在不同性别(gender)下的平均评分。
mean_ratings = data.pivot_table("rating", index="title",columns="gender", aggfunc="mean")
mean_ratings.head(5)#mean_ratings DataFrame 的前5行输出
gender | F | M |
---|---|---|
title | ||
$1,000,000 Duck (1971) | 3.375000 | 2.761905 |
'Night Mother (1986) | 3.388889 | 3.352941 |
'Til There Was You (1997) | 2.675676 | 2.733333 |
'burbs, The (1989) | 2.793478 | 2.962085 |
...And Justice for All (1979) | 3.828571 | 3.689024 |
#使用groupby()函数对data DataFrame按电影标题(title)进行分组,并计算每个电影标题对应的评分数量。
ratings_by_title = data.groupby("title").size()
ratings_by_title.head()#显示每个电影标题对应的评分数量。
active_titles = ratings_by_title.index[ratings_by_title >= 250]#从评分数量中筛选出了评分数大于等于250的活跃电影标题
active_titles
Index([''burbs, The (1989)', '10 Things I Hate About You (1999)','101 Dalmatians (1961)', '101 Dalmatians (1996)', '12 Angry Men (1957)','13th Warrior, The (1999)', '2 Days in the Valley (1996)','20,000 Leagues Under the Sea (1954)', '2001: A Space Odyssey (1968)','2010 (1984)',...'X-Men (2000)', 'Year of Living Dangerously (1982)','Yellow Submarine (1968)', 'You've Got Mail (1998)','Young Frankenstein (1974)', 'Young Guns (1988)','Young Guns II (1990)', 'Young Sherlock Holmes (1985)','Zero Effect (1998)', 'eXistenZ (1999)'],dtype='object', name='title', length=1216)
#使用loc索引器从mean_ratings DataFrame 中选择评分数大于等于250的活跃电影标题
mean_ratings = mean_ratings.loc[active_titles]
mean_ratings
gender | F | M |
---|---|---|
title | ||
'burbs, The (1989) | 2.793478 | 2.962085 |
10 Things I Hate About You (1999) | 3.646552 | 3.311966 |
101 Dalmatians (1961) | 3.791444 | 3.500000 |
101 Dalmatians (1996) | 3.240000 | 2.911215 |
12 Angry Men (1957) | 4.184397 | 4.328421 |
... | ... | ... |
Young Guns (1988) | 3.371795 | 3.425620 |
Young Guns II (1990) | 2.934783 | 2.904025 |
Young Sherlock Holmes (1985) | 3.514706 | 3.363344 |
Zero Effect (1998) | 3.864407 | 3.723140 |
eXistenZ (1999) | 3.098592 | 3.289086 |
1216 rows × 2 columns
#使用rename()函数将mean_ratings DataFrame 中的索引标签从"Seven Samurai (The Magnificent Seven) (Shichinin no samurai) (1954)"更改为
#"Seven Samurai (Shichinin no samurai) (1954)"。
mean_ratings = mean_ratings.rename(index={"Seven Samurai (The Magnificent Seven) (Shichinin no samurai) (1954)":"Seven Samurai (Shichinin no samurai) (1954)"})
#使用sort_values()函数根据女性观众的平均评分("F"列)对mean_ratings DataFrame 进行降序排序
top_female_ratings = mean_ratings.sort_values("F", ascending=False)
top_female_ratings.head()
gender | F | M | diff |
---|---|---|---|
title | |||
Close Shave, A (1995) | 4.644444 | 4.473795 | -0.170650 |
Wrong Trousers, The (1993) | 4.588235 | 4.478261 | -0.109974 |
Sunset Blvd. (a.k.a. Sunset Boulevard) (1950) | 4.572650 | 4.464589 | -0.108060 |
Wallace & Gromit: The Best of Aardman Animation (1996) | 4.563107 | 4.385075 | -0.178032 |
Schindler's List (1993) | 4.562602 | 4.491415 | -0.071187 |
#通过计算mean_ratings DataFrame 中男性观众平均评分("M"列)与女性观众平均评分("F"列)的差异,将差异值添加为名为"diff"的新列。
mean_ratings["diff"] = mean_ratings["M"] - mean_ratings["F"]
mean_ratings
gender | F | M | diff |
---|---|---|---|
title | |||
'burbs, The (1989) | 2.793478 | 2.962085 | 0.168607 |
10 Things I Hate About You (1999) | 3.646552 | 3.311966 | -0.334586 |
101 Dalmatians (1961) | 3.791444 | 3.500000 | -0.291444 |
101 Dalmatians (1996) | 3.240000 | 2.911215 | -0.328785 |
12 Angry Men (1957) | 4.184397 | 4.328421 | 0.144024 |
... | ... | ... | ... |
Young Guns (1988) | 3.371795 | 3.425620 | 0.053825 |
Young Guns II (1990) | 2.934783 | 2.904025 | -0.030758 |
Young Sherlock Holmes (1985) | 3.514706 | 3.363344 | -0.151362 |
Zero Effect (1998) | 3.864407 | 3.723140 | -0.141266 |
eXistenZ (1999) | 3.098592 | 3.289086 | 0.190494 |
1216 rows × 3 columns
#使用sort_values()函数根据差异值("diff"列)对mean_ratings DataFrame 进行升序排序
sorted_by_diff = mean_ratings.sort_values("diff")
sorted_by_diff.head()
gender | F | M | diff |
---|---|---|---|
title | |||
Dirty Dancing (1987) | 3.790378 | 2.959596 | -0.830782 |
Jumpin' Jack Flash (1986) | 3.254717 | 2.578358 | -0.676359 |
Grease (1978) | 3.975265 | 3.367041 | -0.608224 |
Little Women (1994) | 3.870588 | 3.321739 | -0.548849 |
Steel Magnolias (1989) | 3.901734 | 3.365957 | -0.535777 |
#通过使用切片操作[::-1]对sorted_by_diff DataFrame 进行逆序排序,并返回前5行内容。
sorted_by_diff[::-1].head(5)
gender | F | M | diff |
---|---|---|---|
title | |||
Good, The Bad and The Ugly, The (1966) | 3.494949 | 4.221300 | 0.726351 |
Kentucky Fried Movie, The (1977) | 2.878788 | 3.555147 | 0.676359 |
Dumb & Dumber (1994) | 2.697987 | 3.336595 | 0.638608 |
Longest Day, The (1962) | 3.411765 | 4.031447 | 0.619682 |
Cable Guy, The (1996) | 2.250000 | 2.863787 | 0.613787 |
#使用groupby()函数按电影标题(title)分组,并计算每个电影标题对应的评分标准差。
rating_std_by_title = data.groupby("title")["rating"].std()
#从标准差结果中筛选出评分数大于等于250的活跃电影标题,
rating_std_by_title = rating_std_by_title.loc[active_titles]
rating_std_by_title.head()
title 'burbs, The (1989) 1.107760 10 Things I Hate About You (1999) 0.989815 101 Dalmatians (1961) 0.982103 101 Dalmatians (1996) 1.098717 12 Angry Men (1957) 0.812731 Name: rating, dtype: float64
#使用sort_values()函数将rating_std_by_title Series 对象按评分标准差进行降序排序,并返回前10个最大的标准差值。
rating_std_by_title.sort_values(ascending=False)[:10]
title Dumb & Dumber (1994) 1.321333 Blair Witch Project, The (1999) 1.316368 Natural Born Killers (1994) 1.307198 Tank Girl (1995) 1.277695 Rocky Horror Picture Show, The (1975) 1.260177 Eyes Wide Shut (1999) 1.259624 Evita (1996) 1.253631 Billy Madison (1995) 1.249970 Fear and Loathing in Las Vegas (1998) 1.246408 Bicentennial Man (1999) 1.245533 Name: rating, dtype: float64
#展示"genres"列的前5行数据
movies["genres"].head()
#将每个电影的"genres"列按竖线字符分割成一个列表
movies["genres"].head().str.split("|")
#将分割后的列表赋值给了一个名为"genre"的新列,并删除了原始的"genres"列。这样,"genre"列包含了每个电影的类型列表。
movies["genre"] = movies.pop("genres").str.split("|")
movies.head()
movie_id | title | genre | |
---|---|---|---|
0 | 1 | Toy Story (1995) | [Animation, Children's, Comedy] |
1 | 2 | Jumanji (1995) | [Adventure, Children's, Fantasy] |
2 | 3 | Grumpier Old Men (1995) | [Comedy, Romance] |
3 | 4 | Waiting to Exhale (1995) | [Comedy, Drama] |
4 | 5 | Father of the Bride Part II (1995) | [Comedy] |
#使用explode()函数将"genre"列中的列表元素展开为多行,并将结果存储在名为"movies_exploded"的新DataFrame中。然后显示前10行的数据。
movies_exploded = movies.explode("genre")
movies_exploded[:10]
movie_id | title | genre | |
---|---|---|---|
0 | 1 | Toy Story (1995) | Animation |
0 | 1 | Toy Story (1995) | Children's |
0 | 1 | Toy Story (1995) | Comedy |
1 | 2 | Jumanji (1995) | Adventure |
1 | 2 | Jumanji (1995) | Children's |
1 | 2 | Jumanji (1995) | Fantasy |
2 | 3 | Grumpier Old Men (1995) | Comedy |
2 | 3 | Grumpier Old Men (1995) | Romance |
3 | 4 | Waiting to Exhale (1995) | Comedy |
3 | 4 | Waiting to Exhale (1995) | Drama |
#使用pd.merge()函数将"movies_exploded"、"ratings"和"users"三个DataFrame进行合并,创建一个名为"ratings_with_genre"的新DataFrame。
ratings_with_genre = pd.merge(pd.merge(movies_exploded, ratings), users)
#选择"ratings_with_genre" DataFrame 中的第一行数据。
ratings_with_genre.iloc[0]
#使用groupby()函数对"ratings_with_genre" DataFrame 按"genre"和"age"分组,并计算每个组中"rating"列的平均值。
genre_ratings = (ratings_with_genre.groupby(["genre", "age"])["rating"].mean()#使用mean()函数计算每个分组的平均值.unstack("age"))#使用unstack("age")将结果重塑为以"age"作为列索引的形式。
genre_ratings[:10]
age | 1 | 18 | 25 | 35 | 45 | 50 | 56 |
---|---|---|---|---|---|---|---|
genre | |||||||
Action | 3.506385 | 3.447097 | 3.453358 | 3.538107 | 3.528543 | 3.611333 | 3.610709 |
Adventure | 3.449975 | 3.408525 | 3.443163 | 3.515291 | 3.528963 | 3.628163 | 3.649064 |
Animation | 3.476113 | 3.624014 | 3.701228 | 3.740545 | 3.734856 | 3.780020 | 3.756233 |
Children's | 3.241642 | 3.294257 | 3.426873 | 3.518423 | 3.527593 | 3.556555 | 3.621822 |
Comedy | 3.497491 | 3.460417 | 3.490385 | 3.561984 | 3.591789 | 3.646868 | 3.650949 |
Crime | 3.710170 | 3.668054 | 3.680321 | 3.733736 | 3.750661 | 3.810688 | 3.832549 |
Documentary | 3.730769 | 3.865865 | 3.946690 | 3.953747 | 3.966521 | 3.908108 | 3.961538 |
Drama | 3.794735 | 3.721930 | 3.726428 | 3.782512 | 3.784356 | 3.878415 | 3.933465 |
Fantasy | 3.317647 | 3.353778 | 3.452484 | 3.482301 | 3.532468 | 3.581570 | 3.532700 |
Film-Noir | 4.145455 | 3.997368 | 4.058725 | 4.064910 | 4.105376 | 4.175401 | 4.125932 |
2.美国1880-2010年的婴儿名字
美国社会保障局(SSA)提供了从1880年至现在的婴儿姓名频率的数据。可以使用这些数据做很多事情:
根据给定的名字对婴儿名字随时间的比例进行可视化
确定一个名字的相对排位
确定每年最受欢迎的名字,或者流行程度最高或最低的名字
#在读取时,为列指定了列名为["name", "sex", "births"]。
names1880 = pd.read_csv("datasets/babynames/yob1880.txt",names=["name", "sex", "births"])
names1880
name | sex | births | |
---|---|---|---|
0 | Mary | F | 7065 |
1 | Anna | F | 2604 |
2 | Emma | F | 2003 |
3 | Elizabeth | F | 1939 |
4 | Minnie | F | 1746 |
... | ... | ... | ... |
1995 | Woodie | M | 5 |
1996 | Worthy | M | 5 |
1997 | Wright | M | 5 |
1998 | York | M | 5 |
1999 | Zachariah | M | 5 |
#对 names1880 DataFrame 进行分组,按照性别("sex")进行分组,并计算每个性别对应的出生数("births" 列)的总和。
names1880.groupby("sex")["births"].sum()
sex F 90993 M 110493 Name: births, dtype: int64
pieces = []
#代码通过循环遍历从1880年到2010年的文件,并将每个文件的内容读取为DataFrame
for year in range(1880, 2011):path = f"datasets/babynames/yob{year}.txt"frame = pd.read_csv(path, names=["name", "sex", "births"])#为每个DataFrame添加一个名为"year"的列frame["year"] = yearpieces.append(frame)#用pd.concat()函数将所有DataFrame连接成一个单独的DataFrame
names = pd.concat(pieces, ignore_index=True)
names#显示该Frame
name | sex | births | year | |
---|---|---|---|---|
0 | Mary | F | 7065 | 1880 |
1 | Anna | F | 2604 | 1880 |
2 | Emma | F | 2003 | 1880 |
3 | Elizabeth | F | 1939 | 1880 |
4 | Minnie | F | 1746 | 1880 |
... | ... | ... | ... | ... |
1690779 | Zymaire | M | 5 | 2010 |
1690780 | Zyonne | M | 5 | 2010 |
1690781 | Zyquarius | M | 5 | 2010 |
1690782 | Zyran | M | 5 | 2010 |
1690783 | Zzyzx | M | 5 | 2010 |
1690784 rows × 4 columns
#使用pivot_table()函数计算了按年份和性别分组的出生数总和
total_births = names.pivot_table("births", index="year",columns="sex", aggfunc=sum)
#显示total_births DataFrame 的最后几行
total_births.tail()
#绘制了一个标题为"Total births by sex and year"的出生数按年份和性别的折线图。
total_births.plot(title="Total births by sex and year")
#定义了一个名为add_prop的函数。该函数接收一个分组,并为该分组计算一个名为"prop"的新列,表示每个名字在该年份和性别分组中的比例,每个名字的出生率
def add_prop(group):group["prop"] = group["births"] / group["births"].sum()return group
#将names DataFrame 按年份和性别分组,并对每个分组应用add_prop函数
names = names.groupby(["year", "sex"], group_keys=False).apply(add_prop)
name | sex | births | year | prop | |
---|---|---|---|---|---|
0 | Mary | F | 7065 | 1880 | 0.077643 |
1 | Anna | F | 2604 | 1880 | 0.028618 |
2 | Emma | F | 2003 | 1880 | 0.022013 |
3 | Elizabeth | F | 1939 | 1880 | 0.021309 |
4 | Minnie | F | 1746 | 1880 | 0.019188 |
... | ... | ... | ... | ... | ... |
1690779 | Zymaire | M | 5 | 2010 | 0.000003 |
1690780 | Zyonne | M | 5 | 2010 | 0.000003 |
1690781 | Zyquarius | M | 5 | 2010 | 0.000003 |
1690782 | Zyran | M | 5 | 2010 | 0.000003 |
1690783 | Zzyzx | M | 5 | 2010 | 0.000003 |
1690784 rows × 5 columns
#按照 "year" 和 "sex" 进行分组,并计算每个组中的 "prop" 列的总和。
names.groupby(["year", "sex"])["prop"].sum()
year sex 1880 F 1.0M 1.0 1881 F 1.0M 1.0 1882 F 1.0... 2008 M 1.0 2009 F 1.0M 1.0 2010 F 1.0M 1.0 Name: prop, Length: 262, dtype: float64
#该函数接收一个分组,并按照 "births" 列(出生人数)的降序对分组进行排序,然后选择排序结果中的前1000行
def get_top1000(group):return group.sort_values("births", ascending=False)[:1000]
#按照 "year" 和 "sex" 进行分组,并对每个分组应用 get_top1000 函数
grouped = names.groupby(["year", "sex"])
top1000 = grouped.apply(get_top1000)
top1000.head()
name | sex | births | year | prop | |||
---|---|---|---|---|---|---|---|
year | sex | ||||||
1880 | F | 0 | Mary | F | 7065 | 1880 | 0.077643 |
1 | Anna | F | 2604 | 1880 | 0.028618 | ||
2 | Emma | F | 2003 | 1880 | 0.022013 | ||
3 | Elizabeth | F | 1939 | 1880 | 0.021309 | ||
4 | Minnie | F | 1746 | 1880 | 0.019188 |
#使用reset_index()函数对top1000 DataFrame 进行重置索引,并丢弃原始索引。设置drop=True可以移除原始索引列,以便在重置索引后不保留它。
top1000 = top1000.reset_index(drop=True)
top1000.head()#显示出生人数最多的前5名
name | sex | births | year | prop | |
---|---|---|---|---|---|
0 | Mary | F | 7065 | 1880 | 0.077643 |
1 | Anna | F | 2604 | 1880 | 0.028618 |
2 | Emma | F | 2003 | 1880 | 0.022013 |
3 | Elizabeth | F | 1939 | 1880 | 0.021309 |
4 | Minnie | F | 1746 | 1880 | 0.019188 |
#代码根据 "sex" 列的值将 top1000 DataFrame 分为男孩("M")和女孩("F")两个子数据集。
boys = top1000[top1000["sex"] == "M"]
girls = top1000[top1000["sex"] == "F"]
#使用 pivot_table() 函数对 top1000 DataFrame 进行数据透视,计算了每个名字在不同年份下的出生数总和
total_births = top1000.pivot_table("births", index="year",columns="name",aggfunc=sum)
#码使用 info() 方法打印出 total_births DataFrame 的信息,然后从中选择了 "John"、"Harry"、"Mary" 和 "Marilyn" 四个名字的列,
#并绘制了一个子图展示每年的出生数。
total_births.info()
#选择这四个名字进行绘制
subset = total_births[["John", "Harry", "Mary", "Marilyn"]]
#使用 plot() 方法对 subset DataFrame 进行绘图,设置 subplots=True 以绘制子图,figsize=(12, 10) 用于设置图形的大小
subset.plot(subplots=True, figsize=(12, 10),title="Number of births per year")
import matplotlib.pyplot as plt#创建一个新的画布。
plt.figure()
#使用 pivot_table() 函数计算了 top1000 DataFrame 中 的出生率总和
table = top1000.pivot_table("prop", index="year",columns="sex", aggfunc=sum)
#使用 plot() 方法绘制了一个折线图,展示了每年男女出生率关系
table.plot(title="Sum of table1000.prop by year and sex",yticks=np.linspace(0, 1.2, 13))
df = boys[boys["year"] == 2010]#2010年男孩出生人数表
df
name | sex | births | year | prop | |
---|---|---|---|---|---|
260877 | Jacob | M | 21875 | 2010 | 0.011523 |
260878 | Ethan | M | 17866 | 2010 | 0.009411 |
260879 | Michael | M | 17133 | 2010 | 0.009025 |
260880 | Jayden | M | 17030 | 2010 | 0.008971 |
260881 | William | M | 16870 | 2010 | 0.008887 |
... | ... | ... | ... | ... | ... |
261872 | Camilo | M | 194 | 2010 | 0.000102 |
261873 | Destin | M | 194 | 2010 | 0.000102 |
261874 | Jaquan | M | 194 | 2010 | 0.000102 |
261875 | Jaydan | M | 194 | 2010 | 0.000102 |
261876 | Maxton | M | 193 | 2010 | 0.000102 |
1000 rows × 5 columns
#对 DataFrame 中的 "prop" 列进行排序,并计算累计和。然后,展示了累计和的前10个值,
#并使用 searchsorted() 方法找到累计和达到 0.5 时的索引位置。
prop_cumsum = df["prop"].sort_values(ascending=False).cumsum()
prop_cumsum[:10]
prop_cumsum.searchsorted(0.5)
116
#从名为 boys 的 DataFrame 中选择了年份为 1900 的数据,并对该子数据集按 "prop" 列进行降序排序。
#然后,计算累计和,并使用 searchsorted() 方法找到累计和达到 0.5 时的索引位置,最后加上 1。
df = boys[boys.year == 1900]
in1900 = df.sort_values("prop", ascending=False).prop.cumsum()
in1900.searchsorted(0.5) + 1
25
#定义了一个名为 get_quantile_count 的函数。该函数接收一个分组,并按照 "prop" 列的值进行降序排序。然后,计算累计和,
#并使用 searchsorted() 方法找到累计和达到给定分位数 q 时的位置,最后加上 1。
def get_quantile_count(group, q=0.5):group = group.sort_values("prop", ascending=False)return group.prop.cumsum().searchsorted(q) + 1diversity = top1000.groupby(["year", "sex"]).apply(get_quantile_count)
diversity = diversity.unstack()
fig = plt.figure()
diversity.head()
#使用 plot() 方法绘制了一个图表,标题为 "Number of popular names in top 50%"。图表展示了每个年份和性别组合中达到前50%的名字数量。
diversity.plot(title="Number of popular names in top 50%")
#定义了一个名为 get_last_letter 的函数。该函数接收一个字符串 x,并返回字符串的最后一个字母。
def get_last_letter(x):return x[-1]
#使用 map() 方法将 get_last_letter 函数应用于 names DataFrame 的 "name" 列,将每个名字的最后一个字母提取出来
last_letters = names["name"].map(get_last_letter)
last_letters.name = "last_letter"
#使用 pivot_table() 函数对 names DataFrame 进行数据透视,计算每个年份和性别组合中,根据最后一个字母进行分组的出生数总和
table = names.pivot_table("births", index=last_letters,columns=["sex", "year"], aggfunc=sum)
#将展示按照特定年份(1910、1960 和 2010)的出生数数据,并且按照性别和最后一个字母的分布。
subtable = table.reindex(columns=[1910, 1960, 2010], level="year")
subtable.head()
sex | F | M | ||||
---|---|---|---|---|---|---|
year | 1910 | 1960 | 2010 | 1910 | 1960 | 2010 |
last_letter | ||||||
a | 108376.0 | 691247.0 | 670605.0 | 977.0 | 5204.0 | 28438.0 |
b | NaN | 694.0 | 450.0 | 411.0 | 3912.0 | 38859.0 |
c | 5.0 | 49.0 | 946.0 | 482.0 | 15476.0 | 23125.0 |
d | 6750.0 | 3729.0 | 2607.0 | 22111.0 | 262112.0 | 44398.0 |
e | 133569.0 | 435013.0 | 313833.0 | 28655.0 | 178823.0 | 129012.0 |
#展示每个年份和性别组合中每个字母的比例,以及它们在对应年份的出生数总和的占比。
subtable.sum()
letter_prop = subtable / subtable.sum()
letter_prop
sex | F | M | ||||
---|---|---|---|---|---|---|
year | 1910 | 1960 | 2010 | 1910 | 1960 | 2010 |
last_letter | ||||||
a | 0.273390 | 0.341853 | 0.381240 | 0.005031 | 0.002440 | 0.014980 |
b | NaN | 0.000343 | 0.000256 | 0.002116 | 0.001834 | 0.020470 |
c | 0.000013 | 0.000024 | 0.000538 | 0.002482 | 0.007257 | 0.012181 |
d | 0.017028 | 0.001844 | 0.001482 | 0.113858 | 0.122908 | 0.023387 |
e | 0.336941 | 0.215133 | 0.178415 | 0.147556 | 0.083853 | 0.067959 |
f | NaN | 0.000010 | 0.000055 | 0.000783 | 0.004325 | 0.001188 |
g | 0.000144 | 0.000157 | 0.000374 | 0.002250 | 0.009488 | 0.001404 |
h | 0.051529 | 0.036224 | 0.075852 | 0.045562 | 0.037907 | 0.051670 |
i | 0.001526 | 0.039965 | 0.031734 | 0.000844 | 0.000603 | 0.022628 |
j | NaN | NaN | 0.000090 | NaN | NaN | 0.000769 |
k | 0.000121 | 0.000156 | 0.000356 | 0.036581 | 0.049384 | 0.018541 |
l | 0.043189 | 0.033867 | 0.026356 | 0.065016 | 0.104904 | 0.070367 |
m | 0.001201 | 0.008613 | 0.002588 | 0.058044 | 0.033827 | 0.024657 |
n | 0.079240 | 0.130687 | 0.140210 | 0.143415 | 0.152522 | 0.362771 |
o | 0.001660 | 0.002439 | 0.001243 | 0.017065 | 0.012829 | 0.042681 |
p | 0.000018 | 0.000023 | 0.000020 | 0.003172 | 0.005675 | 0.001269 |
q | NaN | NaN | 0.000030 | NaN | NaN | 0.000180 |
r | 0.013390 | 0.006764 | 0.018025 | 0.064481 | 0.031034 | 0.087477 |
s | 0.039042 | 0.012764 | 0.013332 | 0.130815 | 0.102730 | 0.065145 |
t | 0.027438 | 0.015201 | 0.007830 | 0.072879 | 0.065655 | 0.022861 |
u | 0.000684 | 0.000574 | 0.000417 | 0.000124 | 0.000057 | 0.001221 |
v | NaN | 0.000060 | 0.000117 | 0.000113 | 0.000037 | 0.001434 |
w | 0.000020 | 0.000031 | 0.001182 | 0.006329 | 0.007711 | 0.016148 |
x | 0.000015 | 0.000037 | 0.000727 | 0.003965 | 0.001851 | 0.008614 |
y | 0.110972 | 0.152569 | 0.116828 | 0.077349 | 0.160987 | 0.058168 |
z | 0.002439 | 0.000659 | 0.000704 | 0.000170 | 0.000184 | 0.001831 |
import matplotlib.pyplot as plt
#使用 Matplotlib 库绘制了一个包含两个子图的图形窗口,每个子图展示了不同性别的字母比例数据
fig, axes = plt.subplots(2, 1, figsize=(10, 8))
#在第一个子图中绘制了一个垂直柱状图。kind="bar" 表示绘制柱状图,rot=0 表示不旋转 x 轴标签,ax=axes[0] 表示绘制在第一个子图上,title="Male" 设置了子图的标题为 "Male",即男性。
letter_prop["M"].plot(kind="bar", rot=0, ax=axes[0], title="Male")
#在第二个子图中绘制了一个垂直柱状图。kind="bar" 表示绘制柱状图,rot=0 表示不旋转 x 轴标签,ax=axes[1] 表示绘制在第二个子图上,
#title="Female" 设置了子图的标题为 "Female",即女性。legend=False 表示不显示图例。
letter_prop["F"].plot(kind="bar", rot=0, ax=axes[1], title="Female",legend=False)
plt.subplots_adjust(hspace=0.25) # 调整子图之间的垂直间距letter_prop = table / table.sum() # 计算每个字母在每年出生人数中的比例dny_ts = letter_prop.loc[["d", "n", "y"], "M"].T # 从letter_prop中选择字母"d", "n", "y"在男性出生人数中的比例,并进行转置操作dny_ts.head() # 显示dny_ts DataFrame的前几行数据
last_letter | d | n | y |
---|---|---|---|
year | |||
1880 | 0.083055 | 0.153213 | 0.075760 |
1881 | 0.083247 | 0.153214 | 0.077451 |
1882 | 0.085340 | 0.149560 | 0.077537 |
1883 | 0.084066 | 0.151646 | 0.079144 |
1884 | 0.086120 | 0.149915 | 0.080405 |
plt.close("all") # 关闭所有打开的图形窗口
fig = plt.figure() # 创建一个新的Figure对象
dny_ts.plot() # 对dny_ts DataFrame进行折线图的可视化
all_names = pd.Series(top1000["name"].unique()) # 从top1000 DataFrame的"name"列获取唯一的姓名,并将结果存储在all_names变量中lesley_like = all_names[all_names.str.contains("Lesl")] # 选择all_names中包含"Lesl"的姓名,并将结果赋值给lesley_like变量lesley_like # 显示lesley_like Series,即包含以"Lesl"开头的姓名
632 Leslie 2294 Lesley 4262 Leslee 4728 Lesli 6103 Lesly dtype: object
filtered = top1000[top1000["name"].isin(lesley_like)] # 根据top1000 DataFrame中的"name"列与lesley_like中的姓名进行匹配,筛选出匹配的行数据,并将结果赋值给filtered变量filtered.groupby("name")["births"].sum() # 对filtered DataFrame按姓名进行分组,计算每个姓名的出生人数总和,并显示结果
name Leslee 1082 Lesley 35022 Lesli 929 Leslie 370429 Lesly 10067 Name: births, dtype: int64
table = filtered.pivot_table("births", index="year", columns="sex", aggfunc="sum") # 根据年份和性别对filtered DataFrame进行透视,计算每个年份和性别的出生人数总和,并将结果存储在table变量中table = table.div(table.sum(axis="columns"), axis="index") # 对table DataFrame进行行归一化,即每行的总和作为除数,计算每个年份和性别的归一化比例table.tail() # 显示table DataFrame的最后几行数据,即归一化后的比例结果
sex | F | M |
---|---|---|
year | ||
2006 | 1.0 | NaN |
2007 | 1.0 | NaN |
2008 | 1.0 | NaN |
2009 | 1.0 | NaN |
2010 | 1.0 | NaN |
fig = plt.figure() # 创建一个新的Figure对象table.plot(style={"M": "k-", "F": "k--"}) # 对table DataFrame进行折线图的可视化,男性使用黑色实线,女性使用黑色虚线
3.美国农业部视频数据库
美国农业部提供了食物营养信息数据库。每种事务都有一些识别属性以及两份营养元素和营养比例的列表。这种形式的数据不适合分析,所以需要做一些工作将数据转换成更好的形式。
接下来我们将结合代码共同学习这一分析过程。本例题涉及以下知识点,重要处会有代码注释:
创建和操作Pandas DataFrame:使用
pd.DataFrame()
函数创建Pandas DataFrame对象,使用head()
方法查看DataFrame的前几行数据,使用info()
方法查看DataFrame的基本信息。数据筛选和计数:使用
pd.value_counts()
函数对选定列中的每个唯一值进行计数。循环和列表操作:使用
for
循环遍历列表中的每个元素,使用append()
方法将元素添加到列表中。合并DataFrame:使用
pd.concat()
函数将多个DataFrame对象合并为一个大的DataFrame,使用merge()
函数基于指定的列将两个DataFrame合并。数据清洗:使用
drop_duplicates()
方法删除重复的行。列重命名:使用
rename()
方法重命名DataFrame的列名。可视化:使用
matplotlib.pyplot
库进行可视化,使用plot()
方法绘制条形图。分组和聚合:使用
groupby()
方法对DataFrame进行分组,并使用聚合函数计算每个分组的统计量。
import json
db = json.load(open("datasets/usda_food/database.json"))# 计算对象db的长度,即列表中元素的数量
len(db)
# 获取db列表中索引为0的元素的所有键
db[0].keys()# 从db列表中索引为0的元素中获取键为"nutrients"的值的列表,并返回列表中的第一个元素
db[0]["nutrients"][0]# *注意*将db列表中索引为0的元素中的"nutrients"值转换为Pandas DataFrame对象
nutrients = pd.DataFrame(db[0]["nutrients"])# 显示nutrients DataFrame的前7行数据
nutrients.head(7)
value | units | description | group | |
---|---|---|---|---|
0 | 25.18 | g | Protein | Composition |
1 | 29.20 | g | Total lipid (fat) | Composition |
2 | 3.06 | g | Carbohydrate, by difference | Composition |
3 | 3.28 | g | Ash | Other |
4 | 376.00 | kcal | Energy | Energy |
5 | 39.28 | g | Water | Composition |
6 | 1573.00 | kJ | Energy | Energy |
Q:为什么需要将db列表中索引为0的元素中的"nutrients"值转换为Pandas DataFrame对象?
A:创建和操作Pandas DataFrame:nutrients = pd.DataFrame(db[0]["nutrients"])将db列表中索引为0的元素中的"nutrients"值转换为Pandas DataFrame对象,并将其存储在nutrients变量中。这样我们可以使用Pandas提供的函数和方法对数据进行处理和分析。nutrients.head(7)使用head()方法显示nutrients DataFrame的前7行数据。
info_keys = ["description", "group", "id", "manufacturer"] # 包含要从数据库中提取的信息的键的列表
info = pd.DataFrame(db, columns=info_keys) # 使用info_keys作为列名,创建包含db数据的Pandas DataFrame对象,并将其存储在info变量中
info.head() # 显示info DataFrame的前几行数据
info.info() # 显示info DataFrame的基本信息,包括列名、每列的非空值数量、每列的数据类型等
<class 'pandas.core.frame.DataFrame'> RangeIndex: 6636 entries, 0 to 6635 Data columns (total 4 columns):# Column Non-Null Count Dtype --- ------ -------------- ----- 0 description 6636 non-null object1 group 6636 non-null object2 id 6636 non-null int64 3 manufacturer 5195 non-null object dtypes: int64(1), object(3) memory usage: 207.5+ KB
pd.value_counts(info["group"])[:10]
'''
info["group"]:从DataFrame info 中选择了名为 "group" 的列,该列包含了食物的分组信息。
pd.value_counts():对选定列中的每个唯一值进行计数,并返回计数结果。
[:10]:取计数结果中的前 10 个值,即返回出现次数最多的前 10 个分组
'''
Vegetables and Vegetable Products 812 Beef Products 618 Baked Products 496 Breakfast Cereals 403 Legumes and Legume Products 365 Fast Foods 365 Lamb, Veal, and Game Products 345 Sweets 341 Fruits and Fruit Juices 328 Pork Products 328 Name: group, dtype: int64
Q:如何进行数据筛选和计数?
A:info_keys = ["description", "group", "id", "manufacturer"]定义了一个包含要从数据库中提取的信息的键的列表。
info = pd.DataFrame(db, columns=info_keys)使用info_keys作为列名,创建包含db数据的Pandas DataFrame对象,并将其存储在info变量中。
info.head()显示info DataFrame的前几行数据。info.info()显示info DataFrame的基本信息,包括列名、每列的非空值数量、每列的数据类型等。
pd.value_counts(info["group"])[:10]对info["group"]列中的每个唯一值进行计数,并返回计数结果的前10个值,即返回出现次数最多的前10个分组。
nutrients = [] # 创建一个空列表用于存储营养信息for rec in db:fnuts = pd.DataFrame(rec["nutrients"]) # 为每个记录创建一个包含营养信息的DataFrame对象fnuts["id"] = rec["id"] # 添加一个名为"id"的列,将记录的id值赋给该列的每个元素nutrients.append(fnuts) # 将每个记录的营养信息DataFrame添加到nutrients列表中nutrients = pd.concat(nutrients, ignore_index=True) # 将nutrients列表中的DataFrame对象合并为一个大的DataFrame,并重新索引行号nutrients
value | units | description | group | id | |
---|---|---|---|---|---|
0 | 25.180 | g | Protein | Composition | 1008 |
1 | 29.200 | g | Total lipid (fat) | Composition | 1008 |
2 | 3.060 | g | Carbohydrate, by difference | Composition | 1008 |
3 | 3.280 | g | Ash | Other | 1008 |
4 | 376.000 | kcal | Energy | Energy | 1008 |
... | ... | ... | ... | ... | ... |
389350 | 0.000 | mcg | Vitamin B-12, added | Vitamins | 43546 |
389351 | 0.000 | mg | Cholesterol | Other | 43546 |
389352 | 0.072 | g | Fatty acids, total saturated | Other | 43546 |
389353 | 0.028 | g | Fatty acids, total monounsaturated | Other | 43546 |
389354 | 0.041 | g | Fatty acids, total polyunsaturated | Other | 43546 |
nutrients.duplicated().sum() # 统计重复行的数量nutrients = nutrients.drop_duplicates() # 删除重复的行col_mapping = {"description" : "food","group" : "fgroup"}info = info.rename(columns=col_mapping, copy=False) # 重命名info DataFrame的列名为food和fgroupinfo.info() # 显示info DataFrame的基本信息col_mapping = {"description" : "nutrient","group" : "nutgroup"}nutrients = nutrients.rename(columns=col_mapping, copy=False) # 重命名nutrients DataFrame的列名为nutrient和nutgroupnutrients # 显示重命名后的nutrients DataFrame
<class 'pandas.core.frame.DataFrame'> RangeIndex: 6636 entries, 0 to 6635 Data columns (total 4 columns):# Column Non-Null Count Dtype --- ------ -------------- ----- 0 food 6636 non-null object1 fgroup 6636 non-null object2 id 6636 non-null int64 3 manufacturer 5195 non-null object dtypes: int64(1), object(3) memory usage: 207.5+ KB
value | units | nutrient | nutgroup | id | |
---|---|---|---|---|---|
0 | 25.180 | g | Protein | Composition | 1008 |
1 | 29.200 | g | Total lipid (fat) | Composition | 1008 |
2 | 3.060 | g | Carbohydrate, by difference | Composition | 1008 |
3 | 3.280 | g | Ash | Other | 1008 |
4 | 376.000 | kcal | Energy | Energy | 1008 |
... | ... | ... | ... | ... | ... |
389350 | 0.000 | mcg | Vitamin B-12, added | Vitamins | 43546 |
389351 | 0.000 | mg | Cholesterol | Other | 43546 |
389352 | 0.072 | g | Fatty acids, total saturated | Other | 43546 |
389353 | 0.028 | g | Fatty acids, total monounsaturated | Other | 43546 |
389354 | 0.041 | g | Fatty acids, total polyunsaturated | Other | 43546 |
ndata = pd.merge(nutrients, info, on="id") # 基于"id"列将nutrients和info两个DataFrame进行合并,并将结果存储在ndata中ndata.info() # 显示ndata DataFrame的基本信息ndata.iloc[30000] # 获取ndata DataFrame中索引为30000的行的数据
<class 'pandas.core.frame.DataFrame'> Int64Index: 375176 entries, 0 to 375175 Data columns (total 8 columns):# Column Non-Null Count Dtype --- ------ -------------- ----- 0 value 375176 non-null float641 units 375176 non-null object 2 nutrient 375176 non-null object 3 nutgroup 375176 non-null object 4 id 375176 non-null int64 5 food 375176 non-null object 6 fgroup 375176 non-null object 7 manufacturer 293054 non-null object dtypes: float64(1), int64(1), object(6) memory usage: 25.8+ MBvalue 0.04 units g nutrient Glycine nutgroup Amino Acids id 6158 food Soup, tomato bisque, canned, condensed fgroup Soups, Sauces, and Gravies manufacturer Name: 30000, dtype: object
fig = plt.figure() # 创建一个新的空白Figure对象,并将其赋值给变量figresult = ndata.groupby(["nutrient", "fgroup"])["value"].quantile(0.5) # 根据"nutrient"和"fgroup"列进行分组,计算"value"列的中位数,并将结果存储在result变量中
result["Zinc, Zn"].sort_values().plot(kind="barh") # 从result中选择"Zinc, Zn"列的数据,对数据进行排序,然后使用水平条形图进行可视化
by_nutrient = ndata.groupby(["nutgroup", "nutrient"]) # 根据"nutgroup"和"nutrient"列进行分组,将结果存储在by_nutrient变量中def get_maximum(x):return x.loc[x.value.idxmax()] # 定义一个函数get_maximum,用于获取每个分组中"value"列取得最大值的行max_foods = by_nutrient.apply(get_maximum)[["value", "food"]] # 对每个分组应用get_maximum函数,获取"value"列最大值所对应的行,并选择"value"和"food"两列max_foods["food"] = max_foods["food"].str[:50] # 将"food"列的字符串长度截取为最多50个字符max_foods.loc["Amino Acids"]["food"] # 从 max_foods DataFrame 中选择索引为 "Amino Acids" 的行,返回一个包含该行数据的 Series。从该 Series 中选择名为 "food" 的列,返回 "Amino Acids" 分类下食物名称的数据。
nutrient Alanine Gelatins, dry powder, unsweetened Arginine Seeds, sesame flour, low-fat Aspartic acid Soy protein isolate Cystine Seeds, cottonseed flour, low fat (glandless) Glutamic acid Soy protein isolate Glycine Gelatins, dry powder, unsweetened Histidine Whale, beluga, meat, dried (Alaska Native) Hydroxyproline KENTUCKY FRIED CHICKEN, Fried Chicken, ORIGINA... Isoleucine Soy protein isolate, PROTEIN TECHNOLOGIES INTE... Leucine Soy protein isolate, PROTEIN TECHNOLOGIES INTE... Lysine Seal, bearded (Oogruk), meat, dried (Alaska Na... Methionine Fish, cod, Atlantic, dried and salted Phenylalanine Soy protein isolate, PROTEIN TECHNOLOGIES INTE... Proline Gelatins, dry powder, unsweetened Serine Soy protein isolate, PROTEIN TECHNOLOGIES INTE... Threonine Soy protein isolate, PROTEIN TECHNOLOGIES INTE... Tryptophan Sea lion, Steller, meat with fat (Alaska Native) Tyrosine Soy protein isolate, PROTEIN TECHNOLOGIES INTE... Valine Soy protein isolate, PROTEIN TECHNOLOGIES INTE... Name: food, dtype: object
4.2012年联邦选举委员会数据库
美国联邦选举委员会公布了有关政治运动贡献的数据。这些数据包括捐赠者姓名、职业和雇主、地址和缴费金额。你可以尝试做以下分析:
1.按职业和雇主的捐赠统计;2.按捐赠金额统计;3.按州进行统计。
接下来我们将结合代码共同学习这一分析过程。本例题涉及以下知识点,重要处会有解释:
获取唯一值:
fec["cand_nm"].unique()
从fec
DataFrame的"cand_nm"列获取唯一的候选人姓名,并将结果存储在unique_cands
变量中。数据分组:
grouped = fec.groupby("cand_nm")
根据候选人姓名对fec
DataFrame进行分组。数据透视表:
by_occupation = fec.pivot_table("contb_receipt_amt", index="contbr_occupation", columns="party", aggfunc="sum")
使用pivot_table()
函数创建数据透视表,对"contb_receipt_amt"列进行求和聚合,以"contbr_occupation"为行索引,以"party"为列索引。可视化:
over_2mm.plot(kind="barh")
对DataFrame进行可视化,例如水平条形图。数据映射:使用字典对列中的值进行映射,例如
fec["contbr_occupation"].map(get_occ)
使用自定义函数get_occ
将"contbr_occupation"列中的值进行映射。数据堆叠和展开:
grouped.size().unstack(level=0)
计算每个候选人在不同区间标签下的数据量,并将结果转换为宽格式,以候选人姓名为列。数据透视表和缺失值填充:
totals = grouped["contb_receipt_amt"].sum().unstack(level=0).fillna(0)
计算每个候选人在不同州的总捐款金额,将结果转换为宽格式,并用0填充缺失值。数据归一化和比例计算:
percent = totals.div(totals.sum(axis="columns"), axis="index")
对每个州的总捐款金额进行归一化,以每行的总和作为除数,计算归一化后的比例。
fec = pd.read_csv("datasets/fec/P00000001-ALL.csv", low_memory=False) # 从CSV文件中读取数据,并将结果存储在fec变量中,low_memory参数设置为False以确保读取所有数据fec.info() # 显示fec DataFrame的基本信息fec.iloc[123456] # 获取fec DataFrame中索引为123456的行的数据
<class 'pandas.core.frame.DataFrame'> RangeIndex: 1001731 entries, 0 to 1001730 Data columns (total 16 columns):# Column Non-Null Count Dtype --- ------ -------------- ----- 0 cmte_id 1001731 non-null object 1 cand_id 1001731 non-null object 2 cand_nm 1001731 non-null object 3 contbr_nm 1001731 non-null object 4 contbr_city 1001712 non-null object 5 contbr_st 1001727 non-null object 6 contbr_zip 1001620 non-null object 7 contbr_employer 988002 non-null object 8 contbr_occupation 993301 non-null object 9 contb_receipt_amt 1001731 non-null float6410 contb_receipt_dt 1001731 non-null object 11 receipt_desc 14166 non-null object 12 memo_cd 92482 non-null object 13 memo_text 97770 non-null object 14 form_tp 1001731 non-null object 15 file_num 1001731 non-null int64 dtypes: float64(1), int64(1), object(14) memory usage: 122.3+ MBcmte_id C00431445 cand_id P80003338 cand_nm Obama, Barack contbr_nm ELLMAN, IRA contbr_city TEMPE contbr_st AZ contbr_zip 852816719 contbr_employer ARIZONA STATE UNIVERSITY contbr_occupation PROFESSOR contb_receipt_amt 50.0 contb_receipt_dt 01-DEC-11 receipt_desc NaN memo_cd NaN memo_text NaN form_tp SA17A file_num 772372 Name: 123456, dtype: object
unique_cands = fec["cand_nm"].unique() # 从fec DataFrame的"cand_nm"列获取唯一的候选人姓名,将结果存储在unique_cands变量中
unique_cands # 显示unique_cands数组,即唯一的候选人姓名列表
unique_cands[2] # 获取unique_cands数组中索引为2的元素,即第三个候选人的姓名
parties = {"Bachmann, Michelle": "Republican","Cain, Herman": "Republican","Gingrich, Newt": "Republican","Huntsman, Jon": "Republican","Johnson, Gary Earl": "Republican","McCotter, Thaddeus G": "Republican","Obama, Barack": "Democrat","Paul, Ron": "Republican","Pawlenty, Timothy": "Republican","Perry, Rick": "Republican","Roemer, Charles E. 'Buddy' III": "Republican","Romney, Mitt": "Republican","Santorum, Rick": "Republican"}
# 设置党派
fec["cand_nm"][123456:123461] # 获取fec DataFrame中"cand_nm"列索引为123456到123460的行的数据
fec["cand_nm"][123456:123461].map(parties) # 对索引为123456到123460的"cand_nm"列的数据应用parties字典,将候选人姓名映射为对应的党派
fec["party"] = fec["cand_nm"].map(parties) # 将通过parties字典映射后的党派信息添加为fec DataFrame的一个新列,列名为"party"
fec["party"].value_counts() # 统计"party"列中每个党派的数量,并返回计数结果
Democrat 593746 Republican 407985 Name: party, dtype: int64
(fec["contb_receipt_amt"] > 0).value_counts() # 统计"contb_receipt_amt"列中大于0的值的数量和小于等于0的值的数量
True 991475 False 10256 Name: contb_receipt_amt, dtype: int64
fec = fec[fec["contb_receipt_amt"] > 0] # 从fec DataFrame中筛选出"contb_receipt_amt"列大于0的行,并将结果重新赋值给fec变量fec_mrbo = fec[fec["cand_nm"].isin(["Obama, Barack", "Romney, Mitt"])] # 从fec DataFrame中筛选出"cand_nm"列包含"Obama, Barack"或"Romney, Mitt"的行,并将结果赋值给fec_mrbo变量fec["contbr_occupation"].value_counts()[:10] # 统计"contbr_occupation"列中各个职业的数量,并返回前10个结果
RETIRED 233990 INFORMATION REQUESTED 35107 ATTORNEY 34286 HOMEMAKER 29931 PHYSICIAN 23432 INFORMATION REQUESTED PER BEST EFFORTS 21138 ENGINEER 14334 TEACHER 13990 CONSULTANT 13273 PROFESSOR 12555 Name: contbr_occupation, dtype: int64
occ_mapping = {"INFORMATION REQUESTED PER BEST EFFORTS" : "NOT PROVIDED","INFORMATION REQUESTED" : "NOT PROVIDED","INFORMATION REQUESTED (BEST EFFORTS)" : "NOT PROVIDED","C.E.O.": "CEO"
} # 映射 “前” 为 “后”def get_occ(x):# 如果映射未提供,则返回 xreturn occ_mapping.get(x, x)fec["contbr_occupation"] = fec["contbr_occupation"].map(get_occ) # 使用 get_occ 函数将 "contbr_occupation" 列中的值进行映射
emp_mapping = {"INFORMATION REQUESTED PER BEST EFFORTS" : "NOT PROVIDED","INFORMATION REQUESTED" : "NOT PROVIDED","SELF" : "SELF-EMPLOYED","SELF EMPLOYED" : "SELF-EMPLOYED",
} # 映射 “前” 为 “后”def get_emp(x):# 如果映射未提供,则返回 xreturn emp_mapping.get(x, x)fec["contbr_employer"] = fec["contbr_employer"].map(get_emp) # 使用 get_emp 函数将 "contbr_employer" 列中的值进行映射
by_occupation = fec.pivot_table("contb_receipt_amt", # 使用"contb_receipt_amt"列作为值进行透视index="contbr_occupation", # 使用"contbr_occupation"列作为行索引columns="party", # 使用"party"列作为列索引aggfunc="sum") # 对值进行求和聚合over_2mm = by_occupation[by_occupation.sum(axis="columns") > 2000000] # 选择总和大于2000000的行并赋值给over_2mm变量over_2mm # 显示over_2mm DataFrame
party | Democrat | Republican |
---|---|---|
contbr_occupation | ||
ATTORNEY | 11141982.97 | 7477194.43 |
CEO | 2074974.79 | 4211040.52 |
CONSULTANT | 2459912.71 | 2544725.45 |
ENGINEER | 951525.55 | 1818373.70 |
EXECUTIVE | 1355161.05 | 4138850.09 |
HOMEMAKER | 4248875.80 | 13634275.78 |
INVESTOR | 884133.00 | 2431768.92 |
LAWYER | 3160478.87 | 391224.32 |
MANAGER | 762883.22 | 1444532.37 |
NOT PROVIDED | 4866973.96 | 20565473.01 |
OWNER | 1001567.36 | 2408286.92 |
PHYSICIAN | 3735124.94 | 3594320.24 |
PRESIDENT | 1878509.95 | 4720923.76 |
PROFESSOR | 2165071.08 | 296702.73 |
REAL ESTATE | 528902.09 | 1625902.25 |
RETIRED | 25305116.38 | 23561244.49 |
SELF-EMPLOYED | 672393.40 | 1640252.54 |
plt.figure() # 创建一个新的空白Figure对象over_2mm.plot(kind="barh") # 对over_2mm DataFrame进行水平条形图的可视化
def get_top_amounts(group, key, n=5):totals = group.groupby(key)["contb_receipt_amt"].sum() # 对group中的数据按key进行分组,计算每个组中"contb_receipt_amt"列的总和return totals.nlargest(n) # 返回总和最大的前n个组grouped = fec_mrbo.groupby("cand_nm") # 根据候选人姓名对fec_mrbo DataFrame进行分组grouped.apply(get_top_amounts, "contbr_occupation", n=7) # 对分组后的数据应用get_top_amounts函数,按"contbr_occupation"列获取每个组的前7个最大总和grouped.apply(get_top_amounts, "contbr_employer", n=10) # 对分组后的数据应用get_top_amounts函数,按"contbr_employer"列获取每个组的前10个最大总和
cand_nm contbr_employer Obama, Barack RETIRED 22694358.85SELF-EMPLOYED 17080985.96NOT EMPLOYED 8586308.70INFORMATION REQUESTED 5053480.37HOMEMAKER 2605408.54SELF 1076531.20SELF EMPLOYED 469290.00STUDENT 318831.45VOLUNTEER 257104.00MICROSOFT 215585.36 Romney, Mitt INFORMATION REQUESTED PER BEST EFFORTS 12059527.24RETIRED 11506225.71HOMEMAKER 8147196.22SELF-EMPLOYED 7409860.98STUDENT 496490.94CREDIT SUISSE 281150.00MORGAN STANLEY 267266.00GOLDMAN SACH & CO. 238250.00BARCLAYS CAPITAL 162750.00H.I.G. CAPITAL 139500.00 Name: contb_receipt_amt, dtype: float64
bins = np.array([0, 1, 10, 100, 1000, 10000, 100_000, 1_000_000, 10_000_000]) # 定义一个包含分箱边界值的NumPy数组,用于将"contb_receipt_amt"列的值分成不同的区间labels = pd.cut(fec_mrbo["contb_receipt_amt"], bins) # 使用pd.cut函数根据指定的分箱边界将"contb_receipt_amt"列的值进行分箱,并返回一个包含对应区间标签的Serieslabels # 显示labels Series,即包含了每个"contb_receipt_amt"值所属的区间标签
411 (10, 100] 412 (100, 1000] 413 (100, 1000] 414 (10, 100] 415 (10, 100]... 701381 (10, 100] 701382 (100, 1000] 701383 (1, 10] 701384 (10, 100] 701385 (100, 1000] Name: contb_receipt_amt, Length: 694282, dtype: category Categories (8, interval[int64, right]): [(0, 1] < (1, 10] < (10, 100] < (100, 1000] < (1000, 10000] < (10000, 100000] < (100000, 1000000] < (1000000, 10000000]]
grouped = fec_mrbo.groupby(["cand_nm", labels]) # 根据候选人姓名和labels对fec_mrbo DataFrame进行分组grouped.size().unstack(level=0) # 计算每个候选人在不同区间标签下的数据量,并将结果转换为宽格式(以候选人姓名为列),并显示该结果
cand_nm | Obama, Barack | Romney, Mitt |
---|---|---|
contb_receipt_amt | ||
(0, 1] | 493 | 77 |
(1, 10] | 40070 | 3681 |
(10, 100] | 372280 | 31853 |
(100, 1000] | 153991 | 43357 |
(1000, 10000] | 22284 | 26186 |
(10000, 100000] | 2 | 1 |
(100000, 1000000] | 3 | 0 |
(1000000, 10000000] | 4 |
plt.figure() # 创建一个新的空白Figure对象bucket_sums = grouped["contb_receipt_amt"].sum().unstack(level=0) # 计算每个候选人在不同区间标签下的"contb_receipt_amt"列的总和,并转换为宽格式(以候选人姓名为列)normed_sums = bucket_sums.div(bucket_sums.sum(axis="columns"), axis="index") # 对每个候选人在不同区间标签下的总和进行归一化,以每行的总和作为除数,计算归一化后的比例normed_sums # 显示归一化后的比例结果normed_sums[:-2].plot(kind="barh") # 对前面除去最后两行的归一化比例结果进行水平条形图的可视化
grouped = fec_mrbo.groupby(["cand_nm", "contbr_st"]) # 根据候选人姓名和捐赠者所在州(contbr_st)对fec_mrbo DataFrame进行分组totals = grouped["contb_receipt_amt"].sum().unstack(level=0).fillna(0) # 计算每个候选人在不同州的总捐款金额,将结果转换为宽格式(以候选人姓名为列),并用0填充缺失值totals = totals[totals.sum(axis="columns") > 100000] # 筛选出总捐款金额超过100000的行totals.head(10) # 显示前10行的totals DataFrame
cand_nm | Obama, Barack | Romney, Mitt |
---|---|---|
contbr_st | ||
AK | 281840.15 | 86204.24 |
AL | 543123.48 | 527303.51 |
AR | 359247.28 | 105556.00 |
AZ | 1506476.98 | 1888436.23 |
CA | 23824984.24 | 11237636.60 |
CO | 2132429.49 | 1506714.12 |
CT | 2068291.26 | 3499475.45 |
DC | 4373538.80 | 1025137.50 |
DE | 336669.14 | 82712.00 |
FL | 7318178.58 | 8338458.81 |
percent = totals.div(totals.sum(axis="columns"), axis="index") # 对每个州的总捐款金额进行归一化,以每行的总和作为除数,计算归一化后的比例percent.head(10) # 显示前10行的percent DataFrame,即每个州的归一化比例结果
cand_nm | Obama, Barack | Romney, Mitt |
---|---|---|
contbr_st | ||
AK | 0.765778 | 0.234222 |
AL | 0.507390 | 0.492610 |
AR | 0.772902 | 0.227098 |
AZ | 0.443745 | 0.556255 |
CA | 0.679498 | 0.320502 |
CO | 0.585970 | 0.414030 |
CT | 0.371476 | 0.628524 |
DC | 0.810113 | 0.189887 |
DE | 0.802776 | 0.197224 |
FL | 0.467417 | 0.532583 |
《利用Python进行数据分析》示例相关推荐
- 【赠书】pandas创始人手把手教你利用Python进行数据分析
周末就要到了,本次给大家赠送5本Python技术书籍,这次赠送的书籍是<利用Python进行数据分析>. 这是一本什么样的书 Python是目前数据科学领域的王者语言,众多科学家.工程师. ...
- 利用Python进行数据分析--数据聚合与分组运算
转载自:http://blog.csdn.net/ssw_1990/article/details/22422971 1.quantile计算Series或DataFrame列的样本分位数: [pyt ...
- 数据基础---《利用Python进行数据分析·第2版》第8章 数据规整:聚合、合并和重塑
之前自己对于numpy和pandas是要用的时候东学一点西一点,直到看到<利用Python进行数据分析·第2版>,觉得只看这一篇就够了.非常感谢原博主的翻译和分享. 在许多应用中,数据可能 ...
- 数据基础---《利用Python进行数据分析·第2版》第12章 pandas高级应用
之前自己对于numpy和pandas是要用的时候东学一点西一点,直到看到<利用Python进行数据分析·第2版>,觉得只看这一篇就够了.非常感谢原博主的翻译和分享. 前面的章节关注于不同类 ...
- 数据基础---《利用Python进行数据分析·第2版》第11章 时间序列
之前自己对于numpy和pandas是要用的时候东学一点西一点,直到看到<利用Python进行数据分析·第2版>,觉得只看这一篇就够了.非常感谢原博主的翻译和分享. 时间序列(time s ...
- 整理总结:利用Python进行数据分析及思维导图
参考资料:机械工业出版社的<利用Python进行数据分析>(思维导图在最后面) 本篇目录 参考资料:机械工业出版社的<利用Python进行数据分析>(思维导图在最后面) 第一章 ...
- 《利用python进行数据分析》读书笔记
<利用python进行数据分析>是一本利用python的Numpy.Pandas.Matplotlib库进行数据分析的基础介绍,非常适合初学者. 重要的python库 NumPy http ...
- 《利用Python 进行数据分析》第八章:绘图和可视化
对<利用Python 进行数据分析>(Wes Mckinney著)一书中的第八章中绘图和可视化进行代码实验.原书中采用的是Python2.7,而我采用的Python3.7在Pycharm调 ...
- 利用Python进行数据分析:数据规整(基于DataFrame)
利用Python进行数据分析:数据规整 在许多应用中,数据可能分散在许多文件或数据库中,存储的形式也不利于分析.本部分关注可以聚合.合并.重塑数据的方法. 文章目录 利用Python进行数据分析:数据 ...
- 利用Python进行数据分析(学习笔记)
第壹章 准备工作 1.1 本书内容 1.1.1 什么类型的数据 1.2 为何利用Python进行数据分析 1.2.1 Python作为胶水 1.2.2 解决"双语言"难题 1.2. ...
最新文章
- php定义枚举,PHP中Enum(枚举)用法实例详解
- echarts tab切换_Python 数据可视化实战:使用 PyQt5 和 Echarts 打造股票数据看板
- 【POJ - 1486】Sorting Slides(思维建图,二分图求必须边,关建边,图论)
- linux sd卡空间,充分利用树莓派中的SD卡空间
- serve注解是加在哪个类_不会 Java 注解 ? 看这一篇文章!
- 深度学习2.0-45.GAN实战
- js中常遇到 切割截取字符串的几种方法
- AE新知识-10月30日
- SPI通信协议详解(四)
- 110KV降压变电所电气一次部分及防雷保护设计
- 北京科技大学C语言锐格答案,北京科技大学软件课程设计作业.pdf
- 服务器外链图片不显示,nginx服务器设置图片防盗链,禁止图片外链
- react-native 关闭黄色警告
- 新浪和腾讯微博教程(一)
- [MFC]MFC的BUTTON控件响应鼠标按下和抬起
- kaldi学习笔记-三音素训练2
- Clojure CLR 入门
- L3-008 喊山 (30 分)(bfs)
- Rust之枚举和模式匹配(二):控制流程结构match
- jsp页面显示源码实现
热门文章
- Python基础考试及答案
- 微信公众平台如何设置欢迎信息
- Vue中使用Vue-Router管理路由
- (详解)人才测评工具和人才测评方法
- 新年愿望——天下无贼
- 矢量图和位图最大的区别是什么?
- Access denied for user ‘***‘@‘localhost‘ (using password: YES)
- win7服务器如何还原系统教程视频,win7如何进入系统还原教程
- 微信网页分享踩过的坑
- Linux: hardware: iommu;Device is ineligible for IOMMU