Mathematica中的条件数据处理

时间:2011-05-25 20:10:16

标签: data-structures wolfram-mathematica

我正在尝试在Mathematica中准备有效数据分析的最佳工具。 我有一个大约300列& 100 000行。

最好的技巧是什么:

“删除”,“提取”或简单地“考虑”部分数据结构,用于绘制例如。

我能想到的最棘手的例子之一是:

  

鉴于数据结构,

     

为第2列中的值等于x且第8列中的值不等于y的每一行提取第1列到第3列,第6列到第9列以及最后一行

我也欢迎任何有关数据操作的一般建议。

4 个答案:

答案 0 :(得分:6)

对于具有命名列的表中的数据的通用操作,我将引用您的this我的解决方案,以获得类似的问题。对于任何特定情况,手动编写Select函数可能更容易。但是,对于许多列和许多不同的查询,陷入索引的可能性很高。以下是来自上述帖子的修改后的解决方案,它提供了更友好的语法:

Clear[getIds];
getIds[table : {colNames_List, rows__List}] := {rows}[[All, 1]];

ClearAll[select, where];
SetAttributes[where, HoldAll];
select[cnames_List, from[table : {colNames_List, rows__List}], where[condition_]] :=
With[{colRules =  Dispatch[ Thread[colNames -> Thread[Slot[Range[Length[colNames]]]]]],
    indexRules  =  Dispatch[Thread[colNames -> Range[Length[colNames]]]]},
     With[{selF = Apply[Function, Hold[condition] /. colRules]},
       Select[{rows}, selF @@ # &][[All, cnames /. indexRules]]]];

这里发生的是Select中使用的函数是根据您的规范自动生成的。例如(使用@Yoda的例子):

rows = Array[#1 #2 &, {5, 15}];

我们需要定义列名(必须是没有值的字符串或符号):

In[425]:= 
colnames = "c" <> ToString[#] & /@ Range[15]

Out[425]= {"c1", "c2", "c3", "c4", "c5", "c6", "c7", "c8", "c9", "c10", "c11", "c12", 
"c13", "c14", "c15"}

(实际上,通常名称更具描述性)。这是表格:

table = Prepend[rows, colnames];

以下是您需要的选择语句(我选择了x = 4y=2):

select[{"c1", "c2", "c3", "c6", "c7", "c8", "c9", "c15"}, from[table],
    where["c2" == 4 && "c8" != 2]]

{{2, 4, 6, 12, 14, 16, 18, 30}}

现在,对于单个查询,这看起来像是一种复杂的方法。但是您可以执行许多不同的查询,例如

In[468]:= select[{"c1", "c2", "c3"}, from[table], where[EvenQ["c2"] && "c10" > 10]]

Out[468]= {{2, 4, 6}, {3, 6, 9}, {4, 8, 12}, {5, 10, 15}}

和类似的。

当然,如果您的数据中存在特定的相关性,您可能会发现一种特定的特殊用途算法会更快。上述函数可以通过多种方式进行扩展,以简化常见查询(包括“all”等),或自动编译生成的纯函数(如果可能)。

修改

在哲学上,我确信许多Mathematica用户(包括我自己)发现自己不时地一次又一次地编写类似的代码。事实上,Mathematica具有简洁的语法,因此通常很容易为任何特定情况编写。但是,只要一个在某个特定域中工作(例如,表中的数据操作),重复自己的成本对于许多操作来说都很高。我的示例在一个非常简单的设置中说明了一种可能的出路 - 创建一种特定于域的语言(DSL)。为此,通常需要为其定义语法/语法,并将编译器从中编写到Mathematica(以自动生成Mathematica代码)。现在,上面的例子是这个想法的一个非常原始的实现,但我的观点是Mathematica通常非常适合DSL创建,我认为这是一种非常强大的技术。

答案 1 :(得分:4)

data = RandomInteger[{1, 20}, {40, 20}]

x = 5;
y = 8;
Select[data, (#[[2]] == x && #[[8]] != y &)][[All, {1, 2, 3, 6, 7, 8, 9, -1}]]

==> {{5, 5, 1, 4, 18, 6, 3, 5}, {10, 5, 15, 3, 15, 14, 2, 5}, {18, 5, 6, 7, 7, 19, 14, 6}}

获取矩阵和列表的一些有用命令是Span(;;),DropTakeSelectCases等等。请参阅tutorial/GettingAndSettingPiecesOfMatricesguide/PartsOfMatrices

Part([[...]])与;;结合使用可能非常强大。 a [[All,1 ;; - 1 ;; 2]],例如,意味着取所有行和所有奇数列(-1具有通常从末尾开始计数的含义)。

Select可用于从列表中选取元素(并记住矩阵是列表的列表),基于逻辑函数。它的孪生兄弟是Cases,根据模式进行选择。我在这里使用的函数是'pure' function,其中#指的是应用此函数的参数(在这种情况下是列表的元素)。由于元素本身就是列表(矩阵的行),我可以使用Part([[..]]函数来引用列。

答案 2 :(得分:1)

要提取列(或行),您可以通过部分索引

来完成
data = Array[#1 #2 &, {5, 15}];
data[[All, Flatten@{Range@3, Range @@ {6, 9}, -1}]]

MatrixForm@%

最后一行只是为了查看它。

正如Sjoerd在他的评论中所提到的(以及他的答案中的解释),使用Span (;;)命令可以轻松地为单个范围编制索引。如果您要加入多个不相交的范围,则使用Flatten组合使用Range创建的单独范围比手动输入更容易。

答案 3 :(得分:1)

我看了:

  

为第2列中的值等于x且第8列中的值不等于y的每一行提取第1列到第3列,第6列到第9列以及最后一行

作为我们想要的意思:

  • 每行的元素1-3和6-9

  • [[2]] == x && [[8]] != y
  • 中的最后一个元素

这就是我一起攻击的地方:

a = RandomInteger[5, {20, 10}];          (*define the array*)
x = 4; y = 0;                            (*define the test values*)

Join @@ Range @@@ {1 ;; 3, 6 ;; 9};      (*define the column ranges*)

#2 == x && #8 != y & @@@ a;              (*test the rows*)

Append[%%, #] & /@ % /. {True -> -1, False :> Sequence[]};  (*complete the ranges according to the test*)

MapThread[Part, {a, %}] // TableForm     (*extract and display*)