Edited at

Python/pandasのデータ処理で再帰代入撲滅委員会


伝えたい事

R言語におけるmagrittrそしてdplyrによるデータハンドリングはとても心地が良いです.

データの処理のパイプラインが実に美しいです.

一方,いろんな方が書いたpandasにおけるデータを処理のコードを見ていると

df = df[df.a >0]

df = ...

と再帰代入を何度も繰り返していて美しくない.ややこしいことをいうと参照透過性を損う.

でも!!そんな再帰代入を繰り返さなくてもいい,pandasでもメソッドチェーンでデータ処理ができるってのが今日伝えたいことです.

とくにぜひ皆さんに使って欲しいmethodたち


  • pipe

  • assign

  • reset_index

  • set_index

  • group_by

  • pivot

  • stack

これらを頭に叩き込んで使ってもらうべく紹介するってのがこの記事の趣旨です.notebookからのmarkdown吐き出しなので多少の崩れはご容赦ください.

import numpy as np

import pandas as pd


今回使用するデータの生成

乱数で生成したこのデータが今日の相棒です.

df = pd.DataFrame(np.random.randn(20,5), columns=list('ABCDE'))

df




A
B
C
D
E




0
-0.489997
0.169059
1.743541
-0.432755
-0.595007


1
-1.530363
0.711810
-0.382714
-0.139916
-1.734980


2
-0.334975
1.045337
0.757287
1.351123
0.557953


3
0.744929
0.484988
0.429293
-3.272832
0.261902


4
0.407953
0.403938
0.265210
0.818324
-0.657293


5
-0.208507
-0.144381
-0.553875
-3.878549
-0.480763


6
0.019297
1.503824
0.680546
1.415549
-1.554857


7
1.544483
-0.209555
-0.446111
-0.785419
0.220515


8
-1.312732
1.321994
0.320443
-2.245312
-0.409711


9
-0.699864
0.050989
-0.189841
0.269374
-1.098471


10
1.120992
0.856170
0.223470
-0.822884
-0.140143


11
-1.173929
0.155096
-0.589718
0.049350
-0.001723


12
-0.295916
1.322868
-0.731492
-1.995471
-0.991209


13
1.804382
0.626075
-0.383017
1.078767
1.487689


14
-0.345145
-0.318551
-1.244325
0.541235
-0.261979


15
-1.335849
0.355642
2.910935
0.734953
-0.342311


16
1.148712
-0.285870
0.162114
-0.547444
2.438300


17
0.073855
-0.402590
-1.529420
-1.099915
-0.197386


18
-0.445434
0.468738
0.097532
1.569179
-0.393965


19
-1.885451
1.426260
-1.775148
0.993585
0.834851


lambda式

pythonには簡易な関数リテラルがあります.使い方は

lambda 仮引数: 返り値

です.


例:

func = lambda x: x**2

func(2)

4

func(3)

9


apply

各列(axis=0)または各行(axis=1)に対して関数を適用するメソッドです.返り値はpandas.Series


例:

df.apply(lambda x: sum(x), axis=1)

0     0.394842

1 -3.076163
2 3.376725
3 -1.351720
4 1.238132
5 -5.266074
6 2.064360
7 0.323913
8 -2.325318
9 -1.667813
10 1.237605
11 -1.560923
12 -2.691220
13 4.613897
14 -1.628766
15 2.323369
16 2.915812
17 -3.155455
18 1.296050
19 -0.405903
dtype: float64


assign

新たな列を作成するメソッドです.

返り値は同じくpandas.DataFrame

与える関数はpandas.DataFrameをうけとってpandas.Seriesを返すものであれば自由です.


例:

df.assign(

round_A=lambda df: df.A.round(), # 四捨五入
round_B=lambda df: df.B.round(), # 四捨五入
total=lambda df: df.apply(lambda row: sum(row), axis=1) # A-Eの和
)




A
B
C
D
E
round_A
round_B
total




0
-0.489997
0.169059
1.743541
-0.432755
-0.595007
-0
0
0.394842


1
-1.530363
0.711810
-0.382714
-0.139916
-1.734980
-2
1
-3.076163


2
-0.334975
1.045337
0.757287
1.351123
0.557953
-0
1
3.376725


3
0.744929
0.484988
0.429293
-3.272832
0.261902
1
0
-1.351720


4
0.407953
0.403938
0.265210
0.818324
-0.657293
0
0
1.238132


5
-0.208507
-0.144381
-0.553875
-3.878549
-0.480763
-0
-0
-5.266074


6
0.019297
1.503824
0.680546
1.415549
-1.554857
0
2
2.064360


7
1.544483
-0.209555
-0.446111
-0.785419
0.220515
2
-0
0.323913


8
-1.312732
1.321994
0.320443
-2.245312
-0.409711
-1
1
-2.325318


9
-0.699864
0.050989
-0.189841
0.269374
-1.098471
-1
0
-1.667813


10
1.120992
0.856170
0.223470
-0.822884
-0.140143
1
1
1.237605


11
-1.173929
0.155096
-0.589718
0.049350
-0.001723
-1
0
-1.560923


12
-0.295916
1.322868
-0.731492
-1.995471
-0.991209
-0
1
-2.691220


13
1.804382
0.626075
-0.383017
1.078767
1.487689
2
1
4.613897


14
-0.345145
-0.318551
-1.244325
0.541235
-0.261979
-0
-0
-1.628766


15
-1.335849
0.355642
2.910935
0.734953
-0.342311
-1
0
2.323369


16
1.148712
-0.285870
0.162114
-0.547444
2.438300
1
-0
2.915812


17
0.073855
-0.402590
-1.529420
-1.099915
-0.197386
0
-0
-3.155455


18
-0.445434
0.468738
0.097532
1.569179
-0.393965
-0
0
1.296050


19
-1.885451
1.426260
-1.775148
0.993585
0.834851
-2
1
-0.405903


列の選択

sqlで言うところのSelectは

df[['A', 'B']]

で実現できます

df.assign(

round_A=lambda df: df.A.round(), # 四捨五入
round_B=lambda df: df.B.round(), # 四捨五入
total=lambda df: df.apply(lambda row: sum(row), axis=1) # A-Eの和
)[['round_A', 'round_B', 'total']]




round_A
round_B
total




0
-0
0
0.394842


1
-2
1
-3.076163


2
-0
1
3.376725


3
1
0
-1.351720


4
0
0
1.238132


5
-0
-0
-5.266074


6
0
2
2.064360


7
2
-0
0.323913


8
-1
1
-2.325318


9
-1
0
-1.667813


10
1
1
1.237605


11
-1
0
-1.560923


12
-0
1
-2.691220


13
2
1
4.613897


14
-0
-0
-1.628766


15
-1
0
2.323369


16
1
-0
2.915812


17
0
-0
-3.155455


18
-0
0
1.296050


19
-2
1
-0.405903


rename

列の名前を書き換えたいときはrenameメソッドを使います.

df.assign(

round_A=lambda df: df.A.round(), # 四捨五入
round_B=lambda df: df.B.round(), # 四捨五入
total=lambda df: df.apply(lambda row: sum(row), axis=1) # A-Eの和
)[['round_A', 'round_B', 'total']].rename(columns={
'round_A': 'id',
'round_B': 'key',
'total': 'value'
})




id
key
value




0
-0
0
0.394842


1
-2
1
-3.076163


2
-0
1
3.376725


3
1
0
-1.351720


4
0
0
1.238132


5
-0
-0
-5.266074


6
0
2
2.064360


7
2
-0
0.323913


8
-1
1
-2.325318


9
-1
0
-1.667813


10
1
1
1.237605


11
-1
0
-1.560923


12
-0
1
-2.691220


13
2
1
4.613897


14
-0
-0
-1.628766


15
-1
0
2.323369


16
1
-0
2.915812


17
0
-0
-3.155455


18
-0
0
1.296050


19
-2
1
-0.405903


groupby().集計関数()

max以外にもavgsumなど基本的な集計関数が標準で備え付けられています.

返り値には階層的インデックスを持つDataFrameが返ってくるのですがこれが実はpandasのハマりどこだったりします.

df.assign(

round_A=lambda df: df.A.round(), # 四捨五入
round_B=lambda df: df.B.round(), # 四捨五入
total=lambda df: df.apply(lambda row: sum(row), axis=1) # A-Eの和
)[['round_A', 'round_B', 'total']].rename(columns={
'round_A': 'id',
'round_B': 'key',
'total': 'value'
}).groupby(['id', 'key']).max()





value


id
key





-2
1
-0.405903


-1
0
2.323369


1
-2.325318


-0
0
1.296050


1
3.376725


2
2.064360


1
0
2.915812


1
1.237605


2
0
0.323913


1
4.613897


reset_indexとset_index

indexをリセットしてデータとして扱い直します.新しいindexには再度通番が振られます.

set_indexは指定した列でindexを上書きします.

df.assign(

round_A=lambda df: df.A.round(), # 四捨五入
round_B=lambda df: df.B.round(), # 四捨五入
total=lambda df: df.apply(lambda row: sum(row), axis=1) # A-Eの和
)[['round_A', 'round_B', 'total']].rename(columns={
'round_A': 'id',
'round_B': 'key',
'total': 'value'
}).groupby(['id', 'key']).max().reset_index()




id
key
value




0
-2
1
-0.405903


1
-1
0
2.323369


2
-1
1
-2.325318


3
-0
0
1.296050


4
-0
1
3.376725


5
-0
2
2.064360


6
1
0
2.915812


7
1
1
1.237605


8
2
0
0.323913


9
2
1
4.613897

df.assign(

round_A=lambda df: df.A.round(), # 四捨五入
round_B=lambda df: df.B.round(), # 四捨五入
total=lambda df: df.apply(lambda row: sum(row), axis=1) # A-Eの和
)[['round_A', 'round_B', 'total']].rename(columns={
'round_A': 'id',
'round_B': 'key',
'total': 'value'
}).groupby(['id', 'key']).max().reset_index().set_index('id')




key
value


id






-2
1
-0.405903


-1
0
2.323369


-1
1
-2.325318


-0
0
1.296050


-0
1
3.376725


-0
2
2.064360


1
0
2.915812


1
1
1.237605


2
0
0.323913


2
1
4.613897


pipe

データフレーム全体に対する関数の適用です.とくに

df.pipe(lambda df: df[df.f1 > 0])

みたいないわゆるselect-where構文らしきあは頻出のイディオムです.

df.assign(

round_A=lambda df: df.A.round(), # 四捨五入
round_B=lambda df: df.B.round(), # 四捨五入
total=lambda df: df.apply(lambda row: sum(row), axis=1) # A-Eの和
)[['round_A', 'round_B', 'total']].rename(columns={
'round_A': 'id',
'round_B': 'key',
'total': 'value'
}).groupby(['id', 'key']).max().reset_index().set_index('id').pipe(
lambda df: df[df.value > -2]
)




key
value


id






-2
1
-0.405903


-1
0
2.323369


-0
0
1.296050


-0
1
3.376725


-0
2
2.064360


1
0
2.915812


1
1
1.237605


2
0
0.323913


2
1
4.613897

df.assign(

round_A=lambda df: df.A.round(), # 四捨五入
round_B=lambda df: df.B.round(), # 四捨五入
total=lambda df: df.apply(lambda row: sum(row), axis=1) # A-Eの和
)[['round_A', 'round_B', 'total']].rename(columns={
'round_A': 'id',
'round_B': 'key',
'total': 'value'
}).groupby(['id', 'key']).max().reset_index().set_index('id').pipe(
lambda df: df[df.value > -2]
).pipe(
lambda df: df.add_suffix('_l').join(df.add_suffix('_r')) # suffixを追加して自分と結合
)




key_l
value_l
key_r
value_r


id








-2
1
-0.405903
1
-0.405903


-1
0
2.323369
0
2.323369


-0
0
1.296050
0
1.296050


-0
0
1.296050
1
3.376725


-0
0
1.296050
2
2.064360


-0
1
3.376725
0
1.296050


-0
1
3.376725
1
3.376725


-0
1
3.376725
2
2.064360


-0
2
2.064360
0
1.296050


-0
2
2.064360
1
3.376725


-0
2
2.064360
2
2.064360


1
0
2.915812
0
2.915812


1
0
2.915812
1
1.237605


1
1
1.237605
0
2.915812


1
1
1.237605
1
1.237605


2
0
0.323913
0
0.323913


2
0
0.323913
1
4.613897


2
1
4.613897
0
0.323913


2
1
4.613897
1
4.613897


一旦いろいろ整理

df.assign(

round_A=lambda df: df.A.round(), # 四捨五入
round_B=lambda df: df.B.round(), # 四捨五入
total=lambda df: df.apply(lambda row: sum(row), axis=1) # A-Eの和
)[['round_A', 'round_B', 'total']].rename(columns={
'round_A': 'id',
'round_B': 'key',
'total': 'value'
}).groupby(['id', 'key']).max().reset_index().set_index('id').pipe(
lambda df: df[df.value > -2]
).pipe(
lambda df: df.add_suffix('_l').join(df.add_suffix('_r'))
).reset_index().groupby(['id', 'key_l']).sum().reset_index().assign(
key=lambda df: df.value_l.map(lambda x: x*10).round().map(lambda x: 'label' + str(int(x)))
).rename(columns={
'value_r': 'value'
})[['key', 'value']]




key
value




0
label-4
-0.405903


1
label23
2.323369


2
label39
6.737135


3
label101
6.737135


4
label62
6.737135


5
label58
4.153417


6
label25
4.153417


7
label6
4.937809


8
label92
4.937809


pivot

いわゆる'縦持ち'から'横持ち'への変換です.

ちなみに無名のindexに対してreset_index()を使うと新たにindexという列が出来る

df.assign(

round_A=lambda df: df.A.round(), # 四捨五入
round_B=lambda df: df.B.round(), # 四捨五入
total=lambda df: df.apply(lambda row: sum(row), axis=1) # A-Eの和
)[['round_A', 'round_B', 'total']].rename(columns={
'round_A': 'id',
'round_B': 'key',
'total': 'value'
}).groupby(['id', 'key']).max().reset_index().set_index('id').pipe(
lambda df: df[df.value > -2]
).pipe(
lambda df: df.add_suffix('_l').join(df.add_suffix('_r'))
).reset_index().groupby(['id', 'key_l']).sum().reset_index().assign(
key=lambda df: df.value_l.map(lambda x: x*10).round().map(lambda x: 'label' + str(int(x)))
).rename(columns={
'value_r': 'value'
})[['key', 'value']].reset_index()




index
key
value




0
0
label-4
-0.405903


1
1
label23
2.323369


2
2
label39
6.737135


3
3
label101
6.737135


4
4
label62
6.737135


5
5
label58
4.153417


6
6
label25
4.153417


7
7
label6
4.937809


8
8
label92
4.937809

df.assign(

round_A=lambda df: df.A.round(), # 四捨五入
round_B=lambda df: df.B.round(), # 四捨五入
total=lambda df: df.apply(lambda row: sum(row), axis=1) # A-Eの和
)[['round_A', 'round_B', 'total']].rename(columns={
'round_A': 'id',
'round_B': 'key',
'total': 'value'
}).groupby(['id', 'key']).max().reset_index().set_index('id').pipe(
lambda df: df[df.value > -2]
).pipe(
lambda df: df.add_suffix('_l').join(df.add_suffix('_r'))
).reset_index().groupby(['id', 'key_l']).sum().reset_index().assign(
key=lambda df: df.value_l.map(lambda x: x*10).round().map(lambda x: 'label' + str(int(x)))
).rename(columns={
'value_r': 'value'
})[['key', 'value']].reset_index().pivot(
'index',
'key',
'value'
)



key
label-4
label101
label23
label25
label39
label58
label6
label62
label92


index













0
-0.405903
NaN
NaN
NaN
NaN
NaN
NaN
NaN
NaN


1
NaN
NaN
2.323369
NaN
NaN
NaN
NaN
NaN
NaN


2
NaN
NaN
NaN
NaN
6.737135
NaN
NaN
NaN
NaN


3
NaN
6.737135
NaN
NaN
NaN
NaN
NaN
NaN
NaN


4
NaN
NaN
NaN
NaN
NaN
NaN
NaN
6.737135
NaN


5
NaN
NaN
NaN
NaN
NaN
4.153417
NaN
NaN
NaN


6
NaN
NaN
NaN
4.153417
NaN
NaN
NaN
NaN
NaN


7
NaN
NaN
NaN
NaN
NaN
NaN
4.937809
NaN
NaN


8
NaN
NaN
NaN
NaN
NaN
NaN
NaN
NaN
4.937809


fillna

いわゆるnull値を埋める.

df.assign(

round_A=lambda df: df.A.round(), # 四捨五入
round_B=lambda df: df.B.round(), # 四捨五入
total=lambda df: df.apply(lambda row: sum(row), axis=1) # A-Eの和
)[['round_A', 'round_B', 'total']].rename(columns={
'round_A': 'id',
'round_B': 'key',
'total': 'value'
}).groupby(['id', 'key']).max().reset_index().set_index('id').pipe(
lambda df: df[df.value > -2]
).pipe(
lambda df: df.add_suffix('_l').join(df.add_suffix('_r'))
).reset_index().groupby(['id', 'key_l']).sum().reset_index().assign(
key=lambda df: df.value_l.map(lambda x: x*10).round().map(lambda x: 'label' + str(int(x)))
).rename(columns={
'value_r': 'value'
})[['key', 'value']].reset_index().pivot(
'index',
'key',
'value'
).fillna(0)



key
label-4
label101
label23
label25
label39
label58
label6
label62
label92


index













0
-0.405903
0.000000
0.000000
0.000000
0.000000
0.000000
0.000000
0.000000
0.000000


1
0.000000
0.000000
2.323369
0.000000
0.000000
0.000000
0.000000
0.000000
0.000000


2
0.000000
0.000000
0.000000
0.000000
6.737135
0.000000
0.000000
0.000000
0.000000


3
0.000000
6.737135
0.000000
0.000000
0.000000
0.000000
0.000000
0.000000
0.000000


4
0.000000
0.000000
0.000000
0.000000
0.000000
0.000000
0.000000
6.737135
0.000000


5
0.000000
0.000000
0.000000
0.000000
0.000000
4.153417
0.000000
0.000000
0.000000


6
0.000000
0.000000
0.000000
4.153417
0.000000
0.000000
0.000000
0.000000
0.000000


7
0.000000
0.000000
0.000000
0.000000
0.000000
0.000000
4.937809
0.000000
0.000000


8
0.000000
0.000000
0.000000
0.000000
0.000000
0.000000
0.000000
0.000000
4.937809


astype

データ型のキャスト.csvに書きだしたとき 0.0000000....ってならないようになります.

本当はもうちょっと複雑ですがきほんはこれです.

df.assign(

round_A=lambda df: df.A.round(), # 四捨五入
round_B=lambda df: df.B.round(), # 四捨五入
total=lambda df: df.apply(lambda row: sum(row), axis=1) # A-Eの和
)[['round_A', 'round_B', 'total']].rename(columns={
'round_A': 'id',
'round_B': 'key',
'total': 'value'
}).groupby(['id', 'key']).max().reset_index().set_index('id').pipe(
lambda df: df[df.value > -2]
).pipe(
lambda df: df.add_suffix('_l').join(df.add_suffix('_r'))
).reset_index().groupby(['id', 'key_l']).sum().reset_index().assign(
key=lambda df: df.value_l.map(lambda x: x*10).round().map(lambda x: 'label' + str(int(x)))
).rename(columns={
'value_r': 'value'
})[['key', 'value']].reset_index().pivot(
'index',
'key',
'value'
).fillna(0).astype(np.int8)



key
label-4
label101
label23
label25
label39
label58
label6
label62
label92


index













0
0
0
0
0
0
0
0
0
0


1
0
0
2
0
0
0
0
0
0


2
0
0
0
0
6
0
0
0
0


3
0
6
0
0
0
0
0
0
0


4
0
0
0
0
0
0
0
6
0


5
0
0
0
0
0
4
0
0
0


6
0
0
0
4
0
0
0
0
0


7
0
0
0
0
0
0
4
0
0


8
0
0
0
0
0
0
0
0
4


stack

いわゆる横持ちから縦持ちへの変換.

階層インデックス持ちのSeriesが帰ります.データフレームの世界で輝き続けるにはpipeと一緒に使います.

df.assign(

round_A=lambda df: df.A.round(), # 四捨五入
round_B=lambda df: df.B.round(), # 四捨五入
total=lambda df: df.apply(lambda row: sum(row), axis=1) # A-Eの和
)[['round_A', 'round_B', 'total']].rename(columns={
'round_A': 'id',
'round_B': 'key',
'total': 'value'
}).groupby(['id', 'key']).max().reset_index().set_index('id').pipe(
lambda df: df[df.value > -2]
).pipe(
lambda df: df.add_suffix('_l').join(df.add_suffix('_r'))
).reset_index().groupby(['id', 'key_l']).sum().reset_index().assign(
key=lambda df: df.value_l.map(lambda x: x*10).round().map(lambda x: 'label' + str(int(x)))
).rename(columns={
'value_r': 'value'
})[['key', 'value']].reset_index().pivot(
'index',
'key',
'value'
).fillna(0).astype(np.int8).stack()

index  key     

0 label-4 0
label101 0
label23 0
label25 0
label39 0
label58 0
label6 0
label62 0
label92 0
1 label-4 0
label101 0
label23 2
label25 0
label39 0
label58 0
label6 0
label62 0
label92 0
2 label-4 0
label101 0
label23 0
label25 0
label39 6
label58 0
label6 0
label62 0
label92 0
3 label-4 0
label101 6
label23 0
..
5 label6 0
label62 0
label92 0
6 label-4 0
label101 0
label23 0
label25 4
label39 0
label58 0
label6 0
label62 0
label92 0
7 label-4 0
label101 0
label23 0
label25 0
label39 0
label58 0
label6 4
label62 0
label92 0
8 label-4 0
label101 0
label23 0
label25 0
label39 0
label58 0
label6 0
label62 0
label92 4
dtype: int8

df.assign(

round_A=lambda df: df.A.round(), # 四捨五入
round_B=lambda df: df.B.round(), # 四捨五入
total=lambda df: df.apply(lambda row: sum(row), axis=1) # A-Eの和
)[['round_A', 'round_B', 'total']].rename(columns={
'round_A': 'id',
'round_B': 'key',
'total': 'value'
}).groupby(['id', 'key']).max().reset_index().set_index('id').pipe(
lambda df: df[df.value > -2]
).pipe(
lambda df: df.add_suffix('_l').join(df.add_suffix('_r'))
).reset_index().groupby(['id', 'key_l']).sum().reset_index().assign(
key=lambda df: df.value_l.map(lambda x: x*10).round().map(lambda x: 'label' + str(int(x)))
).rename(columns={
'value_r': 'value'
})[['key', 'value']].reset_index().pivot(
'index',
'key',
'value'
).fillna(0).astype(np.int8).pipe(
lambda df: pd.DataFrame({'value':df.stack()})
)





value


index
key





0
label-4
0


label101
0


label23
0


label25
0


label39
0


label58
0


label6
0


label62
0


label92
0


1
label-4
0


label101
0


label23
2


label25
0


label39
0


label58
0


label6
0


label62
0


label92
0


2
label-4
0


label101
0


label23
0


label25
0


label39
6


label58
0


label6
0


label62
0


label92
0


3
label-4
0


label101
6


label23
0


...
...
...


5
label6
0


label62
0


label92
0


6
label-4
0


label101
0


label23
0


label25
4


label39
0


label58
0


label6
0


label62
0


label92
0


7
label-4
0


label101
0


label23
0


label25
0


label39
0


label58
0


label6
4


label62
0


label92
0


8
label-4
0


label101
0


label23
0


label25
0


label39
0


label58
0


label6
0


label62
0


label92
4

81 rows × 1 columns


df.assign(

round_A=lambda df: df.A.round(), # 四捨五入
round_B=lambda df: df.B.round(), # 四捨五入
total=lambda df: df.apply(lambda row: sum(row), axis=1) # A-Eの和
)[['round_A', 'round_B', 'total']].rename(columns={
'round_A': 'id',
'round_B': 'key',
'total': 'value'
}).groupby(['id', 'key']).max().reset_index().set_index('id').pipe(
lambda df: df[df.value > -2]
).pipe(
lambda df: df.add_suffix('_l').join(df.add_suffix('_r'))
).reset_index().groupby(['id', 'key_l']).sum().reset_index().assign(
key=lambda df: df.value_l.map(lambda x: x*10).round().map(lambda x: 'label' + str(int(x)))
).rename(columns={
'value_r': 'value'
})[['key', 'value']].reset_index().pivot(
'index',
'key',
'value'
).fillna(0).astype(np.int8).pipe(
lambda df: pd.DataFrame({'value':df.stack()})
).pipe(
lambda df: df[df.value != 0]
)





value


index
key





1
label23
2


2
label39
6


3
label101
6


4
label62
6


5
label58
4


6
label25
4


7
label6
4


8
label92
4


さいごに

ほらね?再帰代入なんてもうやめよみんな!!