PyODPS本明細書で大規模データ解析及び前処理、類似パンダを実行するためのデータフレームのAPIを提供するには、操作デカルト積を行うインタフェースPyODPSを使用する方法について説明します。
最も一般的なシナリオのデカルト積は、任意の2つまたは操作の間で比較する必要があります。地理的な距離を計算するために、たとえば、大きなテーブルCoordinates1記憶目標点緯度と経度の座標、データのM行の合計は、小さな記憶テーブルCoordinates2点緯度と経度の座標、データのN行の合計を開始することを前提とし、今、目標点から出発のすべての最も最近の点の座標を計算する必要があります。目標点のために、我々はすべての目標点までの距離の開始点を計算し、次に最小距離を見つける必要があるので、全体のプロセスは直積問題であるデータの中間のM * N個を生成する必要があります。
haversine 公式
まず、簡単な背景は、緯度と経度の二点、2点間の距離の位置の既知の座標は次のようにPythonの式を使用して、半正矢式を用いて解くことができます。
def haversine(lat1, lon1, lat2, lon2):
# lat1, lon1 为位置 1 的经纬度坐标
# lat2, lon2 为位置 2 的经纬度坐标
import numpy as np
dlon = np.radians(lon2 - lon1)
dlat = np.radians(lat2 - lat1)
a = np.sin( dlat /2 ) **2 + np.cos(np.radians(lat1)) * np.cos(np.radians(lat2)) * np.sin( dlon /2 ) **2
c = 2 * np.arcsin(np.sqrt(a))
r = 6371 # 地球平均半径,单位为公里
return c * r
MapJoin
最も推奨される方法はmapjoinを使用することで、PyODPSはmapjoin方法を使用し非常に簡単です、あなただけが2つのデータフレームに参加したときに指定する必要がありmapjoin=True
、操作を実行するときmapjoinテーブルを行う権利を持っています。
In [3]: df1 = o.get_table('coordinates1').to_df()
In [4]: df2 = o.get_table('coordinates2').to_df()
In [5]: df3 = df1.join(df2, mapjoin=True)
In [6]: df1.schema
Out[6]:
odps.Schema {
latitude float64
longitude float64
id string
}
In [7]: df2.schema
Out[7]:
odps.Schema {
latitude float64
longitude float64
id string
}
In [8]: df3.schema
Out[8]:
odps.Schema {
latitude_x float64
longitude_x float64
id_x string
latitude_y float64
longitude_y float64
id_y string
}
ジョインによって実行されたときのデフォルトは、重いプラス_xと_yサフィックス間分かるsuffixes
ザ参加後にテーブルがある場合、バイナリタプルサフィックスから定義されたパラメータに渡されたデータフレームPyODPSを通して、自作の関数は非常に簡潔で非常に効率的な、距離を計算することができます。
In [9]: r = 6371
...: dis1 = (df3.latitude_y - df3.latitude_x).radians()
...: dis2 = (df3.longitude_y - df3.longitude_x).radians()
...: a = (dis1 / 2).sin() ** 2 + df3.latitude_x.radians().cos() * df3.latitude_y.radians().cos() * (dis2 / 2).sin() ** 2
...: df3['dis'] = 2 * a.sqrt().arcsin() * r
In [12]: df3.head(10)
Out[12]:
latitude_x longitude_x id_x latitude_y longitude_y id_y dis
0 76.252432 59.628253 0 84.045210 6.517522 0 1246.864981
1 76.252432 59.628253 0 59.061796 0.794939 1 2925.953147
2 76.252432 59.628253 0 42.368304 30.119837 2 4020.604942
3 76.252432 59.628253 0 81.290936 51.682749 3 584.779748
4 76.252432 59.628253 0 34.665222 147.167070 4 6213.944942
5 76.252432 59.628253 0 58.058854 165.471565 5 4205.219179
6 76.252432 59.628253 0 79.150677 58.661890 6 323.070785
7 76.252432 59.628253 0 72.622352 123.195778 7 1839.380760
8 76.252432 59.628253 0 80.063614 138.845193 8 1703.782421
9 76.252432 59.628253 0 36.231584 90.774527 9 4717.284949
In [13]: df1.count()
Out[13]: 2000
In [14]: df2.count()
Out[14]: 100
In [15]: df3.count()
Out[15]: 200000
df3
そこにデータのM * N個はすでに、次の最小距離は、直接かどうかを知る必要があるdf3
GROUPBY接続コールmin
最小距離集約関数は、各目標点のために得ることができます。
In [16]: df3.groupby('id_x').dis.min().head(10)
Out[16]:
dis_min
0 323.070785
1 64.755493
2 1249.283169
3 309.818288
4 1790.484748
5 385.107739
6 498.816157
7 615.987467
8 437.765432
9 272.589621
データフレームのカスタム関数
私たちは、市内の最小距離に対応する点を知っておく必要がある場合、つまり、IDの対応表は、あなたがmapjoin後のMapReduceを呼び出すことができますが、我々はまだ別の方法は、データフレームを使用することである必要があり適用する方法を。1ライン分のカスタム関数のデータを使用するように、この方法を適用することができ、軸パラメータは、行の動作を示す、1でなければなりません。
表リソース
UDFを適用するには注意を払うが、サーバー側で実行され、内部に同様の機能で使用することはできませんdf=o.get_table('table_name').to_df()
表現、特定の原則を参照して、テーブルのデータを取得するためにどこに実行するPyODPSデータフレームコード。例えば、本明細書に、表1及び表2にすべての計算を記録する場合には、表2に必要であるリソーステーブルと、テーブル定義からリソースを参照します。資源のPyODPSの使用も非常に便利なテーブル、入ってくるの単純集合であるresources
パラメータ。コレクションはイテラブルであり、データフレームオブジェクトデータフレームを直接インターフェースを呼び出さないない各反復はnamedtupleある、またはフィールド名に対応するオフセット値を取ることができ、。
## use dataframe udf
df1 = o.get_table('coordinates1').to_df()
df2 = o.get_table('coordinates2').to_df()
def func(collections):
import pandas as pd
collection = collections[0]
ids = []
latitudes = []
longitudes = []
for r in collection:
ids.append(r.id)
latitudes.append(r.latitude)
longitudes.append(r.longitude)
df = pd.DataFrame({'id': ids, 'latitude':latitudes, 'longitude':longitudes})
def h(x):
df['dis'] = haversine(x.latitude, x.longitude, df.latitude, df.longitude)
return df.iloc[df['dis'].idxmin()]['id']
return h
df1[df1.id, df1.apply(func, resources=[df2], axis=1, reduce=True, types='string').rename('min_id')].execute(
libraries=['pandas.zip', 'python-dateutil.zip', 'pytz.zip', 'six.tar.gz'])
カスタム関数では、リソーステーブルは循環によってパンダのデータフレームとして読み出し、パンダのLOCの使用を容易それによって起点に最も近いIDを取得し、最小値に対応する行を見つけることができます。パッケージは、カスタム関数で(本実施形態では、例えばパンダ)成分を使用する必要がある場合、さらに、これを参照することができる物品。
グローバル変数
場合は、データテーブルに少量のは非常に小さく、私たちは、カスタム関数で使用されるグローバル変数としても、小さなテーブルのデータをすることができます。
df1 = o.get_table('coordinates1').to_df()
df2 = o.get_table('coordinates2').to_df()
df = df2.to_pandas()
def func(x):
df['dis'] = haversine(x.latitude, x.longitude, df.latitude, df.longitude)
return df.iloc[df['dis'].idxmin()]['id']
df1[df1.id, df1.apply(func, axis=1, reduce=True, types='string').rename('min_id')].execute(
libraries=['pandas.zip', 'python-dateutil.zip', 'pytz.zip', 'six.tar.gz'])
場合アップロード機能、関数はグローバル変数(上記のコードを使用するであろうdf
)UDFにピクルスを。その顧客の三者パッケージを確保するための最良の方法は、ファイルサイズのアップロードODPSリソースが限られているので、あまりにも大きなリードUDFがリソース生成されたデータの量が多すぎるため、アップロードすることができませんでした、そしてので、しかし、この方法は非常に限られた使用シナリオであることに注意エンドバージョンは、サーバー側と一致している、または、問題の配列であり、データが非常に小さい量だけを使用することが推奨されます。
概要
使用PyODPSはmapjoinを解決することができ、我々はmapjoinを使用することをお勧めして、最高の組み込み関数を使用して計算されたものがmapjoin、直感的な、優れた性能、一般的であり、デカルト積の問題は、主に二つの方法に分けられて解決する、あなたは最高に達することができます効率は、それが十分に柔軟ではありません。別のカスタム関数データフレームを使用することで、より柔軟な、パフォーマンスのほぼ反対側、それによってテーブルリソース着信データフレームカスタム関数としてリソーステーブル、小さなテーブルを用いて、(numpyのパンダ又は性能改善を用いて得ることができます)デカルト積の動作が完了する。