質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Q&A

解決済

1回答

287閲覧

2つのLatLonファイルを確認して最も距離が近い組合せを抽出したい

chouchou

総合スコア10

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

0グッド

0クリップ

投稿2022/05/27 01:48

はじめまして。Python初心者です。表題の件をやりたくて質問します。
LatLonが書かれた2つのcsvがあり、距離を比較する関数を書いてみました。
ーーー
df1
lon lat
130.8 35.1
135.8 36.1
140.8 37.1
145.8 38.1
ーーー
df2
lon lat
131.5 35.1
132.5 35.1
133.5 35.1
134.5 35.1
ーーー
関数

import pandas as pd import numpy as np import csv import glob import math def cal_distance(lon1, lat1, lon2, lat2): # 極半径 pole_radius = 6356752.314245 # 赤道半径 equator_radius = 6378137.0 lat1_m = math.radians(lat1) lon1_m = math.radians(lon1) lat2_m = math.radians(lat2) lon2_m = math.radians(lon2) lat_difference = lat1_m - lat2_m lon_difference = lon1_m - lon2_m # 平均緯度 lat_average = (lat1_m + lat2_m) / 2 # 第一離心率^2 e2 = (math.pow(equator_radius, 2) - math.pow(pole_radius, 2)) / math.pow(equator_radius, 2) w = math.sqrt(1- e2 * math.pow(math.sin(lat_average), 2)) # 子午線曲率半径 m = equator_radius * (1 - e2) / math.pow(w, 3) # 卯酉線曲半径 n = equator_radius / w # 距離計測 distance = math.sqrt(math.pow(m * lat_difference, 2) + math.pow(n * lon_difference * math.cos(lat_average), 2)) return distance / 1000

ここで、次のカラムに

lon1 = df1.iloc[0, 0] lat1 = df1.iloc[0, 1] lon2 = df2.iloc[0, 0] lat2 = df2.iloc[1, 0]

とじかに設定してやると次のカラムで

cal_distance(lon1, lat1, lon2, lat2)

で解を一つ得られるのですが、df1の4行に対してdf2の行全部を当てて比較したいので
for文で回して計算してみようとすると、エラーが出てしまいます。

for i in len(df1): lon1 = df1.iloc[i, 0] lat1 = df1.iloc[i, 1] lon2 = df2.iloc[0, 0] lat2 = df2.iloc[1, 0] cal_distance(lon1, lat1, lon2, lat2)

→TypeError: 'int' object is not iterable

defの部分の書き方がおかしいのかもしれませんが、
1項目だけ設定したらエラーが出ないのに、forにするとエラーが出る理由がよくわかりません。

最終的には、df3を作って、
df1の1行目のLatLonとdf2の全LatLonを当てて、その最小値(min)をdf3に出力、
df1の2行目のLatLonとdf2の全LatLonを当てて、その最小値(min)をdf3に出力、
df1の3行目のLatLonとdf2の全LatLonを当てて、その最小値(min)をdf3に出力、
df1の4行目のLatLonとdf2の全LatLonを当てて、その最小値(min)をdf3に出力

をゴールとしています。

拙くて申し訳ありませんが、ご助言頂けると嬉しいです。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

python

1dfx = df1.merge(df2, how='cross', suffixes=('_1', '_2')) 2dfx['distance'] = dfx.apply(lambda x: cal_distance(*x), axis=1) 3df3 = dfx.iloc[dfx.groupby(['lon_1', 'lat_1'])['distance'].idxmin()].reset_index(drop=True) 4 5print(df3) 6# 7 lon_1 lat_1 lon_2 lat_2 distance 80 130.8 35.1 131.5 35.1 63.823879 91 135.8 36.1 134.5 35.1 161.825625 102 140.8 37.1 134.5 35.1 609.174484 113 145.8 38.1 134.5 35.1 1064.473702 12

投稿2022/05/27 02:33

編集2022/05/27 03:28
melian

総合スコア19805

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

chouchou

2022/05/27 02:52

melian様 一瞬で出来たことにまず驚き、あと、 dfx = df1.merge(df2, how='cross', suffixes=('_1', '_2')) このように全体を一度マージするという方法に、目から鱗が落ちる思いでした。 挙動をひとつひとつデバックを取って確認しました。ありがとうございます。 min_pairの所で、全体のマージでの最小値ではなく、 各組合せ(という表現が相応しいのかですが)、ここでいう所の df1 lon lat 130.8 35.1 135.8 36.1 140.8 37.1 145.8 38.1 にたいして、 dfx lon_df1 lat_df1 lon_df2 lat_df2 distance 130.8 35.1 →df2の中での最小となるlon lat 135.8 36.1 →df2の中での最小となるlon lat 140.8 37.1 →df2の中での最小となるlon lat 145.8 38.1 →df2の中での最小となるlon lat を出力したいのですが、色々やり方があると思うのですが mergeした後に、前後でdf1の値が異なる(タプルにする?)所まででどれ、というような 処理の思考回路で合っていますでしょうか? こういう風にできるのかというのが正直な所の感想で、勉強になりました。
melian

2022/05/27 03:20 編集

> mergeした後に、前後でdf1の値が異なる(タプルにする?)所まででどれ、というような 処理の思考回路で合っていますでしょうか? はい、更新した回答では groupby を使いました。
chouchou

2022/05/27 04:34

意図する通りに実現できました。 考え方が自分の組み立てと違っていたため、特にmergeをこのようなケースで使う事について気付くことができ、非常に勉強になりました。 ありがとうございます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問