比较数组与文件以及数组元素中的表单组

时间:2019-01-03 03:35:26

标签: python arrays pandas numpy

我有一个带有字母(制表符分隔)的文本文件,以及一个带有几个字母(单行)的numpy数组(obj)。文本文件中的行具有不同的列数。文本文件中的某些行可能具有相同字母的多个副本(我希望每行仅考虑一个字母的单个副本)。假定文本文件同一行中的字母彼此相似。此外,numpy数组obj的每个字母都出现在文本文件的一或多个行中。

以下是文本文件的示例(您可以从here下载文件):

b   q   a   i   m   l   r
j   n   o   r   o
e   i   k   u   i   s

在上面的示例中,字母o在第二行中两次被提及,字母i在第三行中被两次提及。我想考虑文本文件字母行的单个副本。

这是obj的示例:obj = np.asarray(['a', 'e', 'i', 'o', 'u'])

我想将obj与文本文件的行和来自obj的元素的表单簇进行比较

这就是我想要的方式。对应于文本文件的每一行,我想要一个表示集群的列表(在上面的示例中,由于文本文件具有三行,因此将具有三个集群)。对于obj的每个给定元素,我想找到存在该元素的文本文件行。然后,我想obj的元素的索引分配给与最大长度的行相对应的簇(行的长度由所有具有单个字母副本的行决定)。

下面是我为此任务编写的python代码

import pandas as pd
import numpy as np

data = pd.read_csv('file.txt', sep=r'\t+', header=None, engine='python').values[:,:].astype('<U1000')
obj = np.asarray(['a', 'e', 'i', 'o', 'u'])

for i in range(data.shape[0]):
    globals()['data_row' + str(i).zfill(3)] = []
    globals()['clust' + str(i).zfill(3)] = []
    for j in range(len(obj)):
        if obj[j] in set(data[i, :]): globals()['data_row' + str(i).zfill(3)] += [j]

for i in range(len(obj)):
    globals()['obj_lst' + str(i).zfill(3)] = [0]*data.shape[0]  

    for j in range(data.shape[0]):
        if i in globals()['data_row' + str(j).zfill(3)]:
            globals()['obj_lst' + str(i).zfill(3)][j] = len(globals()['data_row' + str(j).zfill(3)])

    indx_max = globals()['obj_lst' + str(i).zfill(3)].index( max(globals()['obj_lst' + str(i).zfill(3)]) )
    globals()['clust' + str(indx_max).zfill(3)] += [i]  

for i in range(data.shape[0]): print globals()['clust' + str(i).zfill(3)]

>> [0]
>> [3]
>> [1, 2, 4]

上面的代码给了我正确的答案。但是,在我的实际工作中,文本文件具有成千上万的行,而 numpy数组具有成千上万的元素。并且,以上给出的代码不是很快。因此,我想知道是否有更好(更快)的方法来实现上述功能和目标(使用python)。

1 个答案:

答案 0 :(得分:1)

您可以在merge上的stack(以熊猫为单位)之后使用data,然后使用groupbynunique使用idxmax得到想要的东西

#keep data in pandas
data = pd.read_csv('file.txt', sep=r'\t+', header=None, engine='python')
obj = np.asarray(['a', 'e', 'i', 'o', 'u'])

#merge to keep only the letters from obj
df = (data.stack().reset_index(0,name='l')
          .merge(pd.DataFrame({'l':obj})).set_index('level_0'))

#get the len of unique element of obj in each row of data
# and use transform to keep this lenght along each row of df
df['len'] = df.groupby('level_0').transform('nunique')

#get the result you want in a series
res = (pd.DataFrame({'data_row':df.groupby('l')['len'].idxmax().values})
         .groupby('data_row').apply(lambda x: list(x.index)))
print(res)

data_row
0          [0]
1          [3]
2    [1, 2, 4]
dtype: object

res包含簇,其索引为原始data中的行