pandas.DataFrame:将键列表的列映射到值列表的列

时间:2016-09-10 18:18:38

标签: python pandas dataframe

这是输入:

df = pd.DataFrame({'keys': [('K0', 'K1'), ('K1', 'K2')],
                     'A': ['A0', 'A1']})
lookup_df = pd.DataFrame({'val': ['V1', 'V2', 'V3']},
                          index = ['K0', 'K1', 'K2'])

在进行一些“加入”操作后,我希望在df中添加一个新列,将keysdf的密钥映射到val lookup_df

输出应为:

pd.DataFrame({'keys': [('K0', 'K1'), ('K1', 'K2')],
              'val': [('V0', 'V1'), ('V1', 'V2')],  
              'A': ['A0', 'A1']})

我能想到的一种方式是:

df['val'] = df['keys'].apply(lambda ks: 
    list(map(lambda k: lookup_df.loc[k].val, ks)))

还有其他更好的方法来实现这一目标吗?

3 个答案:

答案 0 :(得分:2)

你可以这样做:

In [83]: df['val'] = df['keys'].str.join(',').str.split(',', expand=True).stack().map(lookup_df.val).unstack().apply(tuple)

In [84]: df
Out[84]:
    A      keys       val
0  A0  (K0, K1)  (V1, V2)
1  A1  (K1, K2)  (V2, V3)

In [85]: lookup_df
Out[85]:
   val
K0  V1
K1  V2
K2  V3

或更好一点,但速度较慢的方法(感谢@Boud):

In [5]: df['val'] = df['keys'].apply(pd.Series).stack().map(lookup_df.val).unstack().apply(tuple)

In [6]: df
Out[6]:
    A      keys       val
0  A0  (K0, K1)  (V1, V2)
1  A1  (K1, K2)  (V2, V3)

针对10K行的计时DF:

In [18]: big = pd.concat([df] * 10**5, ignore_index=True)

In [19]: x = big.head(10**4)

In [20]: x.shape
Out[20]: (10000, 2)

In [21]: %timeit x['keys'].str.join(',').str.split(',', expand=True).stack().map(lookup_df.val).unstack().apply(tuple)
10 loops, best of 3: 75.1 ms per loop

In [22]: %timeit x['keys'].apply(pd.Series).stack().map(lookup_df.val).unstack().apply(tuple)
1 loop, best of 3: 5.5 s per loop

In [23]: %timeit x['keys'].apply(pd.Series).replace(lookup_df.val).apply(tuple)
1 loop, best of 3: 5.52 s per loop

In [24]: %%timeit
   ....: dk = pd.DataFrame(x['keys'].tolist()).applymap(lambda x: lookup_df.val[x])
   ....: x['val'] = zip(dk[0], dk[1])
   ....:
1 loop, best of 3: 1.66 s per loop

结论:最丑陋的方法目前是最快的方法

答案 1 :(得分:2)

缩短并避免字符串操作:

private func touchPointToScenePoint(recognizer: UIGestureRecognizer) -> SCNVector3 {
    // Get touch point
    let touchPoint = recognizer.locationInView(sceneView)

    // Compute near & far points
    let nearVector = SCNVector3(x: Float(touchPoint.x), y: Float(touchPoint.y), z: 0)
    let nearScenePoint = sceneView.unprojectPoint(nearVector)
    let farVector = SCNVector3(x: Float(touchPoint.x), y: Float(touchPoint.y), z: 1)
    let farScenePoint = sceneView.unprojectPoint(farVector)

    // Compute view vector
    let viewVector = SCNVector3(x: Float(farScenePoint.x - nearScenePoint.x), y: Float(farScenePoint.y - nearScenePoint.y), z: Float(farScenePoint.z - nearScenePoint.z))

    // Normalize view vector
    let vectorLength = sqrt(viewVector.x*viewVector.x + viewVector.y*viewVector.y + viewVector.z*viewVector.z)
    let normalizedViewVector = SCNVector3(x: viewVector.x/vectorLength, y: viewVector.y/vectorLength, z: viewVector.z/vectorLength)

    // Scale normalized vector to find scene point
    let scale = Float(15)
    let scenePoint = SCNVector3(x: normalizedViewVector.x*scale, y: normalizedViewVector.y*scale, z: normalizedViewVector.z*scale)

    print("2D point: \(touchPoint). 3D point: \(nearScenePoint). Far point: \(farScenePoint). scene point: \(scenePoint)")

    // Return <scenePoint>
    return scenePoint
}

答案 2 :(得分:1)

这并不意味着漂亮。

dk = pd.DataFrame(df['keys'].tolist()).applymap(lambda x: lookup_df.val[x])
df['val'] = zip(dk[0], dk[1])

df

https://domain2.com