Pandas
前回、Pandasで行方向にデータを追加する方法を紹介しました。
今回はPandasで列方向にデータを追加する方法を紹介します。
それでは始めていきましょう。
df[列名]でデータを追加
データフレームに列としてデータを追加する方法としては「df[列名]」でデータを追加する方法があります。
辞書の様に追加できることから簡単に使える方法です。
import pandas as pd
import numpy as np
column_num = 10
df = pd.DataFrame()
rng = np.random.default_rng()
for c_num in range(column_num):
df[c_num] = rng.random(10)
print(df)
実行結果
0 1 2 3 4 5 6 \
0 0.092656 0.588085 0.532506 0.620316 0.746281 0.901826 0.545977
1 0.249781 0.452919 0.896740 0.204829 0.795558 0.912468 0.218823
2 0.944426 0.131438 0.094824 0.322589 0.834228 0.689732 0.730281
3 0.014335 0.750955 0.810115 0.174651 0.229884 0.236513 0.527441
4 0.189177 0.806379 0.416009 0.006121 0.729997 0.497447 0.846570
5 0.828416 0.219259 0.500104 0.777865 0.523318 0.471064 0.403795
6 0.447570 0.684697 0.773767 0.030717 0.982740 0.672824 0.295245
7 0.654365 0.677355 0.067456 0.132455 0.221908 0.638855 0.197908
8 0.913537 0.822408 0.069830 0.205479 0.446807 0.599840 0.611137
9 0.225850 0.055669 0.051397 0.863112 0.408996 0.892111 0.916572
7 8 9
0 0.046294 0.908354 0.442617
1 0.763491 0.751801 0.457829
2 0.835838 0.370997 0.630565
3 0.082151 0.835465 0.621463
4 0.440525 0.337358 0.508486
5 0.161462 0.401410 0.112175
6 0.239742 0.712198 0.131989
7 0.770848 0.707108 0.046263
8 0.881027 0.071912 0.824282
9 0.290916 0.062953 0.304602
データはNumPyの乱数ジェネレータを使って作成しています。
NumPyの乱数ジェネレータに関してはこちらの記事で紹介していますので、よかったらどうぞ。
この方法は気軽に使える反面、データが多くなると警告が表示されます。
import pandas as pd
import numpy as np
column_num = 1000
df = pd.DataFrame()
rng = np.random.default_rng()
for c_num in range(column_num):
df[c_num] = rng.random(10)
print(df)
実行結果
0 1 2 3 4 5 6 \
0 0.733494 0.629504 0.509985 0.825894 0.918788 0.550446 0.084953
1 0.760066 0.849370 0.062400 0.060143 0.805701 0.553981 0.280778
2 0.961861 0.400218 0.857443 0.422398 0.208799 0.095947 0.596483
3 0.195917 0.340802 0.054104 0.147578 0.857959 0.935003 0.177356
4 0.361968 0.459286 0.266768 0.819802 0.647429 0.886624 0.108233
5 0.126987 0.947966 0.041688 0.495567 0.943472 0.507224 0.003541
6 0.261173 0.586281 0.538216 0.315045 0.792654 0.259711 0.907976
7 0.208204 0.228209 0.276961 0.065344 0.797434 0.954079 0.688665
8 0.603933 0.050230 0.967057 0.385749 0.510954 0.113342 0.252529
9 0.182743 0.380019 0.273160 0.060995 0.949326 0.223114 0.536474
7 8 9 ... 990 991 992 993 \
0 0.883164 0.709349 0.183049 ... 0.933866 0.040979 0.975156 0.464766
1 0.849817 0.429039 0.003395 ... 0.024883 0.596757 0.115032 0.541966
2 0.863383 0.092015 0.535166 ... 0.011203 0.202082 0.003687 0.207222
3 0.742999 0.123932 0.083437 ... 0.443101 0.087289 0.965444 0.457584
4 0.586670 0.103896 0.303144 ... 0.336918 0.717651 0.292918 0.106690
5 0.538667 0.960127 0.029582 ... 0.720822 0.655445 0.685659 0.575143
6 0.351879 0.289922 0.201163 ... 0.644014 0.115342 0.817834 0.518394
7 0.713238 0.525287 0.423531 ... 0.390353 0.452647 0.392868 0.802239
8 0.974515 0.962060 0.314861 ... 0.307875 0.709946 0.889314 0.643739
9 0.331779 0.706041 0.360907 ... 0.234418 0.102739 0.276772 0.435830
994 995 996 997 998 999
0 0.807274 0.644940 0.542253 0.078494 0.536312 0.456097
1 0.101826 0.940361 0.277023 0.458885 0.844071 0.709311
2 0.791395 0.287934 0.267872 0.755436 0.857506 0.142931
3 0.816948 0.013948 0.474316 0.425016 0.096720 0.710496
4 0.216597 0.812262 0.038335 0.895418 0.449557 0.218864
5 0.060690 0.813329 0.617684 0.041414 0.090541 0.911312
6 0.649904 0.335219 0.862966 0.200078 0.580466 0.295298
7 0.224957 0.245704 0.148834 0.321497 0.322426 0.038557
8 0.891455 0.508967 0.581011 0.696066 0.041718 0.668692
9 0.934877 0.248474 0.477411 0.304963 0.228504 0.957152
[10 rows x 1000 columns]
/var/folders/sp/hg7p80kx22s7vct7yb0zl5cm0000gn/T/ipykernel_13283/
4074519197.py:11: PerformanceWarning: DataFrame is highly fragmented.
This is usually the result of calling `frame.insert` many times,
which has poor performance. Consider joining all columns at once
using pd.concat(axis=1) instead. To get a de-fragmented frame,
use `newframe = frame.copy()`
df[c_num] = rng.random(10)
どうやらこの方法はあまりパフォーマンス的に良い方法ではないとのことで、代わりに「pd.concat(axis=1)」を勧められます。
ということで試してみます。
import pandas as pd
import numpy as np
column_num = 1000
df = pd.DataFrame()
rng = np.random.default_rng()
for c_num in range(column_num):
df_add = pd.DataFrame(rng.random(10), columns=[c_num])
df = pd.concat([df, df_add], axis=1)
print(df)
実行結果
0 1 2 3 4 5 6 \
0 0.786263 0.340479 0.992491 0.747589 0.434493 0.771517 0.453220
1 0.885337 0.268389 0.314073 0.234762 0.330169 0.416728 0.973739
2 0.361635 0.017073 0.998744 0.056415 0.532284 0.870129 0.653355
3 0.574577 0.322628 0.769415 0.718639 0.514957 0.472393 0.424075
4 0.300638 0.796059 0.427357 0.817731 0.033193 0.378891 0.127753
5 0.926530 0.051283 0.587905 0.087341 0.191238 0.527160 0.141225
6 0.976033 0.437607 0.730176 0.197983 0.802466 0.266694 0.409749
7 0.587569 0.530384 0.919754 0.679826 0.038273 0.480210 0.239273
8 0.686917 0.356358 0.570043 0.712713 0.029657 0.281358 0.971709
9 0.353700 0.225141 0.183434 0.587338 0.826032 0.202260 0.630070
7 8 9 ... 990 991 992 993 \
0 0.331685 0.892849 0.585956 ... 0.328649 0.197003 0.940035 0.478013
1 0.303131 0.113920 0.184395 ... 0.795621 0.816141 0.489325 0.112984
2 0.665722 0.286215 0.461396 ... 0.966153 0.200030 0.772767 0.611956
3 0.503761 0.929764 0.288608 ... 0.827622 0.206803 0.694326 0.544831
4 0.867214 0.835498 0.060055 ... 0.625875 0.617611 0.880740 0.086261
5 0.824891 0.164958 0.513704 ... 0.872523 0.065001 0.804279 0.023696
6 0.427018 0.422756 0.550454 ... 0.623516 0.751547 0.354685 0.234894
7 0.950831 0.520808 0.595640 ... 0.523113 0.397560 0.436270 0.324722
8 0.415023 0.514080 0.127320 ... 0.715707 0.203550 0.213739 0.145915
9 0.463468 0.551637 0.051414 ... 0.750758 0.673031 0.840803 0.953849
994 995 996 997 998 999
0 0.636352 0.676099 0.129913 0.990963 0.440906 0.254350
1 0.571050 0.637301 0.182800 0.761227 0.887743 0.178316
2 0.500451 0.912980 0.231769 0.819632 0.656509 0.463165
3 0.732940 0.365772 0.721172 0.793519 0.962898 0.750543
4 0.106167 0.523814 0.814335 0.670908 0.916438 0.705283
5 0.888895 0.263819 0.416420 0.239587 0.514156 0.780250
6 0.823298 0.133149 0.958439 0.329760 0.573206 0.005511
7 0.034202 0.773206 0.936291 0.308396 0.370357 0.686141
8 0.605946 0.029003 0.686984 0.744579 0.700958 0.577575
9 0.022187 0.626076 0.002610 0.935992 0.077373 0.148206
[10 rows x 1000 columns]
無事追加できました。
辞書を作成してからデータフレームに変換
「pd.concat()」で追加できるのは分かったのですが、これまでの「df[列名]」に比べると追加の方法が複雑で覚えにくいです。
そんな時はいきなりデータフレームを作成してデータを追加していくのではなく、一旦辞書を作成し、データを追加、最後にその辞書をデータフレームへ変換してしまう方法の方が分かりやすいです。
つまりこんな感じです。
import pandas as pd
import numpy as np
column_num = 1000
rng = np.random.default_rng()
data_dic = {}
for c_num in range(column_num):
data_dic[c_num] = rng.random(10)
df = pd.DataFrame(data_dic)
print(df)
実行結果
0 1 2 3 4 5 6 \
0 0.950443 0.510381 0.380969 0.186369 0.205019 0.311203 0.953946
1 0.449400 0.478602 0.212552 0.943630 0.890136 0.534205 0.581683
2 0.882497 0.613497 0.786964 0.026933 0.369672 0.974456 0.198081
3 0.017958 0.225856 0.665516 0.481735 0.045476 0.301894 0.946426
4 0.757976 0.582993 0.688813 0.689700 0.829662 0.762571 0.730270
5 0.704493 0.291093 0.692176 0.922951 0.726470 0.109277 0.409830
6 0.841655 0.083388 0.845499 0.428125 0.250047 0.208356 0.076435
7 0.645744 0.087695 0.909819 0.006695 0.253948 0.258853 0.104530
8 0.851999 0.736562 0.567915 0.559663 0.954158 0.244089 0.720233
9 0.157651 0.172517 0.758822 0.297292 0.691787 0.672509 0.292546
7 8 9 ... 990 991 992 993 \
0 0.042144 0.920046 0.066642 ... 0.485595 0.313384 0.201674 0.080643
1 0.544037 0.115706 0.609323 ... 0.594952 0.023881 0.940372 0.292379
2 0.034513 0.780951 0.690990 ... 0.580228 0.920914 0.015200 0.789194
3 0.938626 0.211889 0.146446 ... 0.248981 0.483250 0.645695 0.411195
4 0.539950 0.535007 0.492523 ... 0.080248 0.177837 0.335017 0.481670
5 0.347672 0.193756 0.862501 ... 0.992088 0.068966 0.709499 0.462312
6 0.193551 0.625353 0.813343 ... 0.743419 0.178910 0.883817 0.164956
7 0.151856 0.500251 0.931229 ... 0.717289 0.105110 0.593391 0.996897
8 0.592530 0.979624 0.278176 ... 0.226373 0.014485 0.345073 0.601564
9 0.963083 0.572512 0.850270 ... 0.317426 0.946826 0.335413 0.680110
994 995 996 997 998 999
0 0.717807 0.547350 0.332791 0.020598 0.628083 0.516784
1 0.035564 0.705203 0.051547 0.688690 0.263680 0.119006
2 0.151079 0.957535 0.741834 0.156663 0.332617 0.756040
3 0.144769 0.372371 0.144077 0.554499 0.381099 0.409673
4 0.048370 0.412778 0.686117 0.544331 0.554991 0.603065
5 0.680707 0.386414 0.255685 0.272824 0.348710 0.883415
6 0.230230 0.110729 0.131618 0.810427 0.454233 0.559577
7 0.187140 0.898828 0.757570 0.071891 0.098087 0.051177
8 0.988727 0.580772 0.982452 0.384399 0.377691 0.945710
9 0.130793 0.689802 0.638921 0.902125 0.649613 0.218007
[10 rows x 1000 columns]
実行速度を比較してみた
パフォーマンスうんぬんという話が出てきたのでJupyter notebookのマジックコマンド「%%timeit」を使って実行速度を比較してみましょう。
ちなみに最後のデータフレームの出力は省略しておきます。
まずは「df[列名]」でデータを追加する方法です。
%%timeit
import pandas as pd
import numpy as np
column_num = 1000
df = pd.DataFrame()
rng = np.random.default_rng()
for c_num in range(column_num):
df[c_num] = rng.random(10)
実行結果
<magic-timeit>:11: PerformanceWarning: DataFrame is highly
fragmented. This is usually the result of calling `frame.insert`
many times, which has poor performance. Consider joining all
columns at once using pd.concat(axis=1) instead. To get a
de-fragmented frame, use `newframe = frame.copy()`
(中略)
296 ms ± 65.8 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
次に「pd.concat()」を使う方法です。
%%timeit
import pandas as pd
import numpy as np
column_num = 1000
df = pd.DataFrame()
rng = np.random.default_rng()
for c_num in range(column_num):
df_add = pd.DataFrame(rng.random(10), columns=[c_num])
df = pd.concat([df, df_add], axis=1)
実行結果
1.86 s ± 46.1 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
最後に辞書からデータフレームに変換する方法です。
%%timeit
import pandas as pd
import numpy as np
column_num = 1000
rng = np.random.default_rng()
data_dic = {}
for c_num in range(column_num):
data_dic[c_num] = rng.random(10)
df = pd.DataFrame(data_dic)
実行結果
10.3 ms ± 98.9 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
「df[列名]」が296ミリ秒、「pd.concat()」が1.86秒、辞書からデータフレームに変換する方法が10.3ミリ秒ということで、圧倒的に辞書からデータフレームに変換する方法が速かったです。
驚いたのは「df[列名]」の代替案として示された「pd.concat()」が圧倒的に遅かったことです。
どうやら警告メッセージ「Consider joining all columns at once using pd.concat(axis=1) instead.」に書かれている中で「at once(同時に)」が重要なのであって「pd.concat()」が重要なのではないと思われます。
そのため最後の辞書からデータフレームに変換する方法、つまり「at once」の方法が圧倒的に速かったのではないでしょうか。
ということでできる限り辞書等でデータをまとめ、データフレームに変換するという方法を取るのが良さそうです。
次回はPandasのデータフレーム内の行列のデータ、もしくはデータフレームをリストに変換する方法を紹介します。
ではでは今回はこんな感じで。
コメント