迭代Pandas中的行组

时间:2015-05-27 05:32:02

标签: python loops pandas

我是大熊猫和蟒蛇的新手 - 感谢您提供的任何方向!

我有一个包含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。

3 个答案:

答案 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很有用。