【问题标题】:Create a hash do define groups in pandas创建一个哈希确实在熊猫中定义组
【发布时间】:2019-12-17 18:29:57
【问题描述】:

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

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

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 为无: x = "" 别的: x = str(x) 如果 y 为无: y = "" 别的: x = str(x) 如果 z 为无: 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 是可变的,因此不能被散列。所以我假设我必须按元素来做,但我不知道如何以简洁有效的方式做到这一点。

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

【问题讨论】:

    标签: python pandas dataframe


    【解决方案1】:

    你可以使用:

    import pandas as pd
    data = pd.DataFrame({"feature1": ["A", "A", "A", "B", "B", "B"],
                         "feature2": [1, 2, 1, 3, 1, 3]})
    
    data['hash'] = [hash(''.join(str(y) for y in x[1].values)) for x in data.iterrows()]
    

    或者,作为替代

    data['hash'] = data.apply(lambda x: hash(str(x.feature1)+str(x.feature2)), axis=1)
    

    结果:

      feature1  feature2                 hash
    0        A         1  8263268926816845868
    1        A         2 -8020701168240960676
    2        A         1  8263268926816845868
    3        B         3 -4924655571523756344
    4        B         1  6029195539680549382
    5        B         3 -4924655571523756344
    

    性能:

    【讨论】:

    • 嗯,试试 10k 数据测试
    【解决方案2】:

    使用 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)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-08-30
      • 2010-10-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多