文章目录
前言
在学习pandas以及matplotlib库用法的过程中,尝试了对数据进行处理以及可视化,在此记录下近期实例,以期复习使用
一、包的导入
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
本文内容主要使用以上库,并进行了缩写,以下开始分题讲解
二、MoviesLens 1M数据集
1.数据集概述:
GroupLens实验室提供了一些从MoviesLens用户那里收集的20世纪90年代末到21世纪初的电影评分数据的集合。这些数据提供了电影的评分、流派、年份和观众数据(年龄、邮编、性别、职业)。 MovisLens1M数据集包含6000个用户对4000部电影的100万个评分。数据分布在三个表格之中:分别包含评分、用户信息和电影信息。
2.文件代码及解读:
unames = ["user_id", "gender", "age", "occupation", "zip"]
users = pd.read_table("datachuli\movielens\users.dat", sep="::",
header=None, names=unames, engine="python")
rnames = ["user_id", "movie_id", "rating", "timestamp"]
ratings = pd.read_table("datachuli\movielens\ratings.dat", sep="::",
header=None, names=rnames, engine="python")
mnames = ["movie_id", "title", "genres"]
movies = pd.read_table("datachuli\movielens\movies.dat", sep="::",
header=None, names=mnames, engine="python")
首先定义三个列表,分别是关于用户、数据比率,电影,然后对应三个列表元素作为索引读入关于三者的文件,并将列表元素作为索引,生成三个二维的DataFrame。
users.head(5)
ratings.head(5)
movies.head(5)
ratings
其次利用head()去读这三个DataFrame的头五个元素,得如下结果:
data = pd.merge(pd.merge(ratings, users), movies)
data
data.iloc[0]
使用merge函数将三个表合并成一个表,data然后打印第0行数据。
mean_ratings = data.pivot_table("rating", index="title",
columns="gender", aggfunc="mean")
.mean_ratings.head(5)
将电影名称作为索引,以性别为列计算每个电影的比率的均值,并且查看前五个。
ratings_by_title = data.groupby("title").size()
ratings_by_title.head()
active_titles = ratings_by_title.index[ratings_by_title >= 250]
active_titles
将数据集按照电影名称分组,然后查看评分数量的前几个结果,然后用 active_titles去记录评分数量大于等于250.
mean_ratings = mean_ratings.loc[active_titles]
mean_ratings
使用loc方法mean_ratingsDataFrame中选择active_titles的行。然后,您通过打印mean_ratings来查看结果。
mean_ratings = mean_ratings.rename(index={"Seven Samurai (The Magnificent Seven) (Shichinin no samurai) (1954)":
"Seven Samurai (Shichinin no samurai) (1954)"})
top_female_ratings = mean_ratings.sort_values("F", ascending=False)
top_female_ratings.head()
重命名mean_ratingsDataFrame中的一个索引并将其重命名为"Seven Samurai (Shichinin no samurai) (1954)"然后,使用sort_values()方法根据女性评分(“F”)对 mean_ratings进行排序,并使用head()方法查看前几行结果。
mean_ratings["diff"] = mean_ratings["M"] - mean_ratings["F"]
sorted_by_diff = mean_ratings.sort_values("diff")
sorted_by_diff.head()
将男女评分的差距写在新列中,并且排序并输出前几行。
sorted_by_diff[::-1].head()
rating_std_by_title = data.groupby("title")["rating"].std()
rating_std_by_title = rating_std_by_title.loc[active_titles]
rating_std_by_title.head()
表逆序排列。
将数据集按照电影名字分组并计算比率的方差,然后输出前几行
rating_std_by_title.sort_values(ascending=False)[:10]
将之前的数据集排序并输出前十行
movies["genres"].head()
movies["genres"].head().str.split("|")
movies["genre"] = movies.pop("genres").str.split("|")
movies.head()
处理movies的数据集,将其genres列按|分裂,然后储存到新列genre中
movies_exploded = movies.explode("genre")
movies_exploded[:10]
将movies的genre列展开成多行,并输出前十列。
ratings_with_genre = pd.merge(pd.merge(movies_exploded, ratings), users)
ratings_with_genre.iloc[0]
genre_ratings = (ratings_with_genre.groupby(["genre", "age"])
["rating"].mean()
.unstack("age"))
genre_ratings[:10]
使用pd.merge()函数将movies_exploded、ratings和users进行合并,然后,通过使用.iloc[0]打印第一行数据。使用groupby()函数按genre和age对ratings_with_genre进行分组,计算每组中rating列的均值,并使用.unstack(“age”)进行数据重塑,将age作为列索引。最后,使用[:10]打印前10行结果。
3.可视化拓展:
genre_ratings.plot(kind="bar", stacked=True, figsize=(10, 6))
plt.title("Average Ratings by Genre and Age")
plt.xlabel("Genre")
plt.ylabel("Average Rating")
plt.show()
根据分析出来的各个年龄层之间的对电影中类类型的数据做了统计图
三、美国1880-2010年的婴儿名字
1.数据集概述:
美国社会保障局(SSA)提供了从1880年至现在的婴儿姓名频率的数据。可以使用这些数据做很多事情:
根据给定的名字对婴儿名字随时间的比例进行可视化
确定一个名字的相对排位
确定每年最受欢迎的名字,或者流行程度最高或最低的名字
2.代码解读及演示:
2.1导包
与最初相同 若从头开始不必查看
#!head -n 10 datasets/babynames/yob1880.txt
import numpy as np
import pandas as pd
2.2 读取数据
names=["name", "sex", "births"])
names1880
2.3 数据处理:
names1880.groupby("sex")["births"].sum()#男女各出生多少人
pieces = []
for year in range(1880, 2011):
path = f"datasets/babynames/yob{year}.txt"
frame = pd.read_csv(path, names=["name", "sex", "births"])#读取从1880到2010婴儿出生数据
# Add a column for the year
frame["year"] = year
#display(frame)
pieces.append(frame)#合成大dataframe集合
# Concatenate everything into a single DataFrame
names = pd.concat(pieces, ignore_index=True)#合成一个dataframe
#pieces
#names
total_births = names.pivot_table("births", index="year",
columns="sex", aggfunc=sum)#求不同year条件下不同sex的婴儿出生人数
total_births.tail()#取样
total_births.plot(title="Total births by sex and year")
def add_prop(group):
group["prop"] = group["births"] / group["births"].sum()#出生人数占总出生人数的比例
return group
names = names.groupby(["year","sex"],group_keys=False).apply(add_prop)
#按出生年份,性别分别计算
names.groupby(["year", "sex"])["prop"].sum()
def get_top1000(group):
return group.sort_values("births", ascending=False)[:1000]#返回排序后的1000行数据
grouped = names.groupby(["year", "sex"])
top1000 = grouped.apply(get_top1000)
top1000.index
p1000 = top1000.reset_index(drop=True)#启用新索引,删除旧索引
top1000.head()
#top1000.tail()
boys = top1000[top1000["sex"] == "M"]#男女数据分类
girls = top1000[top1000["sex"] == "F"]
boys
#top1000=top1000.rename_axis('year_id')
total_births = top1000.pivot_table("births",
columns="name",
index='year',
aggfunc=sum)#按照出生年份不同展示各个名字的出生人数
total_births
total_births.info()#表信息
subset = total_births[["John", "Harry", "Mary", "Marilyn"]]
subset.plot(subplots=True, figsize=(12, 10),#分开展示四个名字的变化趋势
title="Number of births per year")
plt.figure()
table = top1000.pivot_table("prop", index="year",
columns="sex", aggfunc=sum)#以年为索引,展示各个性别的出生人数比例
table
table.plot(title="Sum of table1000.prop by year and sex",
yticks=np.linspace(0, 1.2, 13))
df = boys[boys["year"] == 2010]#2010 boy相关数据
df
prop_cumsum = df["prop"].sort_values(ascending=False).cumsum()#累积求和
prop_cumsum[:10]
prop_cumsum.searchsorted(0.5)#看比例达到0.5的有几个
输出116
df = boys[boys.year == 1900]
in1900 = df.sort_values("prop", ascending=False).prop.cumsum()
in1900.searchsorted(0.5) + 1#看1900累积达到0.5的有几
输出25
def get_quantile_count(group, q=0.5):
group = group.sort_values("prop", ascending=False)
return group.prop.cumsum().searchsorted(q) + 1#计算累积达到0.5比例的有几个
diversity = top1000.groupby(["year", "sex"]).apply(get_quantile_count)#看各年份达到0.5的有几个
diversity = diversity.unstack()#转化二维
fig = plt.figure()
diversity.head()
diversity.plot(title="Number of popular names in top 50%")
def get_last_letter(x):
return x[-1]
last_letters = names["name"].map(get_last_letter)#名字的最后一个字母
last_letters.name = "last_letter"
table = names.pivot_table("births", index=last_letters,
columns=["sex", "year"], aggfunc=sum)
subtable.head()
subtable.sum()
letter_prop = subtable / subtable.sum()
letter_prop#求比例
import matplotlib.pyplot as plt
fig, axes = plt.subplots(2, 1, figsize=(10, 8))
letter_prop["M"].plot(kind="bar", rot=0, ax=axes[0], title="Male")
letter_prop["F"].plot(kind="bar", rot=0, ax=axes[1], title="Female",
legend=False)#直方图分析名字最后一个字母的比例
letter_prop = table / table.sum()
dny_ts = letter_prop.loc[["d", "n", "y"], "M"].T#选择d,n,y行,M列
dny_ts.head()
all_names = pd.Series(top1000["name"].unique())
lesley_like = all_names[all_names.str.contains("Lesl")]#包含某一字段的所有名字
lesley_like
filtered = top1000[top1000["name"].isin(lesley_like)]
filtered.groupby("name")["births"].sum()#这些名字的婴儿一共出生多少
table = filtered.pivot_table("births", index="year",
columns="sex", aggfunc="sum")#这些名字的婴儿按年龄,分性别表示出生人数
table = table.div(table.sum(axis="columns"), axis="index")
table.tail()
fig = plt.figure()
table.plot(style={"M": "k-", "F": "k--"})
四、美国农业部视频数据库
1.数据集概述:
美国农业部提供了食物营养信息数据库。每种事务都有一些识别属性以及两份营养元素和营养比例的列表。这种形式的数据不适合分析,所以需要做一些工作将数据转换成更好的形式。
2.代码解读及演示:
import json
import pandas as pd
import matplotlib.pyplot as plt
db = json.load(open("datasets/usda_food/database.json"))
len(db)#导入文件 查看文件长度
通过json获得数据文件,并查看长度,长度为6636
db[0].keys()#获取键值
db[0]["nutrients"][0]#获取营养标签下的第一个部分
nutrients = pd.DataFrame(db[0]["nutrients"])#将全体内容传入新的表格中
nutrients.head(7)#查看前七行
得如下结果:
info_keys = ["description", "group", "id", "manufacturer"]#设置信息种类
info = pd.DataFrame(db, columns=info_keys)#重写表格 修改键值
info.head()
数据格式不佳,重写表格并修改键值,设立id为之后使用进行铺垫
info.info()#显示信息
pd.value_counts(info["group"])[:10]#切片显示群组数量前十的信息
分别查看信息进行确认
nutrients = []#创建空列表
for rec in db:#第二次重写
fnuts = pd.DataFrame(rec["nutrients"])
fnuts["id"] = rec["id"]
nutrients.append(fnuts)
nutrients = pd.concat(nutrients, ignore_index=True)#确认索引连续
以营养成分为组织索引进行表格的建立
print(nutrients.duplicated().sum()) #计算重复行的数量
nutrients = nutrients.drop_duplicates()#移除重复行
通过duplicated函数查看重复行以及将重复的行移除,在通过查看确认移除成功
col_mapping = {"description" : "food",
"group" : "fgroup"}#定义字典
info = info.rename(columns=col_mapping, copy=False)#重命名
info.info()#查看信息
col_mapping = {"description" : "nutrient",
"group" : "nutgroup"}
nutrients = nutrients.rename(columns=col_mapping, copy=False)#重命名
nutrients#查看列表
分别对两个dateframe进行索引的重命名,重命名方法为建立字典并使用rename进行。查看确认
ndata = pd.merge(nutrients, info, on="id")#以id为主键对其进行合并
ndata.info()#查看ndata信息
ndata.iloc[30000]#返回第三千行的信息
通过id将其表格进行合并,以期望在一个表格中得到更多的信息。
查看结果
by_nutrient = ndata.groupby(["nutgroup", "nutrient"])#分组为植物类和营养
#定义取值函数
def get_maximum(x):
return x.loc[x.value.idxmax()]
#找到坚果类中含营养类较多的食物
max_foods = by_nutrient.apply(get_maximum)[["value", "food"]]
# make the food a little smaller
max_foods["food"] = max_foods["food"].str[:50]#取前五十
print(max_foods["food"])
通过索引进行组织,并建立最值函数,依次确认最大的值并进行查看
max_foods.loc["Amino Acids"]["food"]#获取amino acids 对应的食物列
得到其中一种营养素对应的食物信息
3.可视化拓展:
fig = plt.figure()#创建画布
result = ndata.groupby(["nutrient", "fgroup"])["value"].quantile(0.5)
result["Zinc, Zn"].sort_values().plot(kind="barh")
对 ndata进行分组操作,并计算每个组合中 value的中位数,结果存储在result 选择了 “Zinc, Zn”,对其排序以水平条形图绘制。
找到了含锌较多的食物
五、2012年联邦选举委员会数据库
5.1处理
美国联邦选举委员会公布了有关政治运动贡献的数据。这些数据包括捐赠者姓名、职业和雇主、地址和缴费金额。你可以尝试做一下的分析:
1.按职业和雇主的捐赠统计
2.按捐赠金额统计
3.按州进行统计
首先我们先导入数据并查看一下数据的基本信息
fec = pd.read_csv("datasets/fec/P00000001-ALL.csv", low_memory=False)
fec.info()
可以看到具体信息如下
<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 float64
10 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+ MB
使用此代码
fec.iloc[123456]
我们可以看到第123456行的全部信息,信息如下
cmte_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函数将所有的候选人的信息唯一的存取下来。
unique_cands = fec["cand_nm"].unique()
unique_cands
unique_cands[2]
使用上面的代码可以看到第三个候选人的名字,当然,我们也可以使用print(unique_cands)来看到所有候选人的名字
如果我们想要知道在这张表里美国各个党派的候选人所出现的次数,我们还需要一张记录候选人以及候选人所属党派的表。表单如下(使用parties来存储这个信息):
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["party"] = fec["cand_nm"].map(parties)#映射
fec["party"].value_counts()#计算次数
通过value_counts()这个函数的功能我们还可以统计捐款超过0元的次数(返还金额的时候捐款金额即为负数),即(fec[“contb_receipt_amt”] > 0) .value_counts()
通过isin()函数我们还能找到所有符合条件的行,比如,如果我们想要查找候选人为"Obama, Barack"和"Romney, Mitt"的行,我们可以使用fec_mrbo = fec[fec[“cand_nm”].isin([“Obama, Barack”, “Romney, Mitt”])]来找到所有符合条件的行。
5.2统计各个职业的捐款信息
首先我们需要通过透视表来获得各个职业的捐款金额,并通过透视表显示出来,代码如下:
by_occupation = fec.pivot_table("contb_receipt_amt",
index="contbr_occupation",
columns="party", aggfunc="sum")
fec.pivot_table("contb_receipt_amt", index="contbr_occupation", columns="party", aggfunc="sum")
将数据集进行透视操作,以 “contbr_occupation” 作为行索引(index),“party” 作为列索引(columns),“contb_receipt_amt” 作为值(values),使用 “sum” 作为聚合函数(aggfunc)。透视表将统计每个职业在不同政党下的捐款总金额。
接下来进一步进行处理
over_2mm = by_occupation[by_occupation.sum(axis="columns") > 2000000]
通过这一步操作,我们可以根据上一步得到的透视表 by_occupation,对每个职业的捐款金额进行行求和,然后筛选出总捐款金额超过200万美元的职业。将符合条件的结果存储在名为 over_2mm 的新变量中。
over_2mm.plot(kind="barh")
然后我们通过绘图就可以直观的得到各个职业在各个政党的捐款情况
5.3统计候选人里雇主和职业的捐款信息
因为捐款信息过于的多,所以我们需要将捐款信息只保留前N高的捐款信息即可,此处我们定义一个函数
def get_top_amounts(group, key, n=5):
totals = group.groupby(key)["contb_receipt_amt"].sum()
return totals.nlargest(n)
通过这个函数,我们能对group进行分组并在key上进行累加捐款金额并返回前n大的值,接下来我妹妹就可以通过调用这个函数来返回对应的信息了
grouped = fec_mrbo.groupby("cand_nm")
grouped.apply(get_top_amounts, "contbr_occupation", n=7)
grouped.apply(get_top_amounts, "contbr_employer", n=12)
通过上面的代码,我们可以返回候选人旗下的职业和雇主的捐款最多的前n个数据。
5.4统计各个区间的捐款情况并按州统计
我们还可以统计各个区间的捐款金额
生成一个numpy数组,分割各个捐款的区间
bins = np.array([0, 1, 10, 100, 1000, 10000,
100_000, 1_000_000, 10_000_000])
labels = pd.cut(fec_mrbo["contb_receipt_amt"], bins)
通过捐款的区间进行分组,并计算每个组的大小,最后,.unstack(level=0)将结果重新排列成一个新的数据框,其中每个唯一的"cand_nm"值成为列的名称,每个组的大小成为相应的值。
grouped = fec_mrbo.groupby(["cand_nm", labels])
grouped.size().unstack(level=0)
绘制图案便于直观观察
bucket_sums = grouped["contb_receipt_amt"].sum().unstack(level=0)
normed_sums = bucket_sums.div(bucket_sums.sum(axis="columns"),
axis="index")
normed_sums#计算比例
normed_sums[:-2].plot(kind="barh")
选出totals中大于100000的数据(州里捐款总额大于100000的)并重新排列成新的数据框
grouped = fec_mrbo.groupby(["cand_nm", "contbr_st"])
totals = grouped["contb_receipt_amt"].sum().unstack(level=0).fillna(0)
totals = totals[totals.sum(axis="columns") > 100000]
totals.head(10)
求和后展示前十行
percent = totals.div(totals.sum(axis="columns"), axis="index")
percent.head(10)
后记
感谢多位小伙伴的支持,若有资料代码等问题,可于留言区探讨。