首页 > 解决方案 > 创建一个哈希确实在熊猫中定义组

问题描述

我有一个由几个元信息组成的数据框。如果所有特征都相同,则该行属于一个组。

假设这个数据框是一个简化的例子:

import pandas as pd
data = pd.DataFrame({"feature1": ["A", "A", "A", "B", "B", "B"]
                        , "feature2": [1,2,1,3,1,3]})

我现在想为每个不同的组合创建一个不同的标记,所以包括我的标记列,我希望这个数据框

expected_result = pd.DataFrame({"feature1": ["A", "A", "A", "B", "B", "B"]
                                   , "feature2": [1,2,1,3,1,3]
                                   , "hash": ["ab", "jk", "ab", "lu", "la", "lu"]})
   feature1   feature2  hash
0   A         1         ab
1   A         2         jk
2   A         1         ab
3   B         3         lu
4   B         1         la
5   B         3         lu

def create_uniqueID(x, y, z): 如果 x 为 None: x = " " else: x = str(x) 如果 y 为 None: y = " " else: x = str(x) 如果 z 为 None: z = "_" 否则:x = str(x) 返回 x+y+z

自然地,我想到了散列这些数据,因此尝试了这个:

def create_uniqueID(x, y):
    if x is None:
        x = "_"
    if y is None:
        y = "_"
    return hash(tuple([x,y]))

data["marker"] = data.apply(create_uniqueID(data.feature1, data.feature2))

但是比我得到的反馈,那个 Series 是可变的,因此不能被散列。所以我假设我必须按元素来做,但我不知道如何以简洁有效的方式做到这一点。

可以获取每列的所有值,对它们进行散列并重新附加它们,但我认为这不是一个好的解决方案。

标签: pythonpandasdataframe

解决方案


使用 lambda 函数分别处理每一行:

data["marker"] = data.apply(lambda x: create_uniqueID(x.feature1, x.feature2), axis=1)
print (data)

  feature1  feature2               marker
0        A         1 -6565221176676644544
1        A         2 -6565221176675562019
2        A         1 -6565221176676644544
3        B         3  4352711037653751181
4        B         1  4352711037651586131
5        B         3  4352711037653751181

另一个想法是使用 lambda 函数,但在将Nones 替换为之前_

np.random.seed(123)
N = 10000
L = list('abcdef') + [None]
data = pd.DataFrame({'feature1': np.random.choice(L, N),
                     'feature2':np.random.randint(100, size=N)})
#print (data)

data["marker1"] = data.fillna('_').apply(lambda x: hash(tuple(x)), axis=1)
print (data)
     feature1  feature2              marker1
0        None        73 -2622163292899442353
1           f        93  6883629009348118745
2        None        73 -2622163292899442353
3           c        95  8232223848018743176
4           e        95 -4199008080420766281
      ...       ...                  ...
9995        e        42 -4199008080510615856
9996        b        65 -2981575294812687977
9997        c        95  8232223848018743176
9998     None        19 -2622163292940578303
9999     None        61 -2622163292990374453

[10000 rows x 3 columns]

10k 行的性能不同,它取决于 DataFrame 的长度:

np.random.seed(123)

def create_uniqueID(x, y):
    if x is None:
        x = "_"
    if y is None:
        y = "_"
    return hash(tuple([x,y]))

N = 10000
L = list('abcdef') + [None]
data = pd.DataFrame({'feature1': np.random.choice(L, N),
                     'feature2':np.random.randint(100, size=N)})
#print (data)

data["marker0"] = data.apply(lambda x: create_uniqueID(x.feature1, x.feature2), axis=1)
data["marker1"] = data.fillna('_').apply(lambda x: hash(tuple(x)), axis=1)

data['hash1'] = [hash(''.join(str(y) for y in x[1].values)) for x in data.iterrows()]
data['hash2'] = data.apply(lambda x: hash(str(x.feature1)+str(x.feature2)), axis=1)

print (data)

In [183]: %timeit data.apply(lambda x: create_uniqueID(x.feature1, x.feature2), axis=1)
332 ms ± 25.6 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

In [184]: %timeit data.fillna('_').apply(lambda x: hash(tuple(x)), axis=1)
212 ms ± 17.3 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

In [185]: %timeit [hash(''.join(str(y) for y in x[1].values)) for x in data.iterrows()]
996 ms ± 113 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

In [186]: %timeit data.apply(lambda x: hash(str(x.feature1)+str(x.feature2)), axis=1)
326 ms ± 8.09 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

推荐阅读