Python學習從0開始——Kaggle實踐可視化001
- 一、創建和加載數據集
- 二、數據預處理
- 1.按name檢查,處理重復值(查重)
- 2.查看存在缺失值的列并處理(缺失值處理)
- 2.1按行或列查看
- 2.2無法推測的數據
- 2.3可由其它列推測的數據
- 3.拆列,獲取元數據
使用數據集:“Top Ranked Anime Dataset 2024”,文件名稱是:toprankedanime.csv
一、創建和加載數據集
登錄kaggle選擇創建新筆記本:
然后刪掉默認代碼,加載數據集:
import numpy as np
import pandas as pd
# 路徑
anime_file_path = '/kaggle/input/top-ranked-anime-dataset/toprankedanime.csv'
# 讀取
anime_data = pd.read_csv(anime_file_path)
# 總覽數據,查看基本信息
#anime_data.describe()
#anime_data.head
#anime_data.columns
#anime_data.head(3)
name | type | episodes | status | aired | premiered | broadcast | producers | licensors | studios | source | genres | duration | rating | score | ranked | popularity | favorites |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Sousou no Frieren | TV | 28 | Finished Airing | Sep 29, 2023 to Mar 22, 2024 | Fall 2023 | Fridays at 23:00 (JST) | [‘Aniplex’, ‘Dentsu’, ……] | [‘add some’] | Madhouse | Manga | [‘Adventure’, ‘Drama’, ‘Fantasy’] | 24 min. per ep. | PG-13 - Teens 13 or older | 9.36 | #1 | #259 | 43,524 |
Steins;Gate | TV | 24 | Finished Airing | Apr 6, 2011 to Sep 14, 2011 | Spring 2011 | Wednesdays at 02:05 (JST) | [‘Frontier Works’, ‘Media Factory’……] | [‘Funimation’] | White Fox | [‘Drama’, ‘Sci-Fi’, ‘Suspense’] | 24 min. per ep. | PG-13 - Teens 13 or older | 9.07 | #3 | #13 | 189,803 | |
Fullmetal Alchemist: Brotherhood | TV | 64 | Finished Airing | Apr 5, 2009 to Jul 4, 2010 | Spring 2009 | Sundays at 17:00 (JST) | [‘Aniplex’, ‘Square Enix’……] | [‘Funimation’, ‘Aniplex of America’] | Bones | Manga | [‘Action’, ‘Adventure’, ‘Drama’, ‘Fantasy’] | 24 min. per ep. | R - 17+ (violence & profanity) | 9.09 | #2 | #3 | 226,283 |
columns:Index([‘name’, ‘type’, ‘episodes’, ‘status’, ‘aired’, ‘premiered’, ‘broadcast’,
‘producers’, ‘licensors’, ‘studios’, ‘source’, ‘genres’, ‘duration’,
‘rating’, ‘score’, ‘ranked’, ‘popularity’, ‘favorites’],
dtype=‘object’)
#動漫名稱:動漫的標題。
#類型:動漫分類(例如,電視、電影、OVA)。
#集數:集數。
#狀態:廣播狀態(例如,“已完成播出”)。
#在電視臺或在線平臺上正式播出的時間
#播出日期:原播出日期。
#首映:首映的季節和年份。
#廣播:每周廣播時間。
#生產者:參與生產的公司。
#許可方:負責在不同地區授權動漫的公司。
#工作室:為該系列制作動畫的工作室。
#來源:原始資料(例如,漫畫、輕小說)。
#類型:描述節目的類別(例如,動作、劇情)。
#持續時間:每集的長度。
#等級:觀眾適宜性
#分數: MyAnimeList 用戶給出的平均評分。
#排名:在MyAnimeList上排名。
#人氣:在MyAnimeList上的人氣排名。
#收藏夾:用戶收藏的次數。
二、數據預處理
1.按name檢查,處理重復值(查重)
使用Pandas庫的duplicated方法。這個方法會返回一個布爾序列,指示哪些行在指定列(或所有列)中是重復的。
# 首先按name檢查是否有重復值duplicated_names = anime_data['name'].duplicated()
# 查看所有重復的名稱
duplicate_names_list = anime_data[duplicated_names]['name'].unique().tolist()
# 輸出重復的名稱(如果有的話)
if len(duplicate_names_list) > 0: print("存在重復的名稱:") print(duplicate_names_list)
else: print("name列中沒有重復值。")
如果有重復行,那么需要額外的處理,以下是一些常見的處理重復值的方法:
-
刪除重復行:
如果你確定重復的行是多余的,并且你想要保留唯一的記錄,你可以刪除這些重復的行。在Pandas中,你可以使用drop_duplicates
方法來實現這一點。anime_data = anime_data.drop_duplicates(subset='name', keep='first') # keep='first'保留第一次出現的行 # 或者 # anime_data = anime_data.drop_duplicates(subset='name', keep='last') # keep='last'保留最后一次出現的行 # 或者 # anime_data = anime_data.drop_duplicates(subset='name', keep=False) # keep=False刪除所有重復的行
-
合并重復行:
如果重復的行包含了一些不同的信息,你可能想要合并這些行。這通常涉及到聚合操作,例如計算重復行的某個字段的平均值、總和等。# 假設你有一個想要聚合的字段'score' anime_data_agg = anime_data.groupby('name').agg({'score': 'mean'}).reset_index() # 計算每個動漫的平均評分
-
標記重復行:
如果你想要保留重復的行,但同時想要知道哪些行是重復的,你可以使用duplicated
方法(如之前所示)來創建一個新的布爾列來標記這些行。anime_data['is_duplicate'] = anime_data.duplicated(subset='name')
-
手動處理:
在某些情況下,你可能需要手動檢查重復的行,并根據具體情況決定如何處理它們。例如,你可能需要查看除了’name’列之外的其他列來確定是否應該合并或刪除這些行。 -
錯誤檢查:
重復的值有時可能表示數據輸入或處理過程中的錯誤。在這種情況下,你可能需要回到數據源,檢查為什么會有重復的行,并修正錯誤。 -
保持備份:
在對數據進行任何修改之前,最好先備份原始數據。這樣,如果后續需要回到原始狀態或重新處理數據,你可以很容易地做到這一點。
根據你的具體需求和數據集的特性,選擇最適合你的方法來處理重復值。
2.查看存在缺失值的列并處理(缺失值處理)
要查看Pandas DataFrame中哪些列存在缺失值(通常表示為NaN),可以使用isnull()方法結合any()或sum()方法。
2.1按行或列查看
#按列查看
# 查看哪些列包含缺失值
columns_with_missing = anime_data.columns[anime_data.isnull().any()].tolist()
print("包含缺失值的列:", columns_with_missing)
# 包含缺失值的列: ['premiered', 'broadcast', 'source', 'rating']即首映,播放,來源,等級# 查看每一列中缺失值的數量
missing_counts = anime_data.isnull().sum()
#print("每一列中缺失值的數量:")
#print(missing_counts)# 只查看包含缺失值的列及其缺失值的數量
columns_with_missing_and_counts = anime_data.columns[anime_data.isnull().any()].tolist()
missing_counts_filtered = anime_data[columns_with_missing_and_counts].isnull().sum()
print("包含缺失值的列及其缺失值的數量:")
print(missing_counts_filtered)
#包含缺失值的列及其缺失值的數量:
#premiered 988
#broadcast 988
#source 658
#rating 1
#dtype: int64
# 按行查看
# 使用 any(axis=1) 來檢查每一行是否至少有一個缺失值
rows_with_missing = anime_data[anime_data.isnull().any(axis=1)] # 顯示這些行
#print(rows_with_missing)# 只顯示該行的缺失列數據
#print(rows_with_missing.name,rows_with_missing[columns_with_missing])# 打印缺失列
#for index, row in rows_with_missing.iterrows():
# print(f"在索引 {index} 的行中,缺失值的列有:")
# for column in row.index[row.isnull()]:
# print(column)
# print("\n") # 打印一個空行分隔不同行的輸出
2.2無法推測的數據
#處理缺失數據#不修改原數據集,創建一個新的數據集修改
anime_data_filled = anime_data.copy() #處理rating
#找到rating為null的數據
#ratingNull=rows_with_missing[rows_with_missing['rating'].isnull()]
#selected_columns = ['name', 'rating', 'score']
#print(ratingNull[selected_columns])
#輸出:
# name rating score
#1762 Xue Ying Ling Zhu 2nd Season NaN 7.48
#rating列的缺失值被替換為'unknown'
anime_data_filled['rating'].fillna('unknown')#處理其他列
#source和broadcast列的缺失值被替換為'unknown'
anime_data_filled['source'].fillna('unknown')
anime_data_filled['broadcast'].fillna('unknown')
2.3可由其它列推測的數據
如:aired值為Apr 1, 2007 to Sep 30, 2007,那么premiered就是Spring 2007
#處理premiered首映列控制問題
#premired列可以由aired列推出
#不推薦將premired值直接設為aired值,因為之后要用到日期分析
#anime_data_filled['premiered'] = anime_data_filled['premiered'].combine_first(anime_data_filled['aired']) # 推薦
import re
from datetime import datetime def infer_premiered_season(aired_date): # 首先嘗試匹配包含開始和結束日期的格式:Oct 4, 2006 to Jun 27, 2007match = re.match(r'(\w+ \d+, \d+) to (\w+ \d+, \d+)', aired_date) if match: start_date_str, end_date_str = match.groups() # 使用開始日期來確定季度 start_date = datetime.strptime(start_date_str, '%b %d, %Y') season = get_season(start_date.month) return f"{season} {start_date.year}" # 如果沒有匹配到開始和結束日期,嘗試匹配單獨的日期:Sep 17, 2016 match = re.match(r'(\w+ \d+, \d+)', aired_date) if match: date_str = match.group(1) date_sigle = datetime.strptime(date_str, '%b %d, %Y') season = get_season(date_sigle.month) return f"{season} {date_sigle.year}" # 如果沒有匹配到開始和結束日期,嘗試匹配單獨的日期:17-Jan-20match = re.match(r'(\d+)-(\w+)-(\d+)', aired_date) if match: year_str, month_str, day_str = match.groups() month_num = get_month_number(month_str) if month_num is not None: year = int(year_str) if len(year_str) == 2: # 如果是兩位數的年份,可能需要一些邏輯來確定實際年份(例如,基于當前年份) year += 2000 if int(year_str) > 20 else 1900 # 簡化的年份推斷,可能需要調整 season = get_season(month_num) return f"{season} {year}" # 如果沒有匹配到開始和結束日期,嘗試匹配單獨的日期:May 2003match = re.search(r'(\w{3})\s(\d{4})', aired_date) if match: month_str, year_str = match.groups() month_num = get_month_number(month_str) year = int(year_str) if month_num is not None: return f"{get_season(month_num)} {year}" # 如果沒有匹配到任何日期格式,返回aired_date值或NaN,比如傳來的值為2003return pd.NA def get_month_number(month_str): # 將月份字符串轉換為數字(例如,"Jan" -> 1) month_dict = { 'Jan': 1, 'Feb': 2, 'Mar': 3, 'Apr': 4, 'May': 5, 'Jun': 6, 'Jul': 7, 'Aug': 8, 'Sep': 9, 'Oct': 10, 'Nov': 11, 'Dec': 12 } return month_dict.get(month_str) def get_season(month): # 根據月份返回季節(Spring, Summer, Fall, Winter) if 3 <= month <= 5: return 'Spring' elif 6 <= month <= 8: return 'Summer' elif 9 <= month <= 11: return 'Fall' else: return 'Winter' # 使用自定義函數填充premiered列的缺失值
anime_data_filled['premiered'] = anime_data_filled['premiered'].fillna(anime_data_filled['aired'].apply(infer_premiered_season))
print(anime_data_filled[anime_data_filled['premiered'].isnull()])
#此時輸出如下,只有年份的數據,獲取不到季節
# name type episodes \
#1234 Saint Seiya: Meiou Hades Juuni Kyuu-hen - Yomi... Special 2
#1265 Meitantei Conan Movie 10: Tantei-tachi no Requ... TV Special 1
#1359 Meitantei Conan Movie 09: Suihei Senjou no Str... TV Special 1
#1690 Meitantei Conan OVA 04: Conan to Kid to Crysta... OVA 1
#1944 Junjou Romantica Special Special 1
# status aired premiered broadcast producers \
#1234 Finished Airing 2003 <NA> NaN ['add some']
#1265 Finished Airing 2006 <NA> NaN ['add some']
#1359 Finished Airing 2005 <NA> NaN ['add some']
#1690 Finished Airing 2004 <NA> NaN ['add some']
#1944 Finished Airing 2008 <NA> NaN ['Kadokawa Shoten'] #刪除還是缺失值的數據
anime_data_filled = anime_data_filled.dropna(subset=['premiered'])
print(anime_data_filled[anime_data_filled['premiered'].isnull()])
#輸出
#Empty DataFrame
#Columns: [name, type, episodes, status, aired, premiered, broadcast, producers, licensors, studios, source, genres, duration, rating, score, ranked, popularity, favorites]
#Index: []
3.拆列,獲取元數據
上一部分對premiered的處理是為了統一成“季度 年份”的格式,然后將其拆分成年列和季度列,同時四個季度可以賦予不同的數值:
#繼續處理premiered
# 定義一個函數將季節轉換為數字
def season_to_number(season): season_dict = { 'Spring': 1, 'Summer': 2, 'Fall': 3, 'Winter': 4 } return season_dict.get(season, None) # 使用str.split方法拆分'premiered'列,并擴展結果到新的列
# 注意:我們使用expand=True,分割后的兩部分將作為兩列(假設分割成功)添加到新的DataFrame中
season_year_df = anime_data_filled['premiered'].str.split(n=1, expand=True) # 給新列重命名
season_year_df.columns = ['season', 'year']
# 將年份列轉換為整數
season_year_df['year'] = season_year_df['year'].astype(int)
# 將拆分后的DataFrame添加到原始DataFrame中
anime_data_filled = pd.concat([anime_data_filled, season_year_df], axis=1)
# 創建一個新的'quarter'列,其中包含季節的數字表示
anime_data_filled['quarter'] = anime_data_filled['season'].apply(season_to_number) # 顯示結果
print(anime_data_filled.head(3))
name | …… | premiered | …… | year | quarter |
---|---|---|---|---|---|
Sousou no Frieren TV | …… | Fall 2023 | …… | 2023 | 3 |
Steins;Gate TV | …… | Spring 2011 | …… | 2011 | 1 |
Fullmetal Alchemist: Brotherhood TV | …… | Spring 2009 | …… | 2009 | 1 |