def _orgnize_matrix(beh_df, pos_df, target_cow_id, near_cows, threshold=10): """ 入力形式に従ってmatrixを作成する threshold: 距離の近さの閾値 [meter] """ target_beh = beh_df[str(target_cow_id)].values target_pos = pos_df[str(target_cow_id)].values input_image = np.zeros((len(target_beh) * 3, len(near_cows) * 3)) i = 0 for cow_id in near_cows: nearcow_beh = beh_df[cow_id].values nearcow_pos = pos_df[cow_id].values j = 0 for t_b, t_p, n_b, n_p in zip(target_beh, target_pos, nearcow_beh, nearcow_pos): lat1, lon1, lat2, lon2 = t_p[0], t_p[1], n_p[0], n_p[1] dis, _ = geography.get_distance_and_direction( lat1, lon1, lat2, lon2, True) if (dis <= threshold): mat = np.zeros((3, 3)) # 3 * 3のマトリックスに行動を埋め込む mat[t_b, n_b] = 1 else: mat = np.zeros((3, 3)) # 近い距離にいない場合はゼロ行列 input_image[j * 3:(j + 1) * 3, i * 3:(i + 1) * 3] = mat # 対応するフィルターに対して行列を代入する j += 1 i += 1 return input_image
def _calculate_behavior_synchronization(self, beh_df, pos_df, cow_id1, cow_id2, epsilon=30): """ 行動同期スコアを計算する epsilon : int. 単位は [m]. この距離以内の時行動同期を測定する(この距離以上のとき同期していても0). """ beh_df2 = beh_df[[str(cow_id1), str(cow_id2)]] # 2頭を抽出 pos_df2 = pos_df[[str(cow_id1), str(cow_id2)]] # 2頭を抽出 # --- 行動同期スコアの計算(空間におけるマンハッタン距離から算出する方法) --- # prop_vec_cow1 = self._measure_behavior_ratio(beh_df2.loc[:, str(cow_id1)].values) # prop_vec_cow2 = self._measure_behavior_ratio(beh_df2.loc[:, str(cow_id2)].values) # neighbor_time = self._measure_time_neighbor(pos_df2.loc[:, str(cow_id1)].values, pos_df2.loc[:, str(cow_id2)].values, threshold=10) # dist = np.abs(prop_vec_cow1-prop_vec_cow2).sum() # 3次元空間内での2点の距離をマンハッタン距離で求める # score = neighbor_time * (2 - dist) # --- 行動同期スコアの計算(スコア行列を使用する方法) --- score = 0 score_matrix = np.array([[1, 0, 0], [0, 3, 0], [0, 0, 9]]) behavior_list1 = beh_df2.loc[:, str(cow_id1)].values # cow1の行動系列 behavior_list2 = beh_df2.loc[:, str(cow_id2)].values # cow2の行動系列 # 2頭間距離のリストを作る distance_list = [] for _, row in pos_df2.iterrows(): try: lat1, lon1, lat2, lon2 = row[0][0], row[0][1], row[1][0], row[1][1] except TypeError: pdb.set_trace() dist, _ = geography.get_distance_and_direction(lat1, lon1, lat2, lon2, True) distance_list.append(dist) # 同期スコアを加算していく for beh1, beh2, dist in zip(behavior_list1, behavior_list2, distance_list): if (dist <= epsilon): # 距離が閾値以内にいる場合 score += score_matrix[beh1, beh2] # スコア行列に従ってスコアを加算する return score
def _measure_time_neighbor(self, arraylist1, arraylist2, threshold): """ 2つの位置が閾値以内にある回数を数え上げる """ count = 0 # 各時刻の2頭の距離を算出する for pos1, pos2 in zip(arraylist1, arraylist2): lat1, lon1 = pos1[0], pos1[1] lat2, lon2 = pos2[0], pos2[1] dist, _ = geography.get_distance_and_direction(lat1, lon1, lat2, lon2, True) if (dist <= threshold): count += 1 return count / len(arraylist1) # 全時刻のうちどれくらいの割合で近くにいたかを[0,1]の範囲で表す
def _measure_mileage(self, pos_df): """ 総移動距離(各時刻の移動距離の総和)を算出する """ mileage = 0 before_lat, before_lon = None, None for _, row in pos_df.iterrows(): lat, lon = row[0][0], row[0][1] if ((before_lat is not None) and (before_lon is not None)): dis, _ = geography.get_distance_and_direction( before_lat, before_lon, lat, lon, True) mileage += dis before_lat, before_lon = lat, lon return mileage
def _calculate_average_distance(self, df, cow_id1, cow_id2): """ 距離の平均を算出する """ df2 = df[[str(cow_id1), str(cow_id2)]] # 2頭を抽出 # --- 行動同期スコアの計算(論文参照) --- count = 0 accumulated_distance = 0 for _, row in df2.iterrows(): lat1, lon1, lat2, lon2 = row[1][0], row[1][1], row[3][0], row[3][1] dis, _ = geography.get_distance_and_direction(lat1, lon1, lat2, lon2, True) # 距離を加算する accumulated_distance += dis count += 1 return accumulated_distance / count
def load_gps(cow_id, start, end): print(sys._getframe().f_code.co_name, "実行中") print("GPSの読み込みを開始します---") # データを読み込み,それぞれのリストを作成 (情報ごとのリストにするか時間ごとのリストのリストにするかは場合による) time_list = [] # 時間のリスト (主キー) position_list = [] # (緯度,経度) のリスト distance_list = [] # 距離のリスト velocity_list = [] # 速さのリスト angle_list = [] # 移動角度のリスト dt = datetime.datetime(start.year, start.month, start.day) a = start while(dt < end): t_list = [] pos_list = [] dis_list = [] vel_list = [] ang_list = [] cow = Cow.Cow(cow_id, dt) dt = dt + datetime.timedelta(days = 1) while(a <= dt and a < end): gps_list = cow.get_gps_list(a, a + datetime.timedelta(minutes = 60)) g_before = None for i in range(int(len(gps_list) / 5)): g = gps_list[i * 5] if g_before is not None: lat1, lon1, vel1 = g_before.get_gps_info(g_before.get_datetime()) lat2, lon2, vel2 = g.get_gps_info(g.get_datetime()) distance, angle = geo.get_distance_and_direction(lat1, lon1, lat2, lon2, False) #print(g.get_datetime().strftime("%Y/%m/%d %H:%M:%S") + " : ", lat2 , ",", lon2) t_list.append(g.get_datetime()) #時間の格納 pos_list.append(geo.translate(lat2, lon2)) #位置情報の格納 dis_list.append(distance) #距離の格納 vel_list.append(vel2) #速さの格納 ang_list.append(angle) #角度の格納 g_before = g a = a + datetime.timedelta(minutes = 60) del gps_list gc.collect() time_list.append(t_list) #1日分の時間のリストの格納 position_list.append(pos_list) #1日分の位置情報の格納 distance_list.append(dis_list) #1日分の距離のリストの格納 velocity_list.append(vel_list) #1日分の速さのリストの格納 angle_list.append(ang_list) #1日分の角度のリストの格納 del cow gc.collect() a = dt print("---GPSの読み込みが終了しました") print(sys._getframe().f_code.co_name, "正常終了") print("The length of time_list: ", len(time_list), "day(s)\n") return time_list, position_list, distance_list, velocity_list, angle_list
def load_gps(cow_id, date): """ データベースから指定牛の指定期間のデータを読み込む (元データ (1 Hz) を5s (0.2Hz) に戻す処理も含む) Parameter cow_id : 牛の個体番号 date : datetime, 読み込む日時 Return time_list : 時間の2次元リスト(1日分のデータ) position_list : 緯度・経度の3次元リスト((緯度, 経度) × 1日分のデータ) distance_list : 距離の2次元リスト(1日分のデータ) velocity_list : 速さの2次元リスト(1日分のデータ) angle_list : 角度の2次元リスト(1日分のデータ) ※ ここでは緯度と経度だけを読み込み前処理で距離や速さを計算する方が良いかもしれません """ print(sys._getframe().f_code.co_name, "実行中") print("GPSの読み込みを開始します---") # データを読み込み,それぞれのリストを作成 (情報ごとのリストにするか時間ごとのリストのリストにするかは場合による) time_list = [] # 時間のリスト (主キー) position_list = [] # (緯度,経度) のリスト distance_list = [] # 距離のリスト velocity_list = [] # 速さのリスト angle_list = [] # 移動角度のリスト dt = datetime.datetime(date.year, date.month, date.day) cow = Cow.Cow(cow_id, dt) dt = dt + datetime.timedelta(hours=9) # JSTでデータベース登録されているため時間を合わせる gps_list = cow.get_gps_list( dt, dt + datetime.timedelta(hours=24)) # 1日分のGPSデータを読み込む g_before = None for i in range(int(len(gps_list) / 5)): g = gps_list[i * 5] # 5の倍数の要素の分だけデータを取り出す if (g_before is not None): lat1, lon1, vel1 = g_before.get_gps_info(g_before.get_datetime()) lat2, lon2, vel2 = g.get_gps_info(g.get_datetime()) distance, angle = geo.get_distance_and_direction( lat1, lon1, lat2, lon2, False) time_list.append(g.get_datetime()) #時間の格納 position_list.append(geo.translate(lat2, lon2)) #位置情報の格納 distance_list.append(distance) #距離の格納 velocity_list.append(vel2) #速さの格納 angle_list.append(angle) #角度の格納 g_before = g print("---GPSの読み込みが終了しました") print(sys._getframe().f_code.co_name, "正常終了") print("The length of time_list: ", len(time_list), "(data)\n") return time_list, position_list, distance_list, velocity_list, angle_list
def read_gps(cow_id, start, end): time_list = [] distance_list = [] velocity_list = [] angle_list = [] dt = datetime.datetime(start.year, start.month, start.day) a = start while(dt < end): t_list = [] dis_list = [] vel_list = [] ang_list = [] cow = Cow.Cow(cow_id, dt) dt = dt + datetime.timedelta(days = 1) while(a < dt and a < end): gps_list = cow.get_gps_list(a, a + datetime.timedelta(minutes = 60)) g_before = None for i in range(int(len(gps_list) / 5)): g = gps_list[i * 5] if g_before is not None: lat1, lon1, vel1 = g_before.get_gps_info(g_before.get_datetime()) lat2, lon2, vel2 = g.get_gps_info(g.get_datetime()) distance, angle = geo.get_distance_and_direction(lat1, lon1, lat2, lon2) #print(g.get_datetime().strftime("%Y/%m/%d %H:%M:%S") + " : ", lat2 , ",", lon2) t_list.append(g.get_datetime()) #時間の格納 dis_list.append(distance) #距離の格納 vel_list.append(vel2) #速さの格納 ang_list.append(angle) #角度の格納 g_before = g a = a + datetime.timedelta(minutes = 60) del gps_list gc.collect() time_list.append(t_list) #1日分の時間のリストの格納 distance_list.append(dis_list) #1日分の距離のリストの格納 velocity_list.append(vel_list) #1日分の速さのリストの格納 angle_list.append(ang_list) #1日分の角度のリストの格納 del cow gc.collect() a = dt return time_list, distance_list, velocity_list, angle_list
def score_synchro(beh_df, pos_df, target_cow_id, community, score_matrix, dis_threshold=10): """ 同期をスコア化する """ score_dict = {} # 返却値 # score_matrix = np.array([[1, 0, 0], [0, 1, 0], [0, 0, 1]]) target_beh = beh_df[str(target_cow_id)].values target_pos = pos_df[str(target_cow_id)].values if (target_cow_id in community): community.remove(target_cow_id) for cow_id in community: score = 0 nearcow_pos = pos_df[cow_id].values nearcow_beh = beh_df[cow_id].values for i in range(len(target_beh)): lat1, lon1 = target_pos[i][0], target_pos[i][1] lat2, lon2 = nearcow_pos[i][0], nearcow_pos[i][1] dis, _ = geography.get_distance_and_direction(lat1, lon1, lat2, lon2, True) # 近い距離にいれば同期しているかを確認する if (dis <= dis_threshold and _check_position(lat1, lon1) and _check_position(lat2, lon2)): score += score_matrix[target_beh[i], nearcow_beh[i]] score_dict[cow_id] = score / 12 # 1分間あたりになおす return score_dict
def _calculate_position_synchronization(self, pos_df, cow_id1, cow_id2, dzeta=10): """ 空間同期スコアを計算する dzeta : int. 単位は [m]. この距離以内の時間を計測する """ dist_matrix = np.array([3, 6, dzeta]) score_matrix = np.array([3, 2, 1, 0]) df2 = pos_df[[str(cow_id1), str(cow_id2)]] # 2頭を抽出 # --- 行動同期スコアの計算(論文参照) --- score = 0 for _, row in df2.iterrows(): try: lat1, lon1, lat2, lon2 = row[0][0], row[0][1], row[1][0], row[1][1] except TypeError: pdb.set_trace() dist, _ = geography.get_distance_and_direction(lat1, lon1, lat2, lon2, True) if (dist <= dist_matrix[0]): score += score_matrix[0] elif (dist <= dist_matrix[1]): score += score_matrix[1] elif (dist <= dist_matrix[2]): score += score_matrix[2] return score
def _find_minimun_distance(self, pos_df, community): """ 最も総距離の短い牛との間の距離の平均を求める """ minimum_dist_cow, minimum_dist = None, 100000 if (len(community) == 1): return "None", 0 # コミュニティメンバがいない場合は欠損値扱い else: my_df = pos_df[[str(self.cow_id)]] for cow_id in community: if (cow_id != str(self.cow_id)): opponent_df = pos_df[[str(cow_id)]] merged_df = pd.concat([my_df, opponent_df], axis=1) sum_dis = 0 for _, row in merged_df.iterrows(): lat1, lon1, lat2, lon2 = row[0][0], row[0][1], row[1][ 0], row[1][1] dis, _ = geography.get_distance_and_direction( lat1, lon1, lat2, lon2, True) sum_dis += dis if (sum_dis < minimum_dist): minimum_dist = sum_dis minimum_dist_cow = cow_id return minimum_dist_cow, minimum_dist / len( pos_df) # 1データ当たりの距離の平均を算出
def _measure_synchronization_ratio(self, df, community, epsilon=30): """ 行動同期度を算出する """ score_matrix = np.array([[1, 0, 0], [0, 2, 0], [0, 0, 3]]) # 行動同期のスコア comm = copy.deepcopy(community) # 一応コピー comm.remove(str(self.cow_id)) # コミュニティから対象牛の要素を削除 if (len(comm) != 0): # コミュニティメンバが自分だけでないとき # --- 対象牛と他のコミュニティメンバとの行動同期度を算出する --- score_list = [] for other_cow_id in comm: score = 0 df2 = df[[str(self.cow_id), str(other_cow_id)]] for _, row in df2.iterrows(): lat1, lon1, lat2, lon2 = row[1][0], row[1][1], row[3][ 0], row[3][1] dis, _ = geography.get_distance_and_direction( lat1, lon1, lat2, lon2, True) # 距離が閾値以内ならスコアを加算する if (dis <= epsilon): score += score_matrix[row[0][1], row[2][1]] score_list.append(score) return sum(score_list) / len(score_list) else: # コミュニティメンバが自分だけのとき return 0
def _rank_cow(pos_df, target_cow_id, threshold=10): """ 観測対象牛と閾値以内の距離にいた時間が多い順にx個の牛を取り出す (抽出後のdfは降順には並び変えない) threshold: 距離の近さの閾値 [meter] """ num_extracted = 5 # 取り出す牛の頭数 near_cows = {} cow_id_list = list(pos_df.columns) cow_id_list.remove(target_cow_id) # 観測対象牛は除去する target_pos = pos_df[target_cow_id].values for cow_id in cow_id_list: nearcow_pos = pos_df[cow_id].values count = 0 for t_p, n_p in zip(target_pos, nearcow_pos): lat1, lon1, lat2, lon2 = t_p[0], t_p[1], n_p[0], n_p[1] dis, _ = geography.get_distance_and_direction( lat1, lon1, lat2, lon2, True) if (dis <= threshold): count += 1 # 近い距離にいた回数をカウント near_cows[cow_id] = count sorted_near_cows = sorted(near_cows.items(), key=lambda x: x[1], reverse=True) # 近い距離にいた時間が長い牛からソート near_cows = sorted([elem[0] for elem in sorted_near_cows[:num_extracted] ]) # 上位x個を抽出し牛のIDのみをリストに格納する return near_cows
def output_feature_info(self, t_list, p_list, d_list, v_list, l_list): """ 特徴をCSVにして出力する (圧縮が既に行われている前提) Parameter t_list :圧縮後の時刻のリスト p_list :圧縮後の位置情報のリスト d_list :圧縮後の距離のリスト l_list :圧縮後の暫定的なラベルのリスト """ print(sys._getframe().f_code.co_name, "実行中") ###登録に必要な変数### before_lat = None before_lon = None after_lat = None after_lon = None rest_vel = None #####登録情報##### time_index = None resting_time_category = None # 時間帯のカテゴリ (日の出・日の入時刻を元に算出) walking_time_category = None # 時間帯のカテゴリ (日の出・日の入時刻を元に算出) previous_rest_length = None #圧縮にまとめられた前の休息の観測の個数 walking_length = None #圧縮にまとめられた歩行の観測の個数 moving_distance = None #休息間の距離 mean_vel = None # 両セグメント内の平均速度 resting_velocity_average = None # 停止セグメントの速度の平均 resting_velocity_deviation = None # 停止セグメントの速度の標準偏差 walking_velocity_average = None # 活動セグメントの速度の平均 walking_velocity_deviation = None # 停止セグメントの速度の標準偏差 moving_direction = None #次の休息への移動方向 print("特徴を計算します---") feature_list = [] behavior_dict = {"resting": 0, "walking": 1} # 行動ラベルの辞書 initial_datetime = t_list[0][0] #####登録##### for i, (time, pos, dis, vel, label) in enumerate(zip(t_list, p_list, d_list, v_list, l_list)): if (label == behavior_dict["walking"]): # 歩行 if (i != 0): # 最初は休息から始まるようにする (もし最初が歩行ならそのデータは削られる) time_index.append((time[0], time[1])) walking_time_category = self._decide_time_category( time[0], initial_datetime) walking_length = (time[1] - time[0]).total_seconds() / 5 + 1 walking_velocity_average, walking_velocity_deviation = self._extract_mean( vel) # 活動セグメント内の平均速度とその標準偏差 vel.extend(rest_vel) # 休息時の速度のリストと結合 max_vel = max(vel) min_vel = min(vel) mean_accumulated_distance, _ = self._extract_mean( dis) # 行動内での移動距離の1観測あたり mean_vel, _ = self._extract_mean(vel) if (label == behavior_dict["resting"]): # 休息 ###前後関係に着目した特徴の算出### after_lat = pos[0][0] after_lon = pos[0][1] resting_time_category = self._decide_time_category( time[0], initial_datetime) if (before_lat is not None and before_lon is not None and rest_vel is not None): moving_distance, moving_direction = geo.get_distance_and_direction( before_lat, before_lon, after_lat, after_lon, True) #前の重心との直線距離 ###リストに追加### feature_list.append([ time_index, resting_time_category, walking_time_category, previous_rest_length, walking_length, mean_accumulated_distance, mean_vel, max_vel, min_vel, resting_velocity_average, resting_velocity_deviation, walking_velocity_average, walking_velocity_deviation, moving_distance, moving_direction ]) ###引継### previous_rest_length = (time[1] - time[0]).total_seconds() / 5 + 1 before_lat = pos[len(pos) - 1][0] before_lon = pos[len(pos) - 1][1] resting_velocity_average, resting_velocity_deviation = self._extract_mean( vel) # 休息セグメント内の平均速度とその標準偏差 rest_vel = vel time_index = [(time[0], time[1])] print("---特徴を計算しました") print(sys._getframe().f_code.co_name, "正常終了\n") return feature_list
def output_feature_info(filename, t_list, p_list, d_list, v_list, l_list): """ 特徴をCSVにして出力する (圧縮が既に行われている前提) Parameter filename :ファイルのパス t_list :圧縮後の時刻のリスト p_list :圧縮後の位置情報のリスト d_list :圧縮後の距離のリスト l_list :圧縮後の暫定的なラベルのリスト """ print(sys._getframe().f_code.co_name, "実行中") ###登録に必要な変数### before_lat = None before_lon = None after_lat = None after_lon = None rest_vel = None #####登録情報##### time_index = None resting_time_category = None # 時間帯のカテゴリ (日の出・日の入時刻を元に算出) walking_time_category = None # 時間帯のカテゴリ (日の出・日の入時刻を元に算出) previous_rest_length = None #圧縮にまとめられた前の休息の観測の個数 walking_length = None #圧縮にまとめられた歩行の観測の個数 moving_distance = None #休息間の距離 moving_direction = None #次の休息への移動方向 print("特徴を計算します---") feature_list = [] behavior_dict = {"resting": 0, "walking": 1} # 行動ラベルの辞書 initial_datetime = t_list[0][0] #####登録##### for i, (time, pos, dis, vel, label) in enumerate(zip(t_list, p_list, d_list, v_list, l_list)): if (label == behavior_dict["walking"]): # 歩行 if (i != 0): # 最初は休息から始まるようにする (もし最初が歩行ならそのデータは削られる) time_index += time[0].strftime( "%Y/%m/%d %H:%M:%S") + "-" + time[1].strftime( "%Y/%m/%d %H:%M:%S") walking_time_category = decide_time_category( time[0], initial_datetime) walking_length = (time[1] - time[0]).total_seconds() / 5 + 1 vel.extend(rest_vel) # 休息時の速度のリストと結合 max_vel = max(vel) min_vel = min(vel) _, dis, mean_vel = extract_mean(pos, dis, vel) ave_accumulated_distance = dis # 行動内での移動距離の1観測あたり if (label == behavior_dict["resting"]): # 休息 ###前後関係に着目した特徴の算出### after_lat = pos[0][0] after_lon = pos[0][1] resting_time_category = decide_time_category( time[0], initial_datetime) if (before_lat is not None and before_lon is not None and rest_vel is not None): moving_distance, moving_direction = geo.get_distance_and_direction( before_lat, before_lon, after_lat, after_lon, True) #前の重心との直線距離 ###リストに追加### feature_list.append([ time_index, resting_time_category, walking_time_category, previous_rest_length, walking_length, ave_accumulated_distance, mean_vel, max_vel, min_vel, moving_distance, moving_direction ]) ###引継### previous_rest_length = (time[1] - time[0]).total_seconds() / 5 + 1 before_lat = pos[len(pos) - 1][0] before_lon = pos[len(pos) - 1][1] rest_vel = vel time_index = time[0].strftime("%Y/%m/%d %H:%M:%S") + "-" + time[ 1].strftime("%Y/%m/%d %H:%M:%S") + " | " print("---特徴を計算しました") ### ファイル名の指定がない時はファイル出力せずにリストを返却 ### if (filename == ""): return feature_list else: print(filename + "に出力します---") if (os.path.exists(filename)): # ファイルがすでに存在しているとき #####出力##### with open(filename, "w", newline="") as f: writer = csv.writer(f) writer.writerow( ("Time", "Resting time category", "Walking time category", "Last rest time", "Walking time", "Moving amount", "Average velocity", "Max velocity", "Min velocity", "Distance", "Direction")) for feature in feature_list: writer.writerow(feature) else: # ファイルが存在していないとき #####出力##### with open(filename, "a", newline="") as f: writer = csv.writer(f) writer.writerow( ("Time", "Resting time category", "Walking time category", "Last rest time", "Walking time", "Moving amount", "Average velocity", "Max velocity", "Min velocity", "Distance", "Direction")) for feature in feature_list: writer.writerow(feature) print("---" + filename + "に出力しました") print(sys._getframe().f_code.co_name, "正常終了\n") return