・pandasを使った解法で問題ございませんが、ライブラリを使わないとかなり大変な作業になりますでしょうか。
そこまで大変・・・という程のものでもないのですが、ライブラリを使った方がやはり楽なのと、この手のものは大体Pandas・・・という印象なので、今後もPythonでこういった作業をやる場合はライブラリをインストールしておくと便利だと思います!
Pandasのインストールは色々な記事が既に世の中に色々あるのでここでは割愛いたします!Anacondaなどの最初からインストールされているものを使うか、pip install pandas
といったpipのコマンドで(エラーにならなければ)入ると思います!
まずデータに関してですが、雑ではありますがそれっぽいサンプルデータを用意しておきました!
インストール済みのPandasライブラリを使う場合、import pandas as pd
といった記述が必要になります。
Pandasで読み込む場合pd.read_csv
関数で第一引数にパスを指定することで対応ができます!GitHubのURLを使うこともできますので、サンプルコードではGitHubのURLを指定していますが、ローカルで扱う場合にはURLの代わりに./sample_data.csv
みたいな指定に書き換えをお願いします!
import pandas as pd
# ローカルファイルから読み込む場合は、 pd.read_csv('./sample_data.csv')
# といったような指定になります。
df: pd.DataFrame = pd.read_csv('https://raw.githubusercontent.com/simon-ritchie/note/master/20210830_qiita_question/sample_data.csv')
print(df)
以下のような内容にしてあります。
visit_date visit_time unix_time user
0 2021-08-25 2021-08-25 00:03:11 1629817391 F
1 2021-08-25 2021-08-25 00:04:49 1629817489 F
2 2021-08-25 2021-08-25 00:08:15 1629817695 B
3 2021-08-25 2021-08-25 00:11:25 1629817885 A
4 2021-08-25 2021-08-25 00:12:32 1629817952 H
.. ... ... ... ...
995 2021-08-30 2021-08-30 14:39:32 1630301972 G
996 2021-08-30 2021-08-30 14:45:20 1630302320 A
997 2021-08-30 2021-08-30 14:49:58 1630302598 C
998 2021-08-30 2021-08-30 14:50:27 1630302627 G
999 2021-08-30 2021-08-30 14:50:52 1630302652 A
コードは以下のようにしてみました!(各行の説明は順番に触れていきます)
from typing import List
import pandas as pd
# GitHub上のCSVからデータを読み込んでいます。
df: pd.DataFrame = pd.read_csv('https://raw.githubusercontent.com/simon-ritchie/note/master/20210830_qiita_question/sample_data.csv')
pv_list: List[int] = []
for index, sr in df.iterrows():
user: str = sr['user']
unix_time: int = int(sr['unix_time'])
three_days_ago_unixtime: int = unix_time - 259200
sliced_df: pd.DataFrame = df[df['user'] == user]
sliced_df = sliced_df[sliced_df['unix_time'] >= three_days_ago_unixtime]
sliced_df = sliced_df[sliced_df['unix_time'] <= unix_time]
pv: int = len(sliced_df)
pv_list.append(pv)
df['pv'] = pv_list
print(df.head(50))
print(df.tail(50))
df.to_csv('result.csv', index=False, encoding='utf-8')
計算結果は以下のようになります!(先頭と末尾の50件ずつを表示しております)
visit_date visit_time unix_time user pv
0 2021-08-25 2021-08-25 00:03:11 1629817391 F 1
1 2021-08-25 2021-08-25 00:04:49 1629817489 F 2
2 2021-08-25 2021-08-25 00:08:15 1629817695 B 1
3 2021-08-25 2021-08-25 00:11:25 1629817885 A 1
4 2021-08-25 2021-08-25 00:12:32 1629817952 H 1
5 2021-08-25 2021-08-25 00:14:13 1629818053 C 1
6 2021-08-25 2021-08-25 00:20:59 1629818459 F 3
7 2021-08-25 2021-08-25 00:49:12 1629820152 D 1
8 2021-08-25 2021-08-25 00:59:20 1629820760 B 2
9 2021-08-25 2021-08-25 01:16:32 1629821792 B 3
10 2021-08-25 2021-08-25 01:24:49 1629822289 G 1
11 2021-08-25 2021-08-25 01:45:39 1629823539 E 1
12 2021-08-25 2021-08-25 01:47:22 1629823642 D 2
13 2021-08-25 2021-08-25 01:50:40 1629823840 D 3
14 2021-08-25 2021-08-25 01:59:44 1629824384 E 2
15 2021-08-25 2021-08-25 02:20:00 1629825600 G 2
16 2021-08-25 2021-08-25 02:32:46 1629826366 F 4
17 2021-08-25 2021-08-25 02:41:27 1629826887 F 5
18 2021-08-25 2021-08-25 02:42:11 1629826931 H 2
19 2021-08-25 2021-08-25 02:43:08 1629826988 E 3
20 2021-08-25 2021-08-25 02:56:08 1629827768 B 4
21 2021-08-25 2021-08-25 02:58:35 1629827915 C 2
22 2021-08-25 2021-08-25 03:10:15 1629828615 E 4
23 2021-08-25 2021-08-25 03:16:24 1629828984 A 2
24 2021-08-25 2021-08-25 03:18:30 1629829110 A 3
25 2021-08-25 2021-08-25 03:25:51 1629829551 A 4
26 2021-08-25 2021-08-25 03:26:05 1629829565 G 3
27 2021-08-25 2021-08-25 03:27:41 1629829661 A 5
28 2021-08-25 2021-08-25 03:31:36 1629829896 A 6
29 2021-08-25 2021-08-25 03:58:13 1629831493 B 5
30 2021-08-25 2021-08-25 04:21:05 1629832865 G 4
31 2021-08-25 2021-08-25 04:23:14 1629832994 D 4
32 2021-08-25 2021-08-25 04:23:35 1629833015 C 3
33 2021-08-25 2021-08-25 04:25:08 1629833108 B 6
34 2021-08-25 2021-08-25 04:35:54 1629833754 E 5
35 2021-08-25 2021-08-25 04:46:50 1629834410 B 7
36 2021-08-25 2021-08-25 04:57:12 1629835032 E 6
37 2021-08-25 2021-08-25 05:03:41 1629835421 A 7
38 2021-08-25 2021-08-25 05:04:59 1629835499 E 7
39 2021-08-25 2021-08-25 05:14:39 1629836079 A 8
40 2021-08-25 2021-08-25 05:19:12 1629836352 D 5
41 2021-08-25 2021-08-25 05:36:12 1629837372 G 5
42 2021-08-25 2021-08-25 06:11:42 1629839502 G 6
43 2021-08-25 2021-08-25 06:12:10 1629839530 A 9
44 2021-08-25 2021-08-25 06:13:42 1629839622 D 6
45 2021-08-25 2021-08-25 06:19:09 1629839949 B 8
46 2021-08-25 2021-08-25 06:23:05 1629840185 B 9
47 2021-08-25 2021-08-25 06:27:30 1629840450 E 8
48 2021-08-25 2021-08-25 06:42:22 1629841342 B 10
49 2021-08-25 2021-08-25 06:47:23 1629841643 H 3
visit_date visit_time unix_time user pv
950 2021-08-30 2021-08-30 11:07:46 1630289266 A 66
951 2021-08-30 2021-08-30 11:07:50 1630289270 C 62
952 2021-08-30 2021-08-30 11:18:33 1630289913 E 66
953 2021-08-30 2021-08-30 11:23:07 1630290187 H 59
954 2021-08-30 2021-08-30 11:43:37 1630291417 H 60
955 2021-08-30 2021-08-30 11:47:38 1630291658 B 58
956 2021-08-30 2021-08-30 11:48:44 1630291724 H 61
957 2021-08-30 2021-08-30 11:53:24 1630292004 A 67
958 2021-08-30 2021-08-30 12:05:42 1630292742 G 81
959 2021-08-30 2021-08-30 12:08:51 1630292931 D 70
960 2021-08-30 2021-08-30 12:14:34 1630293274 A 68
961 2021-08-30 2021-08-30 12:17:49 1630293469 A 69
962 2021-08-30 2021-08-30 12:18:20 1630293500 G 82
963 2021-08-30 2021-08-30 12:18:29 1630293509 A 70
964 2021-08-30 2021-08-30 12:22:56 1630293776 D 70
965 2021-08-30 2021-08-30 12:33:36 1630294416 G 83
966 2021-08-30 2021-08-30 12:34:57 1630294497 H 61
967 2021-08-30 2021-08-30 12:39:06 1630294746 F 66
968 2021-08-30 2021-08-30 12:42:27 1630294947 F 67
969 2021-08-30 2021-08-30 13:00:41 1630296041 A 67
970 2021-08-30 2021-08-30 13:03:59 1630296239 E 65
971 2021-08-30 2021-08-30 13:04:50 1630296290 F 68
972 2021-08-30 2021-08-30 13:08:39 1630296519 C 61
973 2021-08-30 2021-08-30 13:09:45 1630296585 A 68
974 2021-08-30 2021-08-30 13:10:07 1630296607 F 68
975 2021-08-30 2021-08-30 13:20:40 1630297240 B 59
976 2021-08-30 2021-08-30 13:21:55 1630297315 G 82
977 2021-08-30 2021-08-30 13:29:09 1630297749 H 60
978 2021-08-30 2021-08-30 13:31:09 1630297869 C 61
979 2021-08-30 2021-08-30 13:33:20 1630298000 H 61
980 2021-08-30 2021-08-30 13:34:23 1630298063 D 70
981 2021-08-30 2021-08-30 13:36:44 1630298204 B 58
982 2021-08-30 2021-08-30 13:38:40 1630298320 B 59
983 2021-08-30 2021-08-30 13:39:42 1630298382 C 62
984 2021-08-30 2021-08-30 13:43:12 1630298592 B 60
985 2021-08-30 2021-08-30 13:53:17 1630299197 G 83
986 2021-08-30 2021-08-30 13:53:37 1630299217 E 66
987 2021-08-30 2021-08-30 14:05:49 1630299949 B 61
988 2021-08-30 2021-08-30 14:08:22 1630300102 E 67
989 2021-08-30 2021-08-30 14:11:33 1630300293 D 70
990 2021-08-30 2021-08-30 14:14:06 1630300446 A 68
991 2021-08-30 2021-08-30 14:19:29 1630300769 G 84
992 2021-08-30 2021-08-30 14:25:43 1630301143 A 69
993 2021-08-30 2021-08-30 14:33:26 1630301606 A 70
994 2021-08-30 2021-08-30 14:39:26 1630301966 F 69
995 2021-08-30 2021-08-30 14:39:32 1630301972 G 85
996 2021-08-30 2021-08-30 14:45:20 1630302320 A 70
997 2021-08-30 2021-08-30 14:49:58 1630302598 C 62
998 2021-08-30 2021-08-30 14:50:27 1630302627 G 86
999 2021-08-30 2021-08-30 14:50:52 1630302652 A 71
まずpv_list: List[int] = []
の部分ですが、これは各行のPVの計算結果を保存するためのリストとして初期化してあります。
for index, sr in df.iterrows():
の記述ですが、これはPandasのデータフレームと呼ばれるデータで1行ずつループを回す形で各行のデータにアクセスしていくための記述となります。詳細は以下の記事などをご確認ください!
sr
という変数に各行のデータが格納され、sr['user']
やsr['unix_time']
といったように辞書のように書くことで行ごとのの各列のデータにアクセスができます!今回は各行のユーザーとUNIXTIMEの値を変数に格納しています(unix_time: int = int(sr['unix_time'])
などの部分)。
three_days_ago_unixtime: int = unix_time - 259200
の部分で、対象の行の3日前のUNIXTIMEを算出しています。
その後はsliced_df
という変数名を使って、
- 対象のユーザーのみにする(
df[df['user'] == user]
部分)
- UNIXTIMEが3日前よりも後のデータのみにする(
sliced_df[sliced_df['unix_time'] >= three_days_ago_unixtime]
部分)
- UNIXTIMEがその行のUNIXTIME以前のデータのみにする(
sliced_df[sliced_df['unix_time'] <= unix_time]
)
という、スライスと呼ばれるデータの絞り込み処理を入れています!
スライス処理等に関しては以下の記事などをご確認ください。==
や>=
などの比較演算子で条件を設定できます!
続いてpv: int = len(sliced_df)
部分で、前述の条件を満たした行数をカウントしてPVを取得しています。計算した値はpv_list.append(pv)
として結果のデータを保持するためのリストに追加しています。
最後にdf['pv'] = pv_list
として、エクセルで言うところのE列に該当するpvカラム(列)を追加しています!
その後に続くprint(df.head(50))
とprint(df.tail(50))
は先頭の行と末尾の行を50行ずつ表示するための記述です。
参考 :
結果はto_csv
メソッドでCSVで保存ができます!今回はresult.csv
というファイル名で保存しています!
参考 :
注意点として、今回使った書き方(1行ずつのループ・スライスなど)は結構遅めです!コードの分かりやすさを優先しましたが、行数が大分多い・・・場合にはこの書き方はあまり良くないので、コードは複雑になりますがもっとチューニングなどを考慮した書き方が必要になってきます!(その辺までは長くなるので今回は触れておりません)
役立ちそうでしたらLGTM押していただけますと喜びます!