计算每行中所有可能的 2-gram
count all possible 2-grams in each row
假设我有一个这样的 csv 文件(实际上我有超过 100 多种不同的服务):
user_id, services
user_1, "s1,s2,s1,s4,s2,s3,s2"
user_2, "s2,s3,s2,s1,s4"
我想最终得到这个,如果可能的话主要使用python和pandas:
user_id, c12,c21,c13,c31,c14,c42,c23,c32,c14,c43,c34
user_1, 1,1,0,0,1,1,1,1,0,0,0
user_2, 0,1,0,0,0,0,1,1,1,0,1
其中 cij
= sequence si,sj for each user
的数量
理想情况下,我希望它不仅可用于 2 的序列,而且可用于 3 的序列
我在 SO 上找到的是 si sj 的总计数,但不是像这样的计数。我想我在某个时候需要一个枢轴 table,还有 n-gram 但我不知道如何将它们混合在一起:/
感谢您的帮助
重新创建您的数据(但已将服务列拆分为不同的列)
import pandas as pd
df = pd.DataFrame()
df['user_id'] = [1,2]
df['s1'] = [0, 1]
df['s2'] = [1, 1]
df['s3'] = [1,0]
然后我们可以合并:
cols = list(df)[1:]
for c1, c2 in itertools.permutations(c,2):
df[c1+c2] = df[c1] & df[c2]
通过将 2 改成 3,您可以添加 3-gram 而不是 n-gram。
编辑:
我现在更了解你的问题了。下面是一个适用于字符串的解决方案。首先我们创建一些数据:
import pandas as pd
df = pd.DataFrame([['user1',"s1,s2,s1,s4,s2,s3,s2"],['user2',"s2,s3,s2,s1,s4"]])
df.columns = ['userid','services']
对于 n-gram,我们使用了一个灵活的函数(正如您所指出的,您可能想要使用更高级别的 n-gram)
def find_ngrams(input_list, n):
return zip(*[input_list[i:] for i in range(n)])
我们计算出现次数并创建数据框:
results = {}
for idx, row in df.iterrows():
list_of_services = row['services'].split(',')
combinations = ['c_{}_{}'.format(c1,c2) for c1, c2 in find_ngrams(list_of_services, 2)]
results[row['userid']] = {k: 1 for k in combinations}
df2.from_dict(results).transpose()
对于你的玩具示例 returns:
c_s1_s2 c_s1_s4 c_s2_s1 c_s2_s3 c_s3_s2 c_s4_s2
user1 1.0 1.0 1.0 1.0 1.0 1.0
user2 NaN 1.0 1.0 1.0 1.0 NaN
只需使用 python 和 itertools
然后您就可以使用 itertools.pairwise
配方来完成此操作。
import itertools as it
def pairwise(iterable):
"s -> (s0,s1), (s1,s2), (s2, s3), ..."
a, b = it.tee(iterable)
next(b, None)
return zip(a, b)
假设您正在使用 csv.DictReader()
读取文件,那么:
>>> from collection import Counter
>>> services = ['s1', 's2', 's3', 's4'] # Total set of services
>>> combs = list(it.permutations(services, 2)) # All combinations of services
>>> counts = {row['user_id']: Counter(pairwise(row['services'].split(','))) for row in reader}
>>> [{user: {p: c[p] for p in combs} for user, c in counts.items()}]
[{'user_1': {('s1', 's2'): 1,
('s1', 's3'): 0,
('s1', 's4'): 1,
('s2', 's1'): 1,
('s2', 's3'): 1,
('s2', 's4'): 0,
('s3', 's1'): 0,
('s3', 's2'): 1,
('s3', 's4'): 0,
('s4', 's1'): 0,
('s4', 's2'): 1,
('s4', 's3'): 0},
'user_2': {('s1', 's2'): 0,
('s1', 's3'): 0,
('s1', 's4'): 1,
('s2', 's1'): 1,
('s2', 's3'): 1,
('s2', 's4'): 0,
('s3', 's1'): 0,
('s3', 's2'): 1,
('s3', 's4'): 0,
('s4', 's1'): 0,
('s4', 's2'): 0,
('s4', 's3'): 0}}]
假设我有一个这样的 csv 文件(实际上我有超过 100 多种不同的服务):
user_id, services
user_1, "s1,s2,s1,s4,s2,s3,s2"
user_2, "s2,s3,s2,s1,s4"
我想最终得到这个,如果可能的话主要使用python和pandas:
user_id, c12,c21,c13,c31,c14,c42,c23,c32,c14,c43,c34
user_1, 1,1,0,0,1,1,1,1,0,0,0
user_2, 0,1,0,0,0,0,1,1,1,0,1
其中 cij
= sequence si,sj for each user
理想情况下,我希望它不仅可用于 2 的序列,而且可用于 3 的序列
我在 SO 上找到的是 si sj 的总计数,但不是像这样的计数。我想我在某个时候需要一个枢轴 table,还有 n-gram 但我不知道如何将它们混合在一起:/
感谢您的帮助
重新创建您的数据(但已将服务列拆分为不同的列)
import pandas as pd
df = pd.DataFrame()
df['user_id'] = [1,2]
df['s1'] = [0, 1]
df['s2'] = [1, 1]
df['s3'] = [1,0]
然后我们可以合并:
cols = list(df)[1:]
for c1, c2 in itertools.permutations(c,2):
df[c1+c2] = df[c1] & df[c2]
通过将 2 改成 3,您可以添加 3-gram 而不是 n-gram。
编辑:
我现在更了解你的问题了。下面是一个适用于字符串的解决方案。首先我们创建一些数据:
import pandas as pd
df = pd.DataFrame([['user1',"s1,s2,s1,s4,s2,s3,s2"],['user2',"s2,s3,s2,s1,s4"]])
df.columns = ['userid','services']
对于 n-gram,我们使用了一个灵活的函数(正如您所指出的,您可能想要使用更高级别的 n-gram)
def find_ngrams(input_list, n):
return zip(*[input_list[i:] for i in range(n)])
我们计算出现次数并创建数据框:
results = {}
for idx, row in df.iterrows():
list_of_services = row['services'].split(',')
combinations = ['c_{}_{}'.format(c1,c2) for c1, c2 in find_ngrams(list_of_services, 2)]
results[row['userid']] = {k: 1 for k in combinations}
df2.from_dict(results).transpose()
对于你的玩具示例 returns:
c_s1_s2 c_s1_s4 c_s2_s1 c_s2_s3 c_s3_s2 c_s4_s2
user1 1.0 1.0 1.0 1.0 1.0 1.0
user2 NaN 1.0 1.0 1.0 1.0 NaN
只需使用 python 和 itertools
然后您就可以使用 itertools.pairwise
配方来完成此操作。
import itertools as it
def pairwise(iterable):
"s -> (s0,s1), (s1,s2), (s2, s3), ..."
a, b = it.tee(iterable)
next(b, None)
return zip(a, b)
假设您正在使用 csv.DictReader()
读取文件,那么:
>>> from collection import Counter
>>> services = ['s1', 's2', 's3', 's4'] # Total set of services
>>> combs = list(it.permutations(services, 2)) # All combinations of services
>>> counts = {row['user_id']: Counter(pairwise(row['services'].split(','))) for row in reader}
>>> [{user: {p: c[p] for p in combs} for user, c in counts.items()}]
[{'user_1': {('s1', 's2'): 1,
('s1', 's3'): 0,
('s1', 's4'): 1,
('s2', 's1'): 1,
('s2', 's3'): 1,
('s2', 's4'): 0,
('s3', 's1'): 0,
('s3', 's2'): 1,
('s3', 's4'): 0,
('s4', 's1'): 0,
('s4', 's2'): 1,
('s4', 's3'): 0},
'user_2': {('s1', 's2'): 0,
('s1', 's3'): 0,
('s1', 's4'): 1,
('s2', 's1'): 1,
('s2', 's3'): 1,
('s2', 's4'): 0,
('s3', 's1'): 0,
('s3', 's2'): 1,
('s3', 's4'): 0,
('s4', 's1'): 0,
('s4', 's2'): 0,
('s4', 's3'): 0}}]