【问题标题】:Given a vector or list,how to make a symmetric matrix filled with numbers starting from one?给定一个向量或列表,如何制作一个从一个开始的数字填充的对称矩阵?
【发布时间】:2020-03-09 06:36:30
【问题描述】:

给定一些项目,比如“a”、“b”、“c”。我想让一个对称矩阵看起来像这样:

    a   b   c
a   1   2   3
b   2   4   5
c   3   5   6

矩阵中填充了从数字 1 开始的一系列数字。因为矩阵是对称的,所以对角线以上的值应该与对角线以下的值相同。另外,我还想在对角线上填数字。

更新:我已经完成了 Python 的工作,但我是 Python 的新手,我的代码可能相当多余。 我也希望收到用R写的答案。

import pandas as pd
import numpy as np
import itertools

var = ["a","b","c"]
mylist = list(itertools.combinations_with_replacement(var, 2))

df = pd.DataFrame(mylist,columns = ["col_1","col_2"])
df["num"] = list(range(1,len(df['col_1'])+1))

df2 = pd.DataFrame()
df2["col_1"] = df["col_2"]
df2["col_2"] = df["col_1"]
df2["num"] = df["num"]

mydf = df.append(df2)
mydf['label'] = mydf[['col_1', 'col_2']].apply(lambda x: '_'.join(x), axis=1)

mydf = mydf[["label","num"]]


mylist_2 = list(itertools.product(var, repeat=2))
df_2 = pd.DataFrame(mylist_2,columns = ["col_1","col_2"])
df_2["label"] = df_2[['col_1', 'col_2']].apply(lambda x: '_'.join(x), axis=1)

new_df = pd.merge(df_2[["label"]],mydf,on = "label",how = "inner").drop_duplicates()

new_list = list(new_df.num)
my_array = np.asarray(new_list).reshape(len(var),len(var))

matrix_df = pd.DataFrame(my_array,index=var,columns=var)

【问题讨论】:

  • 判断ab之间关系的规则是什么?
  • 您还标记了 R 和 Python?到目前为止你有没有尝试过任何东西,你可以发布你的代码吗?
  • 你想要一个对称矩阵给定什么?方阵?向量?
  • 正如@kosnik 上面所说,矩阵的值是如何确定的?它是现有的内置函数还是您将编写的东西?是矢量化函数吗?

标签: python r tidyverse


【解决方案1】:

最坏的情况,您创建一个与向量一样长和宽的空方阵,然后迭代[i,j](行和列索引)的所有组合并计算每个单元格的值。

如果它是对称的,您可以跳过对角线一侧的迭代:仅计算 i <= j 的组合并在同一迭代中填充 [i,j][j,i] 的值。

编辑以包含一些代码:

vec <- c(1,2,3)
names(vec) <- c("a", "b", "c")
relate <- function(x,y) { x + y }
len <- length(vec)
mat <- matrix(rep(NA_real_, len^2), ncol=len)
for(i in 1:len){
  for(j in i:len){   # Do not compute symmetrical lower half. 
    # Fill in with mirrored values.
    mat[i,j] <- mat[j,i] <- relate(vec[i], vec[j])
    # Omit "mat[j,i] <-" to get a triangular matrix
  }
}
colnames(mat) <- names(vec)
rownames(mat) <- names(vec)
mat

#    a b c
# a  2 3 4
# b  3 4 5
# c  4 5 6

EDIT 2 因为就地编辑更适合大型结构

library(data.table)
vec <- c(1,2,3)
names(vec) <- c("a", "b", "c")
relate <- function(x,y) { x + y }
len <- length(vec)
mat <- as.data.table(matrix(rep(NA_real_, len^2), ncol=len))
for(i in 1:len){
  for(j in i:len){
    res <- relate(vec[i], vec[j])
    set(mat, i, j, res)
    # set(mat, j, i, res)  # Omitting the second assignment to get a triangular result instead.
  }
}
names(mat) <- names(vec)
mat[, rowID := names(vec)] # data.table uses only numeric index for rows
mat

#     a  b c rowID
# 1:  2  3 4     a
# 2: NA  4 5     b
# 3: NA NA 6     c

您可以将最终的 data.table 转换回矩阵,如果您需要严格以矩阵格式分配行名。

为完整性编辑 3

可能有一些实现的功能可以做这种事情,我对这些功能还不够熟悉,无法冒险提出解决方案。 tidyverse purrr::map2() 系列函数可能是替换嵌套 for 循环 https://purrr.tidyverse.org/reference/map2.html 的候选者。然而,我的理解是,区别主要在于代码的可读性和数量,而不是实际性能。

【讨论】:

  • 您能否提供一些代码示例来说明您将如何实现您的建议?
  • 我当时很忙,所以我假设能用两种语言编写代码的人都熟悉二维索引和基本循环结构。我现在正在编辑它以包含代码。
【解决方案2】:
m <- outer(1:3,1:3,"+")
m[,1] <- 1:3
m[1,] <- 1:3

没有更详细的信息,我只能通过上面来帮助你

【讨论】:

    【解决方案3】:

    看看这是否适合你:

    a,b,c = [1,2,3]
    val = [a,b,c]
    for i in val:
        if i==a:
            lst = [a,b,c]
        else:
            lst = [i,b+i,c+i]
        print(*lst)
    

    输出:

    1 2 3
    2 4 5
    3 5 6
    

    【讨论】:

    • 您的解决方案假定bc 列中的值是a 列中值的函数。这不是问题中描述的那种关系。
    • 是吗? i 每次迭代都会发生变化,非常有效:[[a,b,c],[b,b+b,c+b],[c,b+c,c+c]]。这不正是行动想要的吗?
    • 对不起,因为我一开始没有把我的问题解释清楚,你的回答不太合适。
    • @SayanipDutta 抱歉,我没有正确表达我的分歧,但我没有时间进行编辑,所以我就离开了。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-06-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多