我有一个带有字母(制表符分隔)的文本文件,以及一个带有几个字母(单行)的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)。
答案 0 :(得分:1)
您可以在merge
上的stack
(以熊猫为单位)之后使用data
,然后使用groupby
或nunique
使用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
中的行