Pandas - 在applymap过程中获取每个元素的行列名称

14

我试图比较一个字符串列表的相似度,并将结果放在 Pandas 数据框中以供检查;因此我使用一个列表作为索引,另一个列表作为列。然后我想要在它们上面计算 "Levenshtein 相似度"(一种比较两个单词之间相似度的函数)。

我尝试使用 applymap 在每个单元格上执行此操作,并将单元格索引与单元格列进行比较。我该如何做?还有更简单的替代方法吗?

things = ['car', 'bike', 'sidewalk', 'eatery']
action = ['walking', 'caring', 'biking', 'eating']
matrix = pd.DataFrame(index = things, columns = action)

def lev(x):
    x = Levenshtein.distance(x.index, x.column)  
matrix.applymap(lev)

到目前为止,我只能采用以下方法(下面)使用,但我发现它笨拙而缓慢。


matrix = pd.DataFrame(data = [action for i in things], index = things, columns = action)
for i, values in matrix.iterrows():
    for j, value in enumerate(values):
        matrix.ix[i,j] = Levenshtein.distance(i, value)
3个回答

17

我认为您可以在数据框上使用apply函数,并使用.name访问列的值:

def lev(x):
    #replace your function
    return x.index + x.name
a = matrix.apply(lev)
print (a)
                  walking          caring          biking          eating
car            carwalking       carcaring       carbiking       careating
bike          bikewalking      bikecaring      bikebiking      bikeeating
sidewalk  sidewalkwalking  sidewalkcaring  sidewalkbiking  sidewalkeating
eatery      eaterywalking    eaterycaring    eaterybiking    eateryeating

编辑:

如果需要进行一些算术操作,请使用broadcasting

a = pd.DataFrame(matrix.index.values + matrix.columns.values[:,None], 
                 index=matrix.index, 
                 columns=matrix.columns)
print (a)
             walking       caring           biking         eating
car       carwalking  bikewalking  sidewalkwalking  eaterywalking
bike       carcaring   bikecaring   sidewalkcaring   eaterycaring
sidewalk   carbiking   bikebiking   sidewalkbiking   eaterybiking
eatery     careating   bikeeating   sidewalkeating   eateryeating
或:
a = pd.DataFrame(matrix.index.values + matrix.columns.values[:, np.newaxis], 
                 index=matrix.index, 
                 columns=matrix.columns)
print (a)
             walking       caring           biking         eating
car       carwalking  bikewalking  sidewalkwalking  eaterywalking
bike       carcaring   bikecaring   sidewalkcaring   eaterycaring
sidewalk   carbiking   bikebiking   sidewalkbiking   eaterybiking
eatery     careating   bikeeating   sidewalkeating   eateryeating

1
太棒了 - 谢谢。但是是否有一种向量化/逐元素操作的方法可以实现?您所做的基本上就是我一直在使用 iterrows 做的事情。 - jim jarnac
好的,我明白了,无论如何我都必须使用apply / iterrows进行迭代。有点令人失望,但谢谢。 - jim jarnac
1
不确定,但如果检查这里提到的方法可能会更快。但是如果在每次循环中应用某些函数,则可能具有相同的性能。 - jezrael
我感到困惑,当我尝试return x.index + x.name时,出现了AttributeError: 'int' object has no attribute 'name'和AttributeError: 'int' object has no attribute 'index'的错误。我的数据框由整数组成。 - rkian
@rkian:您有一个单独的问题,请发布一个独立的问题,引用这个问题和答案的链接,我们很乐意看一下。如果您得到了“object has no attribute 'name'”错误提示,则说明您访问了单个单元格而不是数据系列,因此可能您尝试在单个数据系列上执行 .apply(),而不是在数据框上操作。 - smci
显示剩余3条评论

9
您可以通过嵌套“apply”来实现,具体如下:

things = ['car', 'bike', 'sidewalk', 'eatery']
action = ['walking', 'caring', 'biking', 'eating']
matrix = pd.DataFrame(index=things, columns=action)
matrix.apply(lambda x: pd.DataFrame(x).apply(lambda y: LD(x.name, y.name), axis=1))

输出:

          walking  caring  biking  eating
car             6       3       6       5
bike            6       5       3       5
sidewalk        7       8       7       8
eatery          6       5       6       3

这里调用 pd.DataFrame(x) 是因为 x 是一个 Series 对象,而 Series.applyapplymap 类似,不会携带 indexcolumns 信息。


0
这是一个应用和理解的结合:
def mapping_function(value, index, column_name):
    # this is called for each cell
    mapping_result = column_name + '|' + str(index) + '|' + str(value)
    return mapping_result


def _column_mapping_function(column_series):
    column_name = column_series.name
    new_series_data = [mapping_function(value, index, column_name) for index, value in column_series.items()]
    new_series = pd.Series(data=new_series_data, index=column_series.index)
    return new_series
    
result = indexed_data_frame.apply(_column_mapping_function)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接