一、前期準備
三個包:Numpy、Pandas和matplotlib;工具:jupyter notebook。首先確保導入這兩個包
#導入Numpy包
import numpy as np
#導入Pandas包
import pandas as pd
二、基礎(chǔ)知識
Pandas有三種數(shù)據(jù)結(jié)構(gòu):Series、DataFrame和Panel。Series類似于一維數(shù)組;DataFrame是類似表格的二維數(shù)組;Panel可以視為Excel的多表單Sheet。
1.read_table
read_table(filepath_or_buffer, sep=False, delimiter=None, header=’infer’, names=None, index_col=None, usecols=None, squeeze=False, prefix=None, mangle_dupe_cols=True, dtype=None, engine=None, converters=None, true_values=None, false_values=None, skipinitialspace=False, skiprows=None, skipfooter=0, nrows=None, na_values=None, keep_default_na=True, na_filter=True, verbose=False, skip_blank_lines=True, parse_dates=False, infer_datetime_format=False, keep_date_col=False, date_parser=None, dayfirst=False, iterator=False, chunksize=None, compression=’infer’, thousands=None, decimal=b’.’, lineterminator=None, quotechar='”‘, quoting=0, doublequote=True, escapechar=None, comment=None, encoding=None, dialect=None, tupleize_cols=None, error_bad_lines=True, warn_bad_lines=True, delim_whitespace=False, low_memory=True, memory_map=False, float_precision=None)
可以用于讀取csv、excel、dat文件。
2.merge
merge(left, right, how=‘inner’, on=None, left_on=None, right_on=None, left_index=False, right_index=False, sort=False, suffixes=(’_x’, ‘_y’), copy=True, indicator=False, validate=None)
連接兩個DataFrame并返回連接之后的DataFrame。
3.iloc
iloc函數(shù):通過行號來取行數(shù)據(jù)(如取第二行的數(shù)據(jù))
4.pivot_table
通過使用pandas.pivot_table()函數(shù),可以實現(xiàn)與電子表格軟件(例如Excel)的數(shù)據(jù)透視表功能相同的處理
5.groupby
和sql中的分組類似,pandas中的groupby函數(shù)也是先將df按照某個字段進行拆分,將相同屬性分為一組;然后對拆分后的各組執(zhí)行相應的轉(zhuǎn)換操作;最后輸出匯總轉(zhuǎn)換后的各組結(jié)果。
三、具體案例
數(shù)據(jù)分析步驟:1.提出問題 2.理解數(shù)據(jù) 3.數(shù)據(jù)清洗 4.構(gòu)建模型 5.數(shù)據(jù)可視化
3.1 MoviesLens 1M數(shù)據(jù)集
GroupLens實驗室提供了一些從MoviesLens用戶那里收集的20世紀90年代末到21世紀初的電影評分數(shù)據(jù)的集合。浙西額數(shù)據(jù)提供了電影的評分、流派、年份和觀眾數(shù)據(jù)(年齡、郵編、性別、職業(yè))。 MovisLens1M數(shù)據(jù)集包含6000個用戶對4000部電影的100萬個評分。數(shù)據(jù)分布在三個表格之中:分別包含評分、用戶信息和電影信息。?
下載地址為:http://files.grouplens.org/datasets/movielens/,有好幾種版本,對應不同數(shù)據(jù)量。
#讀取users.dat文件
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、rating.dat、movies.dat三個文件,并將他們存儲在不同的DataFrame中,分別命名為users、ratings、movies。
users.head(5)
ratings.head(5)
movies.head(5)
ratings
分別輸出三個DataFrame的前五行,并輸出ratings的全部數(shù)據(jù)。
data = pd.merge(pd.merge(ratings, users), movies)
data
data.iloc[0]
使用merge函數(shù)將ratings,users和movies進行合并,保留了三個DataFrame中所有的數(shù)據(jù),并將他們之間重復的數(shù)據(jù)和行進行合并。合并生成名為data的新DataFrame,并輸出整個數(shù)據(jù)以及讀取第一行數(shù)據(jù)。
mean_ratings = data.pivot_table("rating", index="title",
columns="gender", aggfunc="mean")
mean_ratings.head(5)
?使用pivot_table函數(shù)實現(xiàn)數(shù)據(jù)透視表功能,對rating中title列求均值,columns參數(shù)就是用來顯示字符型數(shù)據(jù)的,顯示性別數(shù)據(jù)。求均值生成名為mean_ratings的新DataFrame,并讀取輸出前五行數(shù)據(jù)。
ratings_by_title = data.groupby("title").size()
ratings_by_title.head()
active_titles = ratings_by_title.index[ratings_by_title >= 250]
active_titles
使用groupby函數(shù)對data這一DataFrame按照電影名稱title分組,并計算每個電影標題對應的評分數(shù)量。第二行代碼顯示每個電影標題對應的評分數(shù)量。第三四行代碼統(tǒng)計對應評分數(shù)量大于250的電影標題將其定義為active_titles并輸出。
mean_ratings = mean_ratings.loc[active_titles]
mean_ratings
讀取mean_ratings中評分數(shù)量大于250的電影標題對應的數(shù)據(jù)并輸出。
mean_ratings = mean_ratings.rename(index={"Seven Samurai (The Magnificent Seven) (Shichinin no samurai) (1954)":
"Seven Samurai (Shichinin no samurai) (1954)"})
使用rename函數(shù)將mean_ratings中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()
根據(jù)女性的評分使用排序函數(shù)對mean_ratings進行降序排序并輸出。
mean_ratings["diff"] = mean_ratings["M"] - mean_ratings["F"]
?用mean_ratings中男性評分減去女性評分計算出男女評分差異diff。
sorted_by_diff = mean_ratings.sort_values("diff")
sorted_by_diff.head()
根據(jù)diff列的值使用排序函數(shù)對mean_ratings進行升序排序并輸出。
sorted_by_diff[::-1].head()
使用切片操作對diff進行逆序排序,并輸出。
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()
std函數(shù)用于表示標準差。對電影標題title根據(jù)評分標準差分組。并讀取活躍標題(評分數(shù)量大于250的電影標題)的標準差輸出。
rating_std_by_title.sort_values(ascending=False)[:10]
?根據(jù)評分標準差進行降序排序并讀取前十行,也即輸出評分標準差最大的十個電影標題。
movies["genres"].head()
movies["genres"].head().str.split("|")
movies["genre"] = movies.pop("genres").str.split("|")
movies.head()
讀取電影中g(shù)enres列數(shù)據(jù),并通過|分隔開。將分割后的數(shù)據(jù)命名為genre列,原數(shù)據(jù)列g(shù)enres刪除。
movies_exploded = movies.explode("genre")
movies_exploded[:10]
?使用explode函數(shù)將genre列中分割的數(shù)據(jù)展開成單獨的幾列數(shù)據(jù)并記為movies_exploded這個新DataFrame,輸出前十行數(shù)據(jù)。
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]
將movies_exploded,ratings,users這三個合并起來生成一個新DataFrame,并讀取第一行數(shù)據(jù)。按照genre和age進行分組,并計算每個組評分的平均值,使用unstack函數(shù)將結(jié)果重塑為以age為列索引的形式。
?3.2?美國1880-2010年的嬰兒名字
美國社會保障局(SSA)提供了從1880年至現(xiàn)在的嬰兒姓名頻率的數(shù)據(jù)??梢允褂眠@些數(shù)據(jù)做很多事情:根據(jù)給定的名字對嬰兒名字隨時間的比例進行可視化,確定一個名字的相對排位,確定每年最受歡迎的名字,或者流行程度最高或最低的名字
數(shù)據(jù)集下載地址:http://github.com/wesm/pydata-book
names1880 = pd.read_csv("datasets/babynames/yob1880.txt",
names=["name", "sex", "births"])
names1880
讀取名為“yob1880.txt”文件,并將其列名設(shè)為name,sex,births。
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"])
# Add a column for the year
frame["year"] = year
pieces.append(frame)
# Concatenate everything into a single DataFrame
names = pd.concat(pieces, ignore_index=True)
names
提取從數(shù)據(jù)集中讀取1880-2011年間的數(shù)據(jù)并生成names這個DataFrame。
total_births = names.pivot_table("births", index="year",
columns="sex", aggfunc=sum)
total_births.tail()
total_births.plot(title="Total births by sex and year")
?使用pivot_table函數(shù)以births和sex分組的出生數(shù)總和,并顯示最后幾行。
繪制一個標題為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
定義一個增加組的函數(shù)add_prop,表示每個名字在出生年份和性別組中的比例,每個名字的出生率。
對names按照年份和性別分組,并對每組應用add_prop函數(shù)。
names.groupby(["year", "sex"])["prop"].sum()
?通過年份和性別分組,并計算對每組中的每個名字比例的總和。
def get_top1000(group):
return group.sort_values("births", ascending=False)[:1000]
grouped = names.groupby(["year", "sex"])
top1000 = grouped.apply(get_top1000)
top1000.head()
?定義一個get_top1000的函數(shù),該函數(shù)根據(jù)births進行降序排序,并取前1000行,也即births值最大的前1000。根據(jù)年份和性別分組,并對每個分組應用get_top1000函數(shù)。
top1000 = top1000.reset_index(drop=True)
top1000.head()
使用reset_index()函數(shù)對top1000 DataFrame 進行重置索引,并丟棄原始索引。設(shè)置drop=True可以移除原始索引列,以便在重置索引后不保留它。
boys = top1000[top1000["sex"] == "M"]
girls = top1000[top1000["sex"] == "F"]
total_births = top1000.pivot_table("births", index="year",
columns="name",
aggfunc=sum)
total_births.info()
subset = total_births[["John", "Harry", "Mary", "Marilyn"]]
subset.plot(subplots=True, figsize=(12, 10),
title="Number of births per year")
?根據(jù)性別將top1000的值分為boys和girls兩個數(shù)據(jù)集。并對births進行數(shù)據(jù)透視。
使用info()方法打印出total_births的全部數(shù)據(jù),并選擇John、Harry、Mary、Marilyn四個名字繪制標題為Number of births per year的折線圖。
plt.figure()
table = top1000.pivot_table("prop", index="year",
columns="sex", aggfunc=sum)
table.plot(title="Sum of table1000.prop by year and sex",
yticks=np.linspace(0, 1.2, 13))
對prop進行數(shù)據(jù)透視圖,繪制標題為Sum of table1000.prop by year and sex的折線圖。
df = boys[boys["year"] == 2010]
df
得到2010年男孩出生人數(shù)表
prop_cumsum = df["prop"].sort_values(ascending=False).cumsum()
prop_cumsum[:10]
prop_cumsum.searchsorted(0.5)
?對2010年男孩出生人數(shù)表中prop值進行降序排序并計算累計和,并提取前10行,使用 searchsorted() 方法找到累計和達到 0.5 時的索引位置。
df = boys[boys.year == 1900]
in1900 = df.sort_values("prop", ascending=False).prop.cumsum()
in1900.searchsorted(0.5) + 1
?得到1900年男孩出生人數(shù)表,?對表中prop值進行降序排序并計算累計和,?searchsorted() 方法找到累計和達到 0.5 時的后一個索引位置。
def get_quantile_count(group, q=0.5):
group = group.sort_values("prop", ascending=False)
return group.prop.cumsum().searchsorted(q) + 1
diversity = top1000.groupby(["year", "sex"]).apply(get_quantile_count)
diversity = diversity.unstack()
fig = plt.figure()
diversity.head()
diversity.plot(title="Number of popular names in top 50%")
?定義一個get_quantile_count函數(shù),對prop值進行降序排序并計算累計和,?searchsorted() 方法找到累計和達到 0.5 時的后一個索引位置。
根據(jù)年份和性別分組,并對每組應用get_quantile_count函數(shù),得到diversity這個新DataFrame,并繪制標題為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 = table.reindex(columns=[1910, 1960, 2010], level="year")
subtable.head()
?定義一個返回字符串最后一個字母的函數(shù)。
使用map函數(shù)對names中每一個名字提取最后一個字母。進行數(shù)據(jù)透視。
展示1910,1960,2010年的數(shù)據(jù)。
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)
?導入matplotlib包分別以男生和女生繪制兩幅柱狀圖。
letter_prop = table / table.sum()
dny_ts = letter_prop.loc[["d", "n", "y"], "M"].T
dny_ts.head()
?統(tǒng)計最后男生中名字最后一個字母為d、n、y的比例。
?并繪制折線圖。
all_names = pd.Series(top1000["name"].unique())
lesley_like = all_names[all_names.str.contains("Lesl")]
lesley_like
從top1000 DataFrame的"name"列獲取唯一的姓名,并將結(jié)果存儲在all_names變量中。選擇all_names中包含"Lesl"的姓名,并將結(jié)果賦值給lesley_like變量。顯示lesley_like Series,即包含以"Lesl"開頭的姓名。
filtered = top1000[top1000["name"].isin(lesley_like)]
filtered.groupby("name")["births"].sum()
根據(jù)top1000 DataFrame中的"name"列與lesley_like中的姓名進行匹配,篩選出匹配的行數(shù)據(jù),并將結(jié)果賦值給filtered變量。?對filtered DataFrame按姓名進行分組,計算每個姓名的出生人數(shù)總和,并顯示結(jié)果。
table = filtered.pivot_table("births", index="year",
columns="sex", aggfunc="sum")
table = table.div(table.sum(axis="columns"), axis="index")
table.tail()
根據(jù)年份和性別對filtered進行透視,計算每個年份和性別的出生人數(shù)總和,并將結(jié)果存儲在table變量中。對table進行歸一化,即每行的總和作為除數(shù),計算每個年份和性別的歸一化比例。table歸一化后最后幾行的結(jié)果。
fig = plt.figure()
table.plot(style={"M": "k-", "F": "k--"})
?繪制折線圖,其中男生用實線,女生用虛線。
3.3?美國農(nóng)業(yè)部食品數(shù)據(jù)庫
美國農(nóng)業(yè)部提供了食物營養(yǎng)信息數(shù)據(jù)庫。每種事務都有一些識別屬性以及兩份營養(yǎng)元素和營養(yǎng)比例的列表。這種形式的數(shù)據(jù)不適合分析,所以需要做一些工作將數(shù)據(jù)轉(zhuǎn)換成更好的形式。
下載地址:http://www.nal.usda.gov/fnic/foodcomp/search/
import json
db = json.load(open("datasets/usda_food/database.json"))
len(db)
計算列表中元素的個數(shù)
db[0].keys()
db[0]["nutrients"][0]
nutrients = pd.DataFrame(db[0]["nutrients"])
nutrients.head(7)
獲得db列表中索引為0的所有關(guān)鍵值。?從db列表中索引為0的元素中獲取鍵為"nutrients"的值的列表,并返回列表中的第一個元素。將db列表中索引為0的元素中的"nutrients"值轉(zhuǎn)換為Pandas DataFrame對象。?顯示nutrients DataFrame的前7行數(shù)據(jù)。
info_keys = ["description", "group", "id", "manufacturer"]
info = pd.DataFrame(db, columns=info_keys)
info.head()
info.info()
包含要從數(shù)據(jù)庫中提取的信息的鍵的列表。使用info_keys作為列名,創(chuàng)建包含db數(shù)據(jù)的Pandas DataFrame對象,并將其存儲在info變量中。?顯示info DataFrame的前幾行數(shù)據(jù)。顯示info DataFrame的基本信息。
pd.value_counts(info["group"])[:10]
從DataFrame info 中選擇了名為 "group" 的列,該列包含了食物的分組信息。對選定列中的每個唯一值進行計數(shù),并返回計數(shù)結(jié)果。取計數(shù)結(jié)果中的前 10 個值,即返回出現(xiàn)次數(shù)最多的前 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)
nutrients
?創(chuàng)建一個空列表。定義一個函數(shù)為每個記錄創(chuàng)建一個包含營養(yǎng)信息的DataFrame對象,添加一個名為"id"的列,將記錄的id值賦給該列的每個元素,并將每個記錄的營養(yǎng)信息DataFrame添加到nutrients列表中,?將nutrients列表中的DataFrame對象合并為一個大的DataFrame,并重新索引行號。
nutrients.duplicated().sum() # number of duplicates
nutrients = nutrients.drop_duplicates()
計算duplicates的總值,并將其賦值給nutrients。
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
定義一個字典,里面有兩個鍵值對。將其重命名為info,并輸出。定義另一個字典,將其重命名為nutrients并輸出。
ndata = pd.merge(nutrients, info, on="id")
ndata.info()
ndata.iloc[30000]
?合并nutrients和info,并讀取第30000行數(shù)據(jù)
fig = plt.figure()
result = ndata.groupby(["nutrient", "fgroup"])["value"].quantile(0.5)
result["Zinc, Zn"].sort_values().plot(kind="barh")
以nutrient和fgroup分組,并排序繪制柱狀圖。
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]
max_foods.loc["Amino Acids"]["food"]
?根據(jù)nutgroup和nutrient分組,并定義一個求最大值得函數(shù),對value和food求最大值,對最大food讀取前50行,讀取Amino Acids行數(shù)據(jù)。文章來源:http://www.zghlxwxcb.cn/news/detail-700379.html
文章來源地址http://www.zghlxwxcb.cn/news/detail-700379.html
到了這里,關(guān)于手把手教你如何用python進行數(shù)據(jù)分析?。ǜ剿膫€案例)的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!