R, Python, DB 備忘録

データベースとか、jupyter(Python)、Rとか色々

データ操作まとめ(R dplyrとPython pandasで)

irisデータセットを使ってRとPythonのデータフレームの操作方法の比較

バージョン

  • R
R 4.0.2
dplyr 1.0.1
Python 3.7
pandas 1.1.0

準備

R

> library(tidyverse)
> dim(iris)
150 5
> iris %>% head()
A data.frame: 6 × 5
Sepal.Length	Sepal.Width	Petal.Length	Petal.Width	Species
<dbl>	<dbl>	<dbl>	<dbl>	<fct>
1	5.1	3.5	1.4	0.2	setosa
2	4.9	3.0	1.4	0.2	setosa
3	4.7	3.2	1.3	0.2	setosa
4	4.6	3.1	1.5	0.2	setosa
5	5.0	3.6	1.4	0.2	setosa
6	5.4	3.9	1.7	0.4	setosa

Python

> from sklearn.datasets import load_iris
> import pandas as pd
> import numpy as np
> iris0 = load_iris()
> target_list = [{0:'setosa', 1:'versicolor', 2:'virginica'}[key] for key in iris0.target]
> target_list[:3]
['setosa', 'setosa', 'setosa']

> iris = pd.concat([pd.DataFrame(iris0.data),
...                  pd.DataFrame(np.array(target_list).reshape(-1,1))],
...                 axis=1,
...                 ignore_index=True
...                )
> iris.columns = ['sepal_length', 'sepal_width', 'petal_length', 'petal_width', 'species']
> print(iris.head())
   sepal_length  sepal_width  petal_length  petal_width species
0           5.1          3.5           1.4          0.2  setosa
1           4.9          3.0           1.4          0.2  setosa
2           4.7          3.2           1.3          0.2  setosa
3           4.6          3.1           1.5          0.2  setosa
4           5.0          3.6           1.4          0.2  setosa

(列の)選択

R

  • 列番号を指定すると指定した列のみのdataframeが返ってくる
  • seriesにならないところがポイント
> iris[1] %>% head()
A data.frame: 6 × 1
Sepal.Length
<dbl>
1	5.1
2	4.9
3	4.7
4	4.6
5	5.0
6	5.4
  • 列番号を複数指定すると指定した列らで構成されたdataframeが返ってくる
  • 列番号が重複していると、結果も重複する
> iris[c(1,2,1)] %>% head()
A data.frame: 6 × 3
Sepal.Length	Sepal.Width	Sepal.Length.1
<dbl>	<dbl>	<dbl>
1	5.1	3.5	5.1
2	4.9	3.0	4.9
3	4.7	3.2	4.7
4	4.6	3.1	4.6
5	5.0	3.6	5.0
6	5.4	3.9	5.4
  • select(列名)での選択が可能(NSE)
> iris %>% select(Sepal.Length) %>% head()
A data.frame: 6 × 1
Sepal.Length
<dbl>
1	5.1
2	4.9
3	4.7
4	4.6
5	5.0
6	5.4
  • selectを使う場合は重複は無視される
> iris %>% select(Sepal.Length, Sepal.Length) %>% head()
A data.frame: 6 × 1
Sepal.Length
<dbl>
1	5.1
2	4.9
3	4.7
4	4.6
5	5.0
6	5.4
  • 限定列挙する場合
> iris %>% select(Sepal.Length, Sepal.Width) %>% head()
A data.frame: 6 × 2
Sepal.Length	Sepal.Width
<dbl>	<dbl>
1	5.1	3.5
2	4.9	3.0
3	4.7	3.2
4	4.6	3.1
5	5.0	3.6
6	5.4	3.9
  • one_ofでも同じだが使うことは少ない
> iris %>% select(one_of(c('Sepal.Width', 'Petal.Length'))) %>% head()
A data.frame: 6 × 2
Sepal.Width	Petal.Length
<dbl>	<dbl>
1	3.5	1.4
2	3.0	1.4
3	3.2	1.3
4	3.1	1.5
5	3.6	1.4
6	3.9	1.7
  • 条件に合致する列名を一括して選択する
    • starts_withends_withcontainsone_ofmatches
> iris %>% select(ends_with('Width')) %>% head()
A data.frame: 6 × 2
Sepal.Width	Petal.Width
<dbl>	<dbl>
1	3.5	0.2
2	3.0	0.2
3	3.2	0.2
4	3.1	0.2
5	3.6	0.2
6	3.9	0.4
  • starts_withの実態は、bool型リスト(ベクトル?)なので、論理演算が可能
> iris %>% select(ends_with('Width') & starts_with('Petal')) %>% head()
A data.frame: 6 × 1
Petal.Width
<dbl>
1	0.2
2	0.2
3	0.2
4	0.2
5	0.2
6	0.4
> iris %>% select(ends_with('Width') | starts_with('Petal')) %>% head()
A data.frame: 6 × 3
Sepal.Width	Petal.Width	Petal.Length
<dbl>	<dbl>	<dbl>
1	3.5	0.2	1.4
2	3.0	0.2	1.4
3	3.2	0.2	1.3
4	3.1	0.2	1.5
5	3.6	0.2	1.4
6	3.9	0.4	1.7

Python

  • 列番号を指定すると指定した列のSeriesが返ってくる
> iris.iloc[:5,1]
   sepal_width
0          3.5
1          3.0
2          3.2
3          3.1
4          3.6
  • DataFrameが欲しい場合は列番号をリストにする
> iris.iloc[:5,[1]]
  • 列番号を複数指定すると指定した列らで構成されたDataFrameが返ってくる
  • 列番号が重複していると、結果も重複する
> iris.iloc[:5, [1,2,1]]
sepal_width	petal_length	sepal_width
0	3.5	1.4	3.5
1	3.0	1.4	3.0
2	3.2	1.3	3.2
3	3.1	1.5	3.1
4	3.6	1.4	3.6
  • 列名で選択する場合は.iloc不要
> iris['sepal_length']
0      5.1
1      4.9
2      4.7
3      4.6
4      5.0
      ... 
145    6.7
146    6.3
147    6.5
148    6.2
149    5.9
Name: sepal_length, Length: 150, dtype: float64
  • あるいは.locを使う
> iris.loc[:5,['sepal_length']]
sepal_length
0	5.1
1	4.9
2	4.7
3	4.6
4	5.0
5	5.4
  • 列名が重複していると、結果も重複する
> iris.loc[:5,['sepal_length', 'sepal_length']]
sepal_length	sepal_length
0	5.1	5.1
1	4.9	4.9
2	4.7	4.7
3	4.6	4.6
4	5.0	5.0
5	5.4	5.4
  • 列名の限定列挙
> iris.loc[:5,['sepal_length', 'sepal_width']]
sepal_length	sepal_width
0	5.1	3.5
1	4.9	3.0
2	4.7	3.2
3	4.6	3.1
4	5.0	3.6
5	5.4	3.9
  • 条件に合致する列名を一括して選択する場合はstrアクセサを使う
    • startswithendswithcontains
> iris.loc[:5, lambda x: x.columns.str.endswith('width')]
sepal_width	petal_width
0	3.5	0.2
1	3.0	0.2
2	3.2	0.2
3	3.1	0.2
4	3.6	0.2
5	3.9	0.4
  • startswithの実態は配列でありビット演算子&,|,^,~による要素ごとの論理演算(AND, OR, XOR, NOT)が可能
    • ただし、startswithendswithの引数にはタプルを指定でき、OR条件とすることが可能
> iris.loc[:5, lambda x: x.columns.str.endswith('width') & x.columns.str.startswith('petal')]
petal_width
0	0.2
1	0.2
2	0.2
3	0.2
4	0.2
5	0.4

抽出(filter)

R

  • filter(条件式)で条件に合致する行が抽出できる
> iris %>% filter(Sepal.Width < 3.5) %>% head()
A data.frame: 6 × 5
Sepal.Length	Sepal.Width	Petal.Length	Petal.Width	Species
<dbl>	<dbl>	<dbl>	<dbl>	<fct>
1	4.9	3.0	1.4	0.2	setosa
2	4.7	3.2	1.3	0.2	setosa
3	4.6	3.1	1.5	0.2	setosa
4	4.6	3.4	1.4	0.3	setosa
5	5.0	3.4	1.5	0.2	setosa
6	4.4	2.9	1.4	0.2	setosa
  • 複数の列を使用する条件式も可能
> iris %>% filter(Sepal.Width < Sepal.Length*.8) %>% head()
A data.frame: 6 × 5
Sepal.Length	Sepal.Width	Petal.Length	Petal.Width	Species
<dbl>	<dbl>	<dbl>	<dbl>	<fct>
1	5.1	3.5	1.4	0.2	setosa
2	4.9	3.0	1.4	0.2	setosa
3	4.7	3.2	1.3	0.2	setosa
4	4.6	3.1	1.5	0.2	setosa
5	5.0	3.6	1.4	0.2	setosa
6	5.4	3.9	1.7	0.4	setosa
  • リスト中のいずれかの値と一致する行を抽出する例
> iris %>% filter(Species %in% c('virginica')) %>% head()
A data.frame: 6 × 5
Sepal.Length	Sepal.Width	Petal.Length	Petal.Width	Species
<dbl>	<dbl>	<dbl>	<dbl>	<fct>
1	6.3	3.3	6.0	2.5	virginica
2	5.8	2.7	5.1	1.9	virginica
3	7.1	3.0	5.9	2.1	virginica
4	6.3	2.9	5.6	1.8	virginica
5	6.5	3.0	5.8	2.2	virginica
6	7.6	3.0	6.6	2.1	virginica
  • stringr::str_detectを使えば多彩な文字列条件を適用できる
> iris %>% filter(str_detect(Species, 'v')) %>% group_by(Species) %>% count()
A grouped_df: 2 × 2
Species	n
<fct>	<int>
versicolor	50
virginica	50
  • 選択同様、論理演算が可能
> iris %>% filter(str_detect(Species, 'v') & str_detect(Species, 'ca')) %>% group_by(Species) %>% count()
A grouped_df: 1 × 2
Species	n
<fct>	<int>
virginica	50

Python

  • 抽出する場合は、queryメソッドを使うか、
> iris.query("sepal_width < 3.5").iloc[:6]
  • loc + λ式を使う。
    • 個人的にはこっちのほうが条件をダイナミックに変えやすいため好み
> iris.loc[lambda x: x['sepal_width'] < 3.5].iloc[:6]
sepal_length	sepal_width	petal_length	petal_width	species
1	4.9	3.0	1.4	0.2	setosa
2	4.7	3.2	1.3	0.2	setosa
3	4.6	3.1	1.5	0.2	setosa
6	4.6	3.4	1.4	0.3	setosa
7	5.0	3.4	1.5	0.2	setosa
8	4.4	2.9	1.4	0.2	setosa
  • 複数の列を使用する条件式も可能
> iris.loc[lambda x: x['sepal_width'] < x['sepal_length']*.8].iloc[:6]
sepal_length	sepal_width	petal_length	petal_width	species
0	5.1	3.5	1.4	0.2	setosa
1	4.9	3.0	1.4	0.2	setosa
2	4.7	3.2	1.3	0.2	setosa
3	4.6	3.1	1.5	0.2	setosa
4	5.0	3.6	1.4	0.2	setosa
5	5.4	3.9	1.7	0.4	setosa
  • リスト中のいずれかの値と一致する行を抽出する例
> iris.loc[lambda x: x['species'].isin(['virginica',''])].iloc[:6]
sepal_length	sepal_width	petal_length	petal_width	species
100	6.3	3.3	6.0	2.5	virginica
101	5.8	2.7	5.1	1.9	virginica
102	7.1	3.0	5.9	2.1	virginica
103	6.3	2.9	5.6	1.8	virginica
104	6.5	3.0	5.8	2.2	virginica
105	7.6	3.0	6.6	2.1	virginica
  • strアクセサを使えば多彩な文字列条件を適用できる
    • 下記は'v'を含むspeciesを抽出する例
> iris.loc[lambda x: x['species'].str.contains('v')].groupby('species').size()
species
versicolor    50
virginica     50
dtype: int64
  • 選択同様、ビット演算子が利用可能
> iris.loc[lambda x: x['species'].str.contains('v') & x['species'].str.contains('ca')].groupby('species').size()
species
virginica    50
dtype: int64
> iris.loc[lambda x: x['species'].str.contains('v|ca')].groupby('species').size()
species
versicolor    50
virginica     50
dtype: int64

カテゴリ化

  • 数値をカテゴリ化して集計するケース

R

  • mutateを使って新しいカラムを作成して使う
> iris %>% mutate(cat = Sepal.Width < 3.5) %>% group_by(cat) %>% count()
A grouped_df: 2 × 2
cat	n
<lgl>	<int>
FALSE	25
TRUE	125
  • カテゴリ毎にコード(A, B, C... 等)を振りたいときはif_else入れ子にして新しいカラムを作成する
> iris %>% mutate(cat = if_else(Sepal.Width < 3.5, 'A', if_else(Sepal.Width < 4.0, 'B', 'C'))) %>% group_by(cat) %>% count()
A grouped_df: 3 × 2
cat	n
<chr>	<int>
A	125
B	21
C	4
  • if_elseの中で複数のカラム(Sepal.WidthとSepal.Length)を使用することができる
> iris %>% mutate(cat = if_else(Sepal.Width < 3.5 & Petal.Length > 5.5, 'A', if_else(Sepal.Width < 4.0, 'B', 'C'))) %>% group_by(cat) %>% count()
A grouped_df: 3 × 2
cat	n
<chr>	<int>
A	22
B	124
C	4

Python

  • assignを使って新しいカラムを作成して使う
> iris.assign(cat = lambda x: x['sepal_width'] < 3.5).groupby('cat').size()
cat
False     25
True     125
dtype: int64
  • カテゴリ毎にコード(A, B, C... 等)を振りたいときはリスト内包表記の中で三項演算子if else入れ子にして新しいカラムを作成する
    • Python三項演算子の使い方は(Trueの値) if (条件式) else (Falseの値)である
    • Rに比べるとかなり面倒。もっといい方法はないものか。。。
> iris.assign(cat = lambda x: ['A' if i < 3.5 else 'B' if i < 4.0 else 'C' for i in x['sepal_width']]).groupby('cat').size()
cat
A    125
B     21
C      4
dtype: int64
  • 複数のカラム(Sepal.WidthとSepal.Length)を使う場合は、zipを用いる
> iris.assign(cat = lambda x: ['A' if i < 3.5 and j > 5.5 else 'B' if i < 4.0 else 'C' for i,j in zip(x['sepal_width'], x['petal_length'])]).groupby('cat').size()
cat
A     22
B    124
C      4
dtype: int64

集計

R

  • dplyr 1.0.0から集計時のungroupがデフォルトとなった
    • ただし、.groupsを指定しないとwarningが表示される
> iris %>%
+    group_by(Species) %>%
+    summarize(n = n(), .groups='drop')
A tibble: 3 × 2
Species	n
<fct>	<int>
setosa	50
versicolor	50
virginica	50
  • 複数の集計をまとめて行う場合
> iris %>%
+    group_by(Species) %>%
+    summarize(n = n(),
+              sum_sl = sum(Sepal.Length, na.rm=TRUE),
+              .groups='drop')
A tibble: 3 × 3
Species	n	sum_sl
<fct>	<int>	<dbl>
setosa	50	250.3
versicolor	50	296.8
virginica	50	329.4
  • 集計対象のカラムを条件で一括指定する場合、summarize_atを使用する
> iris %>%
+    group_by(Species) %>%
+    summarize_at(.vars=vars(ends_with('Width')), .funs=sum)
A tibble: 3 × 3
Species	Sepal.Width	Petal.Width
<fct>	<dbl>	<dbl>
setosa	171.4	12.3
versicolor	138.5	66.3
virginica	148.7	101.3
  • dplyr 1.0.0からは、acrossを用いて一括指定することもできる
> iris %>%
+    group_by(Species) %>%
+    summarize(across(ends_with('Width'), ~sum(.x)), .groups='drop')
A tibble: 3 × 3
Species	Sepal.Width	Petal.Width
<fct>	<dbl>	<dbl>
setosa	171.4	12.3
versicolor	138.5	66.3
virginica	148.7	101.3
  • acrossの中でも論理演算は有効
> iris %>%
+    group_by(Species) %>%
+    summarize(across(ends_with('Width') | starts_with('Petal'), ~sum(.x)), .groups='drop')
A tibble: 3 × 4
Species	Sepal.Width	Petal.Width	Petal.Length
<fct>	<dbl>	<dbl>	<dbl>
setosa	171.4	12.3	73.1
versicolor	138.5	66.3	213.0
virginica	148.7	101.3	277.6
  • 論理演算としてNot!を使うケース
> iris %>%
+    group_by(Species) %>%
+    summarize(across(!ends_with('Width'), ~sum(.x)), .groups='drop')
A tibble: 3 × 3
Species	Sepal.Length	Petal.Length
<fct>	<dbl>	<dbl>
setosa	250.3	73.1
versicolor	296.8	213.0
virginica	329.4	277.6
  • 適用する関数を複数指定することも可能
> iris %>%
+    group_by(Species) %>%
+    summarize(across(ends_with('Width') | starts_with('Petal'), list(~sum(.x), ~mean(.x))), .groups='drop')
A tibble: 3 × 7
Species	Sepal.Width_1	Sepal.Width_2	Petal.Width_1	Petal.Width_2	Petal.Length_1	Petal.Length_2
<fct>	<dbl>	<dbl>	<dbl>	<dbl>	<dbl>	<dbl>
setosa	171.4	3.428	12.3	0.246	73.1	1.462
versicolor	138.5	2.770	66.3	1.326	213.0	4.260
virginica	148.7	2.974	101.3	2.026	277.6	5.552
  • 適用する関数を名前付きリストで指定すれば集計結果のカラム名の接尾辞として使用される
> iris %>%
+    group_by(Species) %>%
+    summarize(across(ends_with('Width') | starts_with('Petal'), list(sum=~sum(.x), avg=~mean(.x))), .groups='drop')
A tibble: 3 × 7
Species	Sepal.Width_sum	Sepal.Width_avg	Petal.Width_sum	Petal.Width_avg	Petal.Length_sum	Petal.Length_avg
<fct>	<dbl>	<dbl>	<dbl>	<dbl>	<dbl>	<dbl>
setosa	171.4	3.428	12.3	0.246	73.1	1.462
versicolor	138.5	2.770	66.3	1.326	213.0	4.260
virginica	148.7	2.974	101.3	2.026	277.6	5.552
  • acrossとは別に集計を指定することも可能
    • これにより、一括でsumを求めつつ、レコードカウントも行うことが簡単になった
> iris %>%
+    group_by(Species) %>%
+    summarize(across(ends_with('Width') | starts_with('Petal'), list(sum=~sum(.x), avg=~mean(.x))),
+              n=n(),
+              .groups='drop')
A tibble: 3 × 8
Species	Sepal.Width_sum	Sepal.Width_avg	Petal.Width_sum	Petal.Width_avg	Petal.Length_sum	Petal.Length_avg	n
<fct>	<dbl>	<dbl>	<dbl>	<dbl>	<dbl>	<dbl>	<int>
setosa	171.4	3.428	12.3	0.246	73.1	1.462	50
versicolor	138.5	2.770	66.3	1.326	213.0	4.260	50
virginica	148.7	2.974	101.3	2.026	277.6	5.552	50
, avg=mean))
  • dplyr <1.0.0でなければsummarize_atを使うことは少なくなるだろう
> iris %>%
+    group_by(Species) %>%
+    summarize_at(vars(ends_with('Width') | starts_with('Petal')), list(sum=sum, avg=mean))
A tibble: 3 × 7
Species	Sepal.Width_sum	Petal.Width_sum	Petal.Length_sum	Sepal.Width_avg	Petal.Width_avg	Petal.Length_avg
<fct>	<dbl>	<dbl>	<dbl>	<dbl>	<dbl>	<dbl>
setosa	171.4	12.3	73.1	3.428	0.246	1.462
versicolor	138.5	66.3	213.0	2.770	1.326	4.260
virginica	148.7	101.3	277.6	2.974	2.026	5.552

Python

  • 基本はgroupby+集計用メソッド
    • 集計用メソッド:sizeminmaxcountmeanmedianstdなど
> iris.groupby(by='species').size()
species
setosa        50
versicolor    50
virginica     50
dtype: int64
  • 複数の集計を一括して行う場合はgroupby+agg
    • 辞書で{'集計を行うカラム名': ['集計関数1', '集計関数2', ...]}を渡す
    • 結果のDataFrameのカラム名はマルチインデックス(集計カラム名, 集計関数名)となる
> iris.groupby(by='species').agg({'sepal_width': ['count','sum'], 'sepal_length': 'sum'})
sepal_width	sepal_length
count	sum	sum
species			
setosa	50	171.4	250.3
versicolor	50	138.5	296.8
virginica	50	148.7	329.4
  • groupbyの後に.locを使うことができないため、集計対象のカラムをstrアクセサで一括指定することができない
  • 無理にやるのであれば下記のようにトリッキーになる。
> iris.loc[:, lambda x: x.columns.str.endswith('width') | (x.columns == 'species')].groupby(by='species').sum()
sepal_width	petal_width
species		
setosa	171.4	12.3
versicolor	138.5	66.3
virginica	148.7	101.3
  • aggの中で集計関数を条件分岐させるテクニックもあるようだが、これもやはりトリッキーであろう
> iris.groupby(by='species').agg(lambda x: x.sum() if x.name.endswith('width') else x.min())
sepal_length	sepal_width	petal_length	petal_width
species				
setosa	4.3	171.4	1.0	12.3
versicolor	4.9	138.5	3.0	66.3
virginica	4.9	148.7	4.5	101.3
  • 結局、集計関数をまとめて適用し、後で必要なカラムだけ取り出すのが無難な方法と思う
> df_01 = iris.groupby(by='species').agg(['count','sum'])
df_01
sepal_length	sepal_width	petal_length	petal_width
count	sum	count	sum	count	sum	count	sum
species								
setosa	50	250.3	50	171.4	50	73.1	50	12.3
versicolor	50	296.8	50	138.5	50	213.0	50	66.3
virginica	50	329.4	50	148.7	50	277.6	50	101.3
> df_01[[('sepal_length','count'), ('sepal_width','sum')]]
sepal_length	sepal_width
count	sum
species		
setosa	50	171.4
versicolor	50	138.5
virginica	50	148.7
  • 特定の集計結果だけ取り出すならばxsメソッドが使える
> df_01.xs('sum', axis=1, level=1)
sepal_length	sepal_width	petal_length	petal_width
species				
setosa	250.3	171.4	73.1	12.3
versicolor	296.8	138.5	213.0	66.3
virginica	329.4	148.7	277.6	101.3
  • カラム名にstrアクセサを使用するためには煩雑な方法を取らなければならない
    • カラム名(マルチインデックス)の0レベルには元のカラム名、1レベルには集計関数が入っている。
> df_01.loc[:, lambda x: x.columns.get_level_values(0).str.startswith('sepal') & x.columns.get_level_values(1).str.startswith('sum')]
sepal_length	sepal_width
sum	sum
species		
setosa	250.3	171.4
versicolor	296.8	138.5
virginica	329.4	148.7

集計値を新規カラムとして追加

  • グループごとの合計値を全レコードに追加したい場合、ランキングのカラムを追加したい場合など

R

  • group_by %>% mutateが簡単
> iris %>%
+    group_by(Species) %>%
+    mutate(sum_sepal_width = sum(Sepal.Width),
+           rnk = rank(Sepal.Width),
+           rnk2 = min_rank(Sepal.Width),
+           rnk3 = dense_rank(Sepal.Width),
+           rnk4 = rank(desc(Sepal.Width)),
+          ) %>% head()
A grouped_df: 6 × 10
Sepal.Length	Sepal.Width	Petal.Length	Petal.Width	Species	sum_sepal_width	rnk	rnk2	rnk3	rnk4
<dbl>	<dbl>	<dbl>	<dbl>	<fct>	<dbl>	<dbl>	<int>	<int>	<dbl>
5.1	3.5	1.4	0.2	setosa	171.4	31.5	29	8	19.5
4.9	3.0	1.4	0.2	setosa	171.4	5.5	3	3	45.5
4.7	3.2	1.3	0.2	setosa	171.4	15.0	13	5	36.0
4.6	3.1	1.5	0.2	setosa	171.4	10.5	9	4	40.5
5.0	3.6	1.4	0.2	setosa	171.4	36.0	35	9	15.0
5.4	3.9	1.7	0.4	setosa	171.4	45.5	45	12	5.5

Python

  • assignメソッドを使う
  • ただし、グループごとの合計値を全レコードに追加したい(つまり、集計(集約)関数の結果)場合、transformをかませる必要がある
> iris.assign(
...    sum_sepal_width = lambda x: x.groupby('species')['sepal_width'].transform('sum')
...    ).iloc[:6]
sepal_length	sepal_width	petal_length	petal_width	species	sum_sepal_width
0	5.1	3.5	1.4	0.2	setosa	171.4
1	4.9	3.0	1.4	0.2	setosa	171.4
2	4.7	3.2	1.3	0.2	setosa	171.4
3	4.6	3.1	1.5	0.2	setosa	171.4
4	5.0	3.6	1.4	0.2	setosa	171.4
5	5.4	3.9	1.7	0.4	setosa	171.4
  • ランキングなど、Window関数の結果ならば、λ式の中でそのまま使用できる
> iris.assign(
...    sum_sepal_width = lambda x: x.groupby('species')['sepal_width'].transform('sum'),
...    rnk  = lambda x: x.groupby('species')['sepal_width'].rank(),
...    rnk2 = lambda x: x.groupby('species')['sepal_width'].rank(method='min'),
...    rnk3 = lambda x: x.groupby('species')['sepal_width'].rank(method='dense'),
...    rnk4 = lambda x: x.groupby('species')['sepal_width'].rank(ascending=False),
...    ).iloc[:6]
sepal_length	sepal_width	petal_length	petal_width	species	sum_sepal_width	rnk	rnk2	rnk3	rnk4
0	5.1	3.5	1.4	0.2	setosa	171.4	31.5	29.0	8.0	19.5
1	4.9	3.0	1.4	0.2	setosa	171.4	5.5	3.0	3.0	45.5
2	4.7	3.2	1.3	0.2	setosa	171.4	15.0	13.0	5.0	36.0
3	4.6	3.1	1.5	0.2	setosa	171.4	10.5	9.0	4.0	40.5
4	5.0	3.6	1.4	0.2	setosa	171.4	36.0	35.0	9.0	15.0
5	5.4	3.9	1.7	0.4	setosa	171.4	45.5	45.0	12.0	5.5