いくつかの方法で処理PyODPS DATAFRAME直積

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個はすでに、次の最小距離は、直接かどうかを知る必要があるdf3GROUPBY接続コール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のパンダ又は性能改善を用いて得ることができます)デカルト積の動作が完了する。

おすすめ

転載: yq.aliyun.com/articles/705184