我是大熊猫和蟒蛇的新手 - 感谢您提供的任何方向!
我有一个包含4列的csv文件。我试图将所有行中前三列相同的行组合在一起(列A行1 =列A行2,列B行1 =列B行2,依此类推)
我的数据如下:
phone_number state date description
1 9991112222 NJ 2015-05-14 Condo
2 9991112222 NJ 2015-05-14 Condo sales call
3 9991112222 NJ 2015-05-14 Apartment rental
4 6668885555 CA 2015-05-06 Apartment
5 6668885555 CA 2015-05-06 Apartment rental
6 4443337777 NJ 2015-05-14 condo
因此,在此数据中,第1,2和3行将位于一个组中,第4行和第5行将位于另一个组中。第6行不在1,2和3的组中,因为它具有不同的phone_number。
然后,对于每一行,我想使用Levenshtein距离将描述列中的字符串与该组中的每个其他描述进行比较,并保留描述相似的行。
第1行的“公寓”将与第2行的“公寓销售电话”和第3行的“公寓租赁”进行比较。它不会与第6行的“公寓”进行比较。
最后,目标是清除描述与同一组中的其他描述不够相似的行。换句话说,打印出描述至少与该组中的另一个(任何其他)描述有些相似的所有行。理想输出:
phone_number state date description
1 9991112222 NJ 2015-05-14 Condo
2 9991112222 NJ 2015-05-14 Condo sales call
4 6668885555 CA 2015-05-06 Apartment
5 6668885555 CA 2015-05-06 Apartment rental
第6行无法打印,因为它从不在组中。第3行不打印,因为“公寓租赁”与“公寓”或“公寓销售电话”不够相似
这是我到目前为止的代码。我不知道这是否是最好的方法。如果我到目前为止做得对,我无法弄清楚如何打印整行感兴趣的内容:
import Levenshtein
import itertools
import pandas as pd
test_data = pd.DataFrame.from_csv('phone_state_etc_test.csv', index_col=None)
for pn in test_data['phone_number']:
for dt in test_data['date']:
for st in test_data['state']:
for a, b in itertools.combinations(test_data[
(test_data['phone_number'] == pn) &
(test_data['state'] == st) &
(test_data['date'] == dt)
]
['description'], 2):
if Levenshtein.ratio(a,b) > 0.35:
print pn, "|", dt, "|", st, "|" #description
这会打印出一堆重复的这些行:
9991112222 | NJ | 2015-05-14 |
6668885555 | CA | 2015-05-06 |
但如果我在打印行的末尾添加说明,我会得到一个
SyntaxError: invalid syntax
有关如何打印整行的任何想法?无论是在pandas数据帧还是其他格式中,都无所谓 - 我只需要输出到csv。
答案 0 :(得分:2)
为什么不使用pandas.groupby
选项查找唯一群组(基于电话号码,状态和日期)。这样做可以让您分别处理所有Description
值并执行您想要做的任何事情。
例如,我将使用上述列进行分组,并获取此组中Description
列的唯一值 -
In [49]: df.groupby(['phone_number','state','date']).apply(lambda v: v['description'].unique())
Out[49]:
phone_number state date
4443337777 NJ 2015-05-14 [condo]
6668885555 CA 2015-05-06 [Apartment, Apartment-rental]
9991112222 NJ 2015-05-14 [Condo, Condo-sales-call, Apartment-rental]
dtype: object
您可以使用apply
中的任何功能。这里有更多示例 - http://pandas.pydata.org/pandas-docs/stable/groupby.html
答案 1 :(得分:1)
我不完全确定如何最好地对pandas
中的所有值对进行计算 - 这里我已经创建了一个矩阵,其描述为行和列(所以主要的对角线是矩阵将描述与自身进行比较),但它似乎并不完全是惯用的:
def find_similar_rows(group, threshold=0.35):
sim_matrix = pd.DataFrame(index=group['description'],
columns=group['description'])
for d1 in sim_matrix.index:
for d2 in sim_matrix.columns:
# Leave diagonal entries as nan
if d1 != d2:
sim_matrix.loc[d1, d2] = Levenshtein.ratio(d1, d2)
keep = sim_matrix.gt(threshold, axis='columns').any()
# A bit of possibly unnecessary mucking around with the index
# here, could probably be cleaned up
rows_to_keep = group.loc[keep[group['description']].tolist(), :]
return rows_to_keep
grouped = test_data.groupby('phone_number', group_keys=False)
grouped.apply(find_similar_rows)
Out[64]:
phone_number state date description
4 6668885555 CA 2015-05-06 Apartment
5 6668885555 CA 2015-05-06 Apartment rental
1 9991112222 NJ 2015-05-14 Condo
2 9991112222 NJ 2015-05-14 Condo sales call
答案 2 :(得分:0)
从提供的数据看,您希望保留描述中第一个单词与该组最常见的第一个单词匹配的行。 如果是这种情况,您可以这样做:
test_data['description_root'] = test_data.str.split().str[0]
# this adds a columns with the first word from the description column
grouped = test_data.groupby(['phone_number', 'state', 'date'])
most_frequent_root = grouped.description_root.transform(
lambda s: s.value_counts().idxmax())
# this is a series with the same index as the original df containing
# the most frequently occuring root for each group
test_data[test_data.description_root == most_frequent_root]
# this will give you the matching rows
您还可以在.describe
上致电grouped
,为每个群组提供一些其他信息。很抱歉,如果这不是主题,但我认为你可能会发现系列字符串方法(.str
)和groupby很有用。