熊猫数据汇总

时间:2020-07-06 17:30:04

标签: python-3.x summarization

我有一个模糊数据,如下所示。请注意,第一项具有重复的名称(考虑这一点很重要)。

('Alex', ['String1', 'String34'])
('Piper', ['String5', 'String64', 'String12'])
('Nicky', ['String3', 'String21', 'String42', 'String51'])
('Linda', ['String14'])
('Suzzane', ['String11', 'String36', 'String16'])
('Alex', ['String64', 'String34', 'String12', 'String5'])
('Linda', ['String3', 'String77'])
('Piper', ['String41', 'String64', 'String11', 'String34'])
('Suzzane', ['String12'])
('Nicky', ['String11',  'String51'])
('Alex', ['String77', 'String64', 'String3', 'String5'])
('Linda', ['String51'])
('Nicky', ['String77', 'String12', 'String34'])
('Suzzane', ['String51', 'String3'])
('Piper', ['String11', 'String64', 'String5'])

如果以上数据位于一个名为“ output.txt”的文件中,那么如何导入它并汇总数据,如下所示?

[仅保留唯一的名称,并且对于每个主要名称,将从存在的所有重复项中填充唯一的字符串]

('Alex', ['String1', 'String34', 'String64', 'String12', 'String5', 'String77', 'String3'])
('Piper', ['String5', 'String64', 'String12', 'String11', 'String41', 'String34'])
('Nicky', ['String3', 'String21', 'String42', 'String51', 'String11', 'String77', 'String12', 'String34'])
('Linda', ['String14', 'String3', 'String77', 'String51'])
('Suzzane', ['String11', 'String36', 'String16', 'String12', 'String51', 'String3'])

4 个答案:

答案 0 :(得分:3)

您可以将数据加载到熊猫dataframe中:

import pandas as pd

df = pd.DataFrame(data=[('Alex', ['String1', 'String34']),
('Alex', ['String64', 'String34', 'String12', 'String5']),
('Nicky', ['String11',  'String51']),
('Nicky', ['String77', 'String12', 'String34'])])
df = df.rename(columns={0:'name', 1:'strings'})

然后创建一个function来串联熊猫列上的列表:

def concatenate(strings):
   strings_agg = []
    for string in strings:
        strings_agg.extend(string)
    return strings_agg

最后将功能apply列至该列:

df.groupby('name').apply(lambda x: concatenate(x['strings'])).to_frame()

答案 1 :(得分:3)

我同意pandas是一个 great 库,但是使用普通的python内置软件包 1 可以很容易地完成这种事情。您可以简单地将python defaultdict与集合一起使用,并使用正则表达式finditer进行解析。

1 特别有意义,因为您的输入或输出都不属于任何熊猫数据类型(pd.Series,pd.DataFrame等)或甚至是标准的.csv /表格格式。

代码

from collections import defaultdict
import re

dataset = defaultdict(set)

with open('output.txt') as f:
    for line in f:
        itr = re.finditer("'(\S+?)'", line)
        name = next(itr).groups()[0]
        strings = {x.groups()[0] for x in itr}
        dataset[name] |= strings

with open('results.txt', 'w') as f:
    for name, strings in dataset.items():
        print(f"('{name}', {list(strings)})", file=f)

示例输出

('Alex', ['String1', 'String5', 'String77', 'String64', 'String34', 'String12', 'String3'])
('Piper', ['String5', 'String11', 'String64', 'String34', 'String12', 'String41'])
('Nicky', ['String21', 'String77', 'String34', 'String11', 'String51', 'String3', 'String12', 'String42'])
('Linda', ['String77', 'String14', 'String51', 'String3'])
('Suzzane', ['String11', 'String36', 'String12', 'String16', 'String51', 'String3'])

解释代码的工作原理

  • 逐行读取。我们可以使用正则表达式来捕获两个单引号(\S)之间非空白(')的内容。因此,正则表达式模式为'(\S+?)'。加号+表示匹配一个或多个字符,而?则使搜索变得非贪婪(匹配尽可能少的字符),因此我们将解析所有单独的字符串,而不仅仅是所有字符串该行中的内容。
  • re.finditer用于匹配具有相同模式的多个组。在这种情况下,将使用它代替re.findall,因为re.findall创建列表,而re.finditer创建 iterator 。 (小的优化:因为根本不需要列表,所以不创建列表)
  • 然后,我们通过在name上调用next()来捕获itr。它从迭代器返回第一个元素。
  • 然后,调用groups()并从返回的值中获取第一项。这就是访问模式中带括号(())捕获的组的方式。
  • 然后,对于迭代器itr的其余部分,我们只有要从中创建python sets的字符串,这些字符串会隔离唯一的元素。显示的语法是 set comprehension
  • 在同一行上,我们将结果集保存到defaultdictdataset变量中。 defaultdicts很不错,因为当访问不存在的项目时,它会自动创建该类型的条目。我们使用defaultdict(set)来将set作为默认类型。操作d[key] |= vald[key] = d[key] | val相同,|创建的集合是新集合的 union ,而我们可能已经在其中dataset
  • 最后一部分只是将输出逐行写入results.txt。将strings强制转换为列表是可选的,但可以使输出类似于问题中的内容。

答案 2 :(得分:1)

import ast
import csv
import pandas as pd

#load data from txt file, doesnt has to be csv, can be a txt file!
df = pd.read_csv(r"D:\test\output.txt", sep="/n", header=None, names=["data"], engine='python')

#convert text data to tupels and list
df["data"] = df["data"].map(lambda x: ast.literal_eval(x))
#extract surename
df["surename"] = df["data"].map(lambda x: x[0])
#extract list of strings
df["strings"] = df["data"].map(lambda x: x[1])
#create 1 row for each string in the list of strings
df = df.explode("strings")
#remove duplicate entries
df = df.drop_duplicates(subset=["surename", "strings"], keep="first")
#group the data by surename to get a list of unique strings (unique because we removed duplicates, order will be kept)
df_result = df.groupby(["surename"]).aggregate({"strings":list}).reset_index()
#combine both th extractd surename and the modified list of strings again
df_result["result"] = df_result.apply(lambda x: (x["surename"], x["strings"]), axis=1)

#output the data to a file of your choice
df_result[["result"]].to_csv(r"D:\test\result.txt",index=False, header=None, quoting=csv.QUOTE_NONE, escapechar = '')

答案 3 :(得分:1)

{{1}}