teratail header banner
teratail header banner
質問するログイン新規登録

回答編集履歴

1

詳細を考えたので追記

2021/06/18 12:09

投稿

TakaiY
TakaiY

スコア14545

answer CHANGED
@@ -1,3 +1,202 @@
1
1
  そもそも、関数を定義しているだけで呼んでいないので、何も起きないのは当然です。
2
2
 
3
+ ---
4
+
5
+ [この件はこの質問](https://teratail.com/questions/344591)あたりから続いているんだと思います。ここから関数化して進めているのでしょうが、その関数の中でいろいろ入れ込んでしまうのは筋が悪いですから、そこに戻って進めます。
6
+
7
+ ## まずは関数化と動作確認
8
+
9
+ もとのファイルでcsvをFFTする処理はできているということなので、まずはこの処理を関数に入れてみましょう。
10
+ そして、ここが大事ですが、この段階でもとのファイルと同じように動作するようにします。これができなれけば先に進むことはできません。
11
+
12
+ さて、関数にするにあたっては、処理そのものを全部関数にするのではなくて、最後のcsvへの書き出しは関数の外に出します。この部分は後で変更したいからです。
13
+ 関数名はfftだと他の紛らわしいので、my_fftとしました。
14
+ 作る関数の引数は読み込むcsvファイルの名前にします。
15
+
16
+ csvに出力しないとしたら、作成したデータ、この場合はdfですね、はどうするのかというと、関数の返り値にします。
17
+ この関数は、csvファイルを引数にして呼び出すと、FFTの結果を返す関数だということです。
18
+
19
+ 関数ができれば、関数にした処理をちゃんと呼び出すのを忘れてはいけません。関数は定義しただけでは動作しません。
20
+ 関数を呼び出すときは、定義の通り、CSVファイルを1つ指定します。 返り値でFFTの結果が返るので、それを変数で受けて、csvに書き出します。
21
+
22
+ このように変更したのが以下のソースです。
23
+ このソースで想定どおり動作することを確認してみてください。
24
+
25
+ ちなみに、pythonファイルのインデントは基本的にスペース4つに統一すべきです。
26
+ 以下のソースでは修正してあります。
27
+
28
+ ※ 以下コード書きますが、手元に情報が無いので、動作の検証まではしていません。バグがあるかもしれませんが悪しからず。
29
+
30
+ ```python
31
+ import cv2
32
+ import numpy as np
33
+ import matplotlib.pyplot as plt
34
+ import csv
35
+ import os
36
+ import glob
37
+ import pandas as pd
38
+
39
+
40
+ def my_fft(infile):
41
+ ##### 実験条件、分析対象の設定 ######
42
+ t = np.arange(0,8.192,0.0005) #サンプリング時間,周波数の指定(開始時間(=0),終了時間,サンプリング周期)
43
+
44
+ file = infile #分析対象のファイル指定
45
+
46
+ ##### データの読み込みy #####
47
+ for i in range(4):
3
- (後で追記予定)
48
+ print(i)
49
+ def loadvtp(file,i): #ファイルの読み込みに使用する関数の定義
50
+ vtp = pd.read_csv(file+'.csv', dtype='float', skiprows=57, usecols=[i+2], nrows=16384, engine='python', header=None) #解析対象となるデータの読み込み
51
+ vtp = vtp - np.mean(vtp) #平均を引く
52
+ vtp = np.squeeze(vtp)
53
+ return vtp
54
+
55
+ ##### 主流(x)成分出力の計算 #####
56
+
57
+ vx = loadvtp(file,i)
58
+
59
+ ##### FFT #####
60
+
61
+ freq = np.fft.fftfreq(16384, 1/2000) #周波数軸の生成(サンプリング点数, サンプリング周期)
62
+
63
+ f = np.fft.fft(vx) #FFT
64
+ f [0]=f[0]/2 #定常成分を1/2にする(スケーリングに必要)
65
+ amp = np.abs(f)/(16384/2) #FFT結果を振幅に合わせてスケーリング
66
+
67
+ freq = freq[0:16384//2] #周波数軸の対称成分を除く
68
+ amp = amp[0:16384//2] #振幅の対称成分を除く
69
+
70
+ if i==0:
71
+ yav=vx
72
+ xav=""
73
+ vav=""
74
+ wav=""
75
+ y=amp
76
+ x=""
77
+ v=""
78
+ w=""
79
+ elif i==1:
80
+ yav=yav
81
+ xav=vx
82
+ vav=""
83
+ wav=""
84
+ y=y
85
+ x=amp
86
+ v=""
87
+ w=""
88
+ elif i==2:
89
+ yav=yav
90
+ xav=xav
91
+ vav=vx
92
+ wav=""
93
+ y=y
94
+ x=x
95
+ v=amp
96
+ w=""
97
+ elif i==3:
98
+ yav=yav
99
+ xav=xav
100
+ vav=vav
101
+ wav=vx
102
+ y=y
103
+ x=x
104
+ v=v
105
+ w=amp
106
+
107
+ print(y)
108
+ print(x)
109
+ print(v)
110
+ print(w)
111
+
112
+ df = [t, yav, xav, vav, wav, freq, y, x, v, w]
113
+ df=pd.DataFrame(df).T
114
+
115
+ return df
116
+
117
+
118
+ ## メイン処理
119
+ ## 1ファイルだけ
120
+ ## csv
121
+ in_csv_file = '0.73'
122
+ fft_df = my_fft(in_csv_file)
123
+ fft_df.to_csv('FFT.csv', index=None)
124
+
125
+ ```
126
+
127
+ 上のソースで動作確認できたでしょうか?できていなければ次に進んでも意味がありません。
128
+
129
+ ## 複数ファイル処理。まだ出力はCSV
130
+
131
+ 次に、フォルダの中のファイルを全て順に処理するようにしましょう。
132
+
133
+ すでに、1つのファイルを処理する関数はできているので、それを、取得したファイル名で順に呼びだすだけです。ファイルの出力処理は同じです。
134
+ だたし、CSVで出力するときにファイル名が固定のFFT.csvだと、どんどん上書きしてしまうので、読み込んファイルの名前を含むように変えてやります。
135
+ ファイル名の取得は質問にあるソースあるglob処理を使いました。globで取ってきたファイル名はパスなので、ファイル名の部分だけ取り出すためにosモジュールを使います。
136
+
137
+ その様に変更したのが以下のソースです。
138
+ 関数の部分は変えていないので割愛で、メイン処理の部分を書き換えます(前のを残しておいてはだめです)
139
+ import文は最終的にはファイルの先頭にまとめた方がいいでしょう。
140
+
141
+ 動かしてみると、スクリプトのあるファルダにcsvファイルができているはずです。
142
+ できていますか? そして、中身が想定通りでしょうか?
143
+
144
+ ```python
145
+ ## メイン処理
146
+ ## UPフォルダ内全部
147
+ ## 個別にcsvに出力
148
+ import os
149
+
150
+ infile = glob.glob("UP/*.csv")
151
+ infile.sort()
152
+ print('入力csvファイル数', len(infile))
153
+
154
+ for in_csv_file in infile:
155
+ in_file_name = os.path.basename(in_csv_file)
156
+
157
+ fft_df = my_fft(in_csv_file)
158
+
159
+ fft_df.to_csv(f'FFT_{in_file_name}.csv', index=None)
160
+
161
+ ```
162
+
163
+ 上のソースで動作確認できたでしょうか?できていなければ次に進んでも意味がありません。
164
+
165
+ ## 最後にExcelににします。
166
+
167
+ Pandasにはto_excelという関数がありますので、それを使えばいいでしょう。
168
+ [このサイトに詳しく説明してあります](https://note.nkmk.me/python-pandas-to-excel/)
169
+ そこにも書いてありますが、使うにはopenpyxlが必要になりますので入っていなければインストールしておきます。
170
+
171
+ 複数のDataFrameを1つのブックに入れるので、サイトの最後に書いてある方法でやります。
172
+
173
+ 今度もメイン処理の部分だけ書き換えます(前のを残しておいてはだめです)
174
+ それが以下のコードです。
175
+
176
+ ```python
177
+ ## メイン処理
178
+ ## UPフォルダ内全部
179
+ ## Excelに出力. ファイル名はFFT.xlsxとしています。
180
+ import os
181
+
182
+ infile = glob.glob("UP/*.csv")
183
+ infile.sort()
184
+ print('入力csvファイル数', len(infile))
185
+
186
+ with pd.ExcelWriter('FFT.xlsx', mode='w') as writer:
187
+ for in_csv_file in infile:
188
+ in_file_name = os.path.basename(in_csv_file)
189
+
190
+ fft_df = my_fft(in_csv_file)
191
+
192
+ fft_df.to_excel(writer, sheet_name=in_file_name)
193
+
194
+ ```
195
+
196
+
197
+
198
+ 以上ですが、こんな風に、処理の中核部分を関数化してあれば、処理対象や出力方法などはその処理とは関係ないので、見通し良く作っていくことができるのです。
199
+ 最初の回答の人が関数化と書いたのはこういうことだったのです。
200
+
201
+ 関数化した中の処理についても、さらに関数化するなどして読みやすくすることもできますが置いておきました。
202
+