【问题标题】:reading a matrix and fetch row and column names in python在 python 中读取矩阵并获取行名和列名
【发布时间】:2016-02-05 12:24:54
【问题描述】:

我想读取一个矩阵文件,如下所示:

sample  sample1 sample2 sample3
sample1 1   0.7 0.8
sample2 0.7 1   0.8
sample3 0.8 0.8 1

我想获取所有值 > 0.8 的对。例如:sample1,sample3 0.8sample2,sample3 0.8 等在一个大文件中。

当我使用csv.reader 时,每一行都会变成一个列表,并且跟踪行和列名会使程序变得狡猾。我想知道一种优雅的方法,比如使用numpypandas

期望的输出:

sample1,sample3 0.8 
sample2,sample3 0.8

1 可以忽略,因为在同一个样本之间,它总是为 1。

【问题讨论】:

  • pandas 和 numpy 都有 csv 阅读器。有很多关于这些的问题。

标签: python-2.7 numpy pandas


【解决方案1】:

您可以使用np.triu 屏蔽掉上三角值:

In [11]: df
Out[11]:
         sample1  sample2  sample3
sample
sample1      1.0      0.7      0.8
sample2      0.7      1.0      0.8
sample3      0.8      0.8      1.0

In [12]: np.triu(df, 1)
Out[12]:
array([[ 0. ,  0.7,  0.8],
       [ 0. ,  0. ,  0.8],
       [ 0. ,  0. ,  0. ]])

In [13]: np.triu(df, 1) >= 0.8
Out[13]:
array([[False, False,  True],
       [False, False,  True],
       [False, False, False]], dtype=bool)

然后提取正确的索引/列我认为你必须使用np.where*:

In [14]: np.where(np.triu(df, 1) >= 0.8)
Out[14]: (array([0, 1]), array([2, 2]))

这为您提供了一个包含第一个索引索引和列索引的数组(这是此 numpy 版本中效率最低的部分):

In [16]: index, cols = np.where(np.triu(df, 1) >= 0.8)

In [17]: [(df.index[i], df.columns[j], df.iloc[i, j]) for i, j in zip(index, cols)]
Out[17]:
[('sample1', 'sample3', 0.80000000000000004),
 ('sample2', 'sample3', 0.80000000000000004)]

根据需要。

*我可能忘记了获取最后一个块的更简单方法(编辑:下面的 pandas 代码可以做到这一点,但我认为可能还有另一种方法。)


您可以在 pandas 中使用相同的技巧,但使用堆栈来本地获取索引/列:

In [21]: (np.triu(df, 1) >= 0.8) * df
Out[21]:
         sample1  sample2  sample3
sample
sample1        0        0      0.8
sample2        0        0      0.8
sample3        0        0      0.0

In [22]: res = ((np.triu(df, 1) >= 0.8) * df).stack()

In [23]: res
Out[23]:
sample
sample1  sample1    0.0
         sample2    0.0
         sample3    0.8
sample2  sample1    0.0
         sample2    0.0
         sample3    0.8
sample3  sample1    0.0
         sample2    0.0
         sample3    0.0
dtype: float64

In [24]: res[res!=0]
Out[24]:
sample
sample1  sample3    0.8
sample2  sample3    0.8
dtype: float64

【讨论】:

    【解决方案2】:

    如果您想使用 Pandas,以下答案会有所帮助。我假设您会自己弄清楚如何将矩阵文件读入 Pandas。我还假设您的列和行标记正确。读取数据后,您最终会得到一个 DataFrame,它看起来很像您在问题顶部的矩阵。我假设所有行名都是 DataFrame 索引。我以您已将数据读入一个名为df 的变量作为我的起点。

    Pandas 按行比按列更有效。因此,我们按行执行操作,循环遍历列。

    pairs = {}
    for col in df.columns:
        pairs[col] = df[(df[col] >= 0.8) & (df[col] < 1)].index.tolist()
        # If row names are not an index, but a different column named 'names' run the following line, instead of the line above
        # pairs[col] = df[(df[col] >= 0.8) & (df[col] < 1)]['names'].tolist()
    

    或者,您可以使用apply() 来执行此操作,因为这也会遍历所有列。 (也许在 0.17 会释放 GIL 以获得更快的结果,我不知道,因为我没有尝试过。)

    pairs 现在将包含作为键的列名和作为相关性大于 0.8 但小于 1 的值的行名列表。

    如果您还想从 DataFrame 中提取相关值,请将 .tolist() 替换为 .to_dict().to_dict() 将生成一个字典,索引是键,值是值:{index -&gt; value}。所以,最终你的pairs 看起来像{column -&gt; {index -&gt; value}}。它也将保证免费nan。请注意,.to_dict() 仅在您的索引包含您想要的行名时才有效,否则它将返回默认索引,即数字。


    附言。如果您的文件很大,我建议您分块阅读。在这种情况下,上面的代码将针对每个块重复。所以它应该在你的循环中迭代块。但是,您必须小心地将来自下一个块的新数据附加到pairs。以下链接供您参考:

    1. Pandas I/O docs
    2. Pandas read_csv() function
    3. SO question on chunked read

    您可能还想阅读参考资料 1,了解 Pandas 支持的其他类型的 I/O。

    【讨论】:

      【解决方案3】:

      要读取它,您需要 skipinitialspaceindex_col 参数:

      a=pd.read_csv('yourfile.txt',sep=' ',skipinitialspace=True,index_col=0)
      

      要成对地获取值:

      [[x,y,round(a[x][y],3)] for x in a.index for y in a.columns if x!=y and a[x][y]>=0.8][:2]
      

      给予:

      [['sample1', 'sample3', 0.8], 
      ['sample2', 'sample3', 0.8]]
      

      【讨论】:

        【解决方案4】:

        使用scipy.sparse.coo_matrix,因为它适用于“(行,列)数据”格式。

        from scipy.sparse import coo_matrix
        import numpy as np
        
        M = np.matrix([[1.0, 0.7, 0.8], [0.7, 1.0, 0.8], [0.8, 0.8, 1.0]])
        S = coo_matrix(M)
        

        这里,S.row 和 S.col 是行和列索引的数组,S.data 是这些索引处的值数组。所以你可以过滤

        idx = S.data >= 0.8
        

        例如,仅使用这些元素创建一个新矩阵:

        S2 = coo_matrix((S.data[idx], (S.row[idx], S.col[idx])))
        print S2
        

        输出是

        (0, 0)  1.0
        (0, 2)  0.8
        (1, 1)  1.0
        (1, 2)  0.8
        (2, 0)  0.8
        (2, 1)  0.8
        (2, 2)  1.0
        

        注 (0,1) 不会出现,因为值为 0.7。

        【讨论】:

          【解决方案5】:

          pandas 的read_table 可以处理sep 参数中的正则表达式。

          In [19]: !head file.txt
          sample  sample1 sample2 sample3
          sample1 1   0.7 0.8
          sample2 0.7 1   0.8
          sample3 0.8 0.8 1
          
          In [20]: df = pd.read_table('file.txt', sep='\s+')
          
          In [21]: df
          Out[21]:
              sample  sample1  sample2  sample3
          0  sample1      1.0      0.7      0.8
          1  sample2      0.7      1.0      0.8
          2  sample3      0.8      0.8      1.0
          

          从那里,您可以过滤所有 >= 0.8 的值。

          In [23]: df[df >= 0.8]
          Out[23]:
              sample  sample1  sample2  sample3
          0  sample1      1.0      NaN      0.8
          1  sample2      NaN      1.0      0.8
          2  sample3      0.8      0.8      1.0
          

          【讨论】:

          • 我的问题是如何取出这些对?所需的输出是行名和列名。
          猜你喜欢
          • 2016-06-13
          • 2013-12-11
          • 1970-01-01
          • 1970-01-01
          • 2019-09-11
          • 1970-01-01
          • 2011-08-10
          • 2011-05-11
          • 1970-01-01
          相关资源
          最近更新 更多