【问题标题】:How to insert a column into a matrix, the correct Mathematica way如何将列插入矩阵,正确的 Mathematica 方式
【发布时间】:2011-11-24 03:25:53
【问题描述】:

我认为 Mathematica 偏向于行而不是列。

给定一个矩阵,插入一行似乎很容易,只需使用Insert[]

(a = {{1, 2, 3}, {4, 0, 8}, {7 , 8, 0}}) // MatrixForm

1   2    3
4   0    8
7   8    0

 row = {97, 98, 99};
(newa = Insert[a, row, 2]) // MatrixForm

1   2   3
97  98  99
4   0   8
7   8   0

但是要插入一列,经过一番挣扎,我找到了2种方法,我在下面展示,想问问这里的专家他们是否看到了更短更直接的方法(Mathematica 有这么多命令,我可以忽略了一个以非常直接的方式做这种事情的人),因为我认为我现在拥有的方法对于这样一个基本的操作来说仍然太复杂了。

第一种方法

必须做双重转置:

a = {{1, 2, 3}, {4, 0, 8}, {7 , 8, 0}}
column = {97, 98, 99}
newa = Transpose[Insert[Transpose[a], column, 2]]

1   97  2   3
4   98  0   8
7   99  8   0

第二种方法

使用 SparseArray,但需要注意索引位置。这样做有点尴尬:

(SparseArray[{{i_, j_} :> column[[i]] /; j == 2, {i_, j_} :> a[[i, j]] /; j == 1, 
              {i_, j_} :> a[[i, j - 1]] /; j > 1}, {3, 4}]) // Normal

1   97  2   3
4   98  0   8
7   99  8   0

问题是:有没有更实用的方式,比上面的短一点?我当然可以使用上述其中一种,并用一个函数包装整个东西,比如insertColumn[...],以使其易于使用。但想看看是否有比我更简单的方法来做到这一点。

作为参考,这是我在 Matlab 中的操作方式:

EDU>> A=[1 2 3;4 0 8;7 8 0]
A =
     1     2     3
     4     0     8
     7     8     0

EDU>> column=[97 98 99]';

EDU>> B=[A(:,1) column A(:,2:end)]

B =
     1    97     2     3
     4    98     0     8
     7    99     8     0

【问题讨论】:

  • 重复问题:Inserting into a 2d list
  • @WReach 您链接的问题的表述有点狭隘,要求在最后添加列(尽管有些解决方案更通用,也适合这个问题)。跨度>
  • This 问题也类似。 There Janus 提请注意通过ArrayFlatten 方法插入一列零(例如)的“技巧”,如下所示:ArrayFlatten@{{a[[All, ;; 1]], 0, a[[All, 2 ;; 3]]}}(在我看来,recent question 已被处理得更多比这个更严厉的是“可能的重复”)
  • @TomD 我认为问题没有得到平等对待的一个原因是更多的人意识到前一个问题是重复的(例如,我不知道这个问题的主题之前讨论过在如此相似的环境中,当然 Sjoerd 也没有)。那是因为最近有很多人(包括我自己)加入了 mma SO 标签。 OTOH,一旦问题获得动力(答案、投票、cmets 等),它就会开始自己的生命,而结束可能不再是一个好的选择。

标签: wolfram-mathematica


【解决方案1】:

您的双重Transpose 方法看起来不错。对于非常大的矩阵,这将快 2-3 倍:

MapThread[Insert, {a, column, Table[2, {Length[column]}]}]

如果你想模仿你的 Matlab 方式,最接近的可能是这样的:

ArrayFlatten[{{a[[All, ;; 1]], Transpose[{column}], a[[All, 2 ;;]]}}]

请记住,插入需要制作整个矩阵副本。因此,如果您打算以这种方式构建矩阵,则预先分配矩阵(如果您知道其大小)并通过 Part 进行就地修改会更有效。

【讨论】:

  • 谢谢,我有点接近你的第二种方法,但我正在写一个 [[All,1]] 并且很难从那里开始,直到现在我才知道我可以使用 [[All, ;; 1]]。这个微小的差异使得更容易使用输出成为可能。这真的有助于了解这个很酷的技巧。我相信这会派上用场,因为我在 Mathematica 中使用了很多矩阵。再次感谢。
【解决方案2】:

我想我会这样做,但这里有一些其他的方法:

-与MapIndexed

newa = MapIndexed[Insert[#1, column[[#2[[1]]]], 2] &, a]

-与Sequence

newa = a;
newa[[All, 1]] = Transpose[{newa[[All, 1]], column}];
newa = Replace[a, List -> Sequence, {3}, Heads -> True]

有趣的是,这似乎是一种“就地”工作的方法,即它并不真正需要 Leonid 的回答中所述的矩阵副本,如果您打印生成的矩阵,它显然是一种魅力。

但是,有一个大问题。在数学组讨论“part assigned sequence behavior puzzling”中查看Sequence 的问题。

【讨论】:

  • +1。您提到的问题是我没有使用基于 Sequence 的方法的原因之一。这里还有两个相关链接,一个是最近的:groups.google.com/group/comp.soft-sys.math.mathematica/…groups.google.com/group/comp.soft-sys.math.mathematica/…。我通常对基于Sequence 的作业持消极态度,原因是我在这些帖子中的帖子中提到的。不使用Sequence 的另一个原因是这将导致打包矩阵的解包。
  • 顺便说一句,Sequence 的方法还是会导致复制,只是更好的隐藏。当您执行Insert 时,复制是在定义时完成的。使用基于Sequence 的方法,复制在运行时完成,在评估的Sequence - 拼接步骤期间完成。在这方面,我考虑了一个列表示例 - 在 MathLink 的文档中使用 Sequence 构建:reference.wolfram.com/mathematica/tutorial/… 特别具有误导性。他们强调性能,但忽略了这种方法具有二次复杂度的事实(如Append)。
【解决方案3】:

我通常只是这样做:

In: m0 = ConstantArray[0, {3, 4}]; 
    m0[[All, {1, 3, 4}]] = {{1, 2, 3}, {4, 0, 8}, {7, 8, 0}}; 
    m0[[All, 2]] = {97, 98, 99}; m0 

Out: 
    {{1, 97, 2, 3}, {4, 98, 0, 8}, {7, 99, 8, 0}}

我不知道它在效率方面如何。

【讨论】:

    【解决方案4】:

    我最初将此作为评论发布(现已删除)

    基于user656058this 问题(Mathematica 'Append To' Function Problem)中给出的方法和Mr Wizardreply,以下替代方法添加使用TableInsert 可以收集到矩阵的列:

    (a = {{1, 2, 3}, {4, 0, 8}, {7, 8, 0}});
    column = {97, 98, 99};
    
    Table[Insert[a[[i]], column[[i]], 2], {i, 3}] // MatrixForm
    

    给予

    类似地,添加一列零(比如说):

    Table[Insert[#[[i]], 0, 2], {i, Dimensions[#][[1]]}] & @ a 
    

    如上面的 cmets 中所述,Janus 已引起人们注意通过ArrayFlatten 方法添加一列零的“技巧”(请参阅​​here

    ArrayFlatten[{{Take[#, All, 1], 0, Take[#, All, -2]}}] & @ 
      a // MatrixForm
    

    编辑

    也许更简单,至少对于较小的矩阵

    (Insert[a[[#]], column[[#]], 2] & /@ Range[3]) // MatrixForm
    

    或者,插入一列零

    Insert[a[[#]], 0, 2] & /@ Range[3]
    

    或者,更笼统一点:

    Flatten@Insert[a[[#]], {0, 0}, 2] & /@ Range[3] // MatrixForm
    

    当然,也可以轻松适应 AppendPrepend

    【讨论】:

      【解决方案5】:

      您可以在大小为 1 的子集中使用具有 2 级别规范的 Join 以及 Partition:

      a = {{1, 2, 3}, {4, 0, 8}, {7 , 8, 0}}
      column = {97, 98, 99}
      newa = Join[a,Partition[column,1],2]
      

      【讨论】:

      • 我认为这是建议的解决方案的缺点。效果很好!
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-01-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多