ラベル DataFrame の投稿を表示しています。 すべての投稿を表示
ラベル DataFrame の投稿を表示しています。 すべての投稿を表示

2024年6月22日土曜日

scikit-learnのデータセット、Bunchクラスはとても有用

scikit-learnのデータセット

scikit-learnは機械学習を扱う便利なライブラリですが、簡単に試せるようにサンプル・データセットも用意されています。 
多くの方はscikit-learnの入門にこのデータセットを利用されると思います。

sklearn.__version__ : 1.4.2

 サンプルデータセットには小さいサイズのToy Datasetsと画像などの大きなサイズのReal World Datasetsの2種類が用意されています。


#! /usr/bin/env python
# -*- coding:utf-8 -*-

iris_data = sklearn.datasets.load_iris()

print(type(iris_data))


<class 'sklearn.utils._bunch.Bunch'>

データセットはBunchクラスのオブジェクトとして読み込まれます。

Bunchクラスはdictのサブクラスでdictと同じように扱えるので、keys()でメンバ一覧出来ます。

print(iris_data.keys())

dict_keys(['data', 'target', 'frame', 'target_names', 'DESCR', 'feature_names', 'filename', 'data_module'])


Bunchクラスのデータをpandasのデータフレームに変換する

Bunchクラスのデータをpandasのデータフレームとして扱うには、データの中身をdata変数、列名をfeature_namesから取ります。

 
 df = pd.DataFrame(iris_data.data, columns=iris_data.feature_names)
 
 pritn(df.head())
 
 

 sepal length (cm)  sepal width (cm)  petal length (cm)  petal width (cm)
0                5.1               3.5                1.4               0.2
1                4.9               3.0                1.4               0.2
2                4.7               3.2                1.3               0.2
3                4.6               3.1                1.5               0.2
4                5.0               3.6                1.4               0.2

このようにデータフレームとしても扱えますが、Bunchオブジェクトは説明変数、目的変数、注釈などに分けてあるので通常のデータフレームよりデータの内容が理解しやすいです。

通常のデータフレームは行と列ですぐに扱えますが、扱いやすい分、列名が短縮系で意味が分からなかったり、データ自身を解釈するのに他に説明が必要です。

Bunchクラスではデータの意味や説明まで含まれているので、データをどのように扱うか他を参照しなくても理解出来ます。

scikit-learnは急速に進化中ですが、Bunchクラスはサンプルデータだけでなく、もっと広まっても良い気がします。

2022年6月17日金曜日

NBA選手データを整える

 NBAはデータを豊富に提供しているので分析に適しています。

ただし、身長や体重が日本と異なる表記なので、日本で分かりやすいようにデータを変換してみます。

ついでに欠損値除去や微調整してデータを取り扱い安くします。


まず、元データ player_data.csv の中身を確認します。

filename = "player_data.csv"

df = pd.read_csv(filename)

print(df.head())
print()
print(df.shape)
print()
print(df.info())


                  name  year_start  year_end position height  weight        birth_date                                college

0       Alaa Abdelnaby        1991      1995      F-C   6-10   240.0     June 24, 1968                        Duke University

1      Zaid Abdul-Aziz        1969      1978      C-F    6-9   235.0     April 7, 1946                  Iowa State University

2  Kareem Abdul-Jabbar        1970      1989        C    7-2   225.0    April 16, 1947  University of California, Los Angeles

3   Mahmoud Abdul-Rauf        1991      2001        G    6-1   162.0     March 9, 1969             Louisiana State University

4    Tariq Abdul-Wahad        1998      2003        F    6-6   223.0  November 3, 1974              San Jose State University


(4550, 8)


<class 'pandas.core.frame.DataFrame'>

RangeIndex: 4550 entries, 0 to 4549

Data columns (total 8 columns):

 #   Column      Non-Null Count  Dtype  

---  ------      --------------  -----  

 0   name        4550 non-null   object 

 1   year_start  4550 non-null   int64  

 2   year_end    4550 non-null   int64  

 3   position    4549 non-null   object 

 4   height      4549 non-null   object 

 5   weight      4544 non-null   float64

 6   birth_date  4519 non-null   object 

 7   college     4248 non-null   object 

dtypes: float64(1), int64(2), object(5)


データは4550件、birth_dateやweightに欠損値が散見されます。


print(df[df['weight'].isnull()])
print()
print(df[df['birth_date'].isnull()].sort_values('year_end', ascending=False))

df2 = df.dropna(how="any")
欠損値データを確認すると昔の人ばかりなので、昔の年代を分析しない場合は削除して構わないでしょう。dropna(how="any")で欠損値を取り除いたデータフレームにします。


# 1foot = 30.48, 1inch = 2.54cm
FOOT= 30.48
INCH = 2.54

# 1pond = 0.4536kg
LB = 0.4536

# フィートをセンチに
def toCenti(height):

    ft, inc = height.split("-")
    cent = int(ft) * FOOT + int(inc) * INCH

    return round(cent, 2)


# ポンドをキログラムに
def toKilogram(weight):

    kg = weight * LB
    
    return round(kg, 2)
    
 
# 以上の関数を身長体重データに適用させる
df2['height'] = df2['height'].apply(toCenti)
df2['weight'] = df2['weight'].apply(toKilogram)


print(df2.head())
print()
print(df2.shape)



                  name  year_start  year_end position  height  weight        birth_date                                college
0       Alaa Abdelnaby        1991      1995      F-C  208.28  108.86     June 24, 1968                        Duke University
1      Zaid Abdul-Aziz        1969      1978      C-F  205.74  106.60     April 7, 1946                  Iowa State University
2  Kareem Abdul-Jabbar        1970      1989        C  218.44  102.06    April 16, 1947  University of California, Los Angeles
3   Mahmoud Abdul-Rauf        1991      2001        G  185.42   73.48     March 9, 1969             Louisiana State University
4    Tariq Abdul-Wahad        1998      2003        F  198.12  101.15  November 3, 1974              San Jose State University

(4213, 8)

変換できました。

player_data_a.csv
完成データは 

2022年5月21日土曜日

NBAデータから歴代得点王ランキングを出してみる

馴染みのあるデータや好きなスポーツのデータを扱ったりするとデータフレームを習得するのも楽しめていいですね。

今回はおなじくkaggleの NBA Players stats since 1950 から Seasons_Stats.csv を使用して歴代得点王を取り出したいと思います。


#! /usr/bin/env python

# -*- coding:utf-8 -*-

#
import pandas as pd
import numpy as np

filename = "../data/Seasons_Stats.csv"

print("[NBA]")
print()

df = pd.read_csv(filename, index_col=0)

print()

# 年間得点の多い順にソート
porder = df.sort_values('PTS', ascending=False)

# Year, Player, PTSのみのデータフレームにする
points = porder.loc[:, ['Year', 'Player', 'PTS']]

# Year, Player, PTSのみのDataFrame 数
print(points.shape)
print()

# 欠損値の削除
points = points.dropna()
print(points.shape)
print()

# 見やすいようにfloatからintへの変換
point = points.astype({'Year': 'int64', 'PTS': 'int64'})
print(points.dtypes)
print()
print(points.info())
print()

# 得点ランキングトップ50を表示する
points.reset_index(drop=True, inplace=True)
points.index = np.arange(1, len(points)+1)
print(points.head(50))


まず、年間得点(PTS)を sort_values() を使い得点の多い順(逆ソート)します。
得点だけのランキングなので記録年数(Year)、選手名(Player)、年間得点(PTS)だけのデータフレームを loc を使って切り出します。

このままだと年と年間得点もデータ型が float64 なのでintに変えたいと思いますが、欠損値があるのでデータ変換できません。
そこで先に欠損値行をdropna() で消します。
元の数(24691, 3) から (24624, 3) に減りました。
これで astype() を使い 年と年間得点を int に変換します。

もう一つソートされてもインデックスがそのままだと何の数字か分からないのでインデックスを reset_index() で振り直します。
インデックスをランキングにしたいなら0基準より1から数えたほうがいいでしょう。

すべて整ったら歴代得点ランキングトップ50を取り出してみます。

    Year                Player   PTS
1   1962     Wilt Chamberlain*  4029
2   1963     Wilt Chamberlain*  3586
3   1987       Michael Jordan*  3041
4   1961     Wilt Chamberlain*  3033
5   1964     Wilt Chamberlain*  2948
6   1988       Michael Jordan*  2868
7   2006           Kobe Bryant  2832
8   1975           Bob McAdoo*  2831
9   1972  Kareem Abdul-Jabbar*  2822
10  1967           Rick Barry*  2775
11  1990       Michael Jordan*  2753
12  1973       Tiny Archibald*  2719
13  1963         Elgin Baylor*  2719
14  1960     Wilt Chamberlain*  2707
15  1966     Wilt Chamberlain*  2649
16  1989       Michael Jordan*  2633
17  1971  Kareem Abdul-Jabbar*  2596
18  2014          Kevin Durant  2593
19  1980        George Gervin*  2585
20  1991       Michael Jordan*  2580
21  2017     Russell Westbrook  2558
22  1982        George Gervin*  2551
23  1993       Michael Jordan*  2541
24  1990          Karl Malone*  2540
25  1961         Elgin Baylor*  2538
26  1965     Wilt Chamberlain*  2534
27  1982         Moses Malone*  2520
28  1962         Walt Bellamy*  2495
29  1996       Michael Jordan*  2491
30  1964      Oscar Robertson*  2480
31  2006          LeBron James  2478
32  1966           Jerry West*  2476
33  2010          Kevin Durant  2472
34  2003           Kobe Bryant  2461
35  1982       Adrian Dantley*  2457
36  1981       Adrian Dantley*  2452
37  1975           Rick Barry*  2450
38  1962      Oscar Robertson*  2432
39  1997       Michael Jordan*  2431
40  2007           Kobe Bryant  2430
41  1962           Bob Pettit*  2429
42  1976           Bob McAdoo*  2427
43  1984       Adrian Dantley*  2418
44  1986         Alex English*  2414
45  1967      Oscar Robertson*  2412
46  2003         Tracy McGrady  2407
47  1992       Michael Jordan*  2404
48  1988    Dominique Wilkins*  2397
49  2009           Dwyane Wade  2386
50  1994       David Robinson*  2383


 Wilt Chamberlainの年間得点が異常と言われるほど凄い数字だというのが分かります。






 

NBAデータをDataFrameを使ってグループ分けをする

Pandasのデータフレームはデータ分析に適しています。

NBAデータから自分の取り出したいデータに分けてみます。

データ元は便利な kaggle から「NBA Players stats since 1950」というデータをお借りします。


Seasons_Stats.csvには1950-2017年まで(24691, 53)件という選手の膨大なデータがあります。


 #! /usr/bin/env python
 # -*- coding:utf-8 -*-
 
 #import pandas as pd
 import numpy as np
 
 filename = "Seasons_Stats.csv"
 
 df = pd.read_csv(filename)
 
 print(df.head())
 print()
 print(df.shape)
 print()


 Unnamed: 0    Year         Player Pos   Age  ...    STL   BLK    TOV     PF     PTS
9547        9547  1990.0     Mark Acres   C  27.0  ...   36.0  25.0   70.0  248.0   362.0
9548        9548  1990.0  Michael Adams  PG  27.0  ...  121.0   3.0  141.0  133.0 1221.0
9549        9549  1990.0   Mark Aguirre  SF  30.0  ...   34.0  19.0  121.0  201.0  1099.0
9550        9550  1990.0    Danny Ainge  PG  30.0  ...  113.0  18.0  185.0  238.0  1342.0
9551        9551  1990.0    Mark Alarie  PF  26.0  ...   60.0  39.0  101.0  219.0   860.0

(24691, 53)



これでは流石に大きすぎるので1990年代のデータだけ取り出してみましょう。

y1990 = df[df['Year'] == 1990]
y1990 = y1990.drop(y1990.columns[0], axis=1)
y1990 = y1990.reset_index(drop=True)

print(y1990.head())
print()
print(y1990.shape)
先頭のインデックスはいらないのでdrop関数で弾いて、reset_index関数で振り直しています。
引数のdrop=Trueは元のインデックスを残さないためのものです。


     Year         Player Pos   Age   Tm  ...    STL   BLK    TOV     PF     PTS
0  1990.0     Mark Acres   C  27.0  ORL  ...   36.0  25.0   70.0  248.0   362.0
1  1990.0  Michael Adams  PG  27.0  DEN  ...  121.0   3.0  141.0  133.0  1221.0
2  1990.0   Mark Aguirre  SF  30.0  DET  ...   34.0  19.0  121.0  201.0  1099.0
3  1990.0    Danny Ainge  PG  30.0  SAC  ...  113.0  18.0  185.0  238.0  1342.0
4  1990.0    Mark Alarie  PF  26.0  WSB  ...   60.0  39.0  101.0  219.0   860.0

(459, 52)

これで1990年のデータが取り出せました。

NBAの1試合平均チームスタッツ (2025-26レギュラーシーズン)

前回 の元となったデータ、チーム毎の各スタッツ平均です。   team games w l win% PTS AST BLK STL ...