在 python 中读取矩阵并获取行名和列名
Posted
技术标签:
【中文标题】在 python 中读取矩阵并获取行名和列名【英文标题】:reading a matrix and fetch row and column names in 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.8
sample2,sample3 0.8
等在一个大文件中。
当我使用csv.reader
时,每一行都会变成一个列表,并且跟踪行和列名会使程序变得狡猾。我想知道一种优雅的方法,比如使用numpy
或pandas
。
期望的输出:
sample1,sample3 0.8
sample2,sample3 0.8
1 可以忽略,因为在同一个样本之间,它总是为 1。
【问题讨论】:
pandas 和 numpy 都有 csv 阅读器。有很多关于这些的问题。 【参考方案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 -> value
。所以,最终你的pairs
看起来像column -> index -> value
。它也将保证免费nan
。请注意,.to_dict()
仅在您的索引包含您想要的行名时才有效,否则它将返回默认索引,即数字。
附言。如果您的文件很大,我建议您分块阅读。在这种情况下,上面的代码将针对每个块重复。所以它应该在你的循环中迭代块。但是,您必须小心地将来自下一个块的新数据附加到pairs
。以下链接供您参考:
-
Pandas I/O docs
Pandas
read_csv()
function
SO question on chunked read
您可能还想阅读参考资料 1,了解 Pandas 支持的其他类型的 I/O。
【讨论】:
【参考方案3】:要读取它,您需要 skipinitialspace
和 index_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
【讨论】:
我的问题是如何取出这些对?所需的输出是行名和列名。以上是关于在 python 中读取矩阵并获取行名和列名的主要内容,如果未能解决你的问题,请参考以下文章