在Python中将不同长度的多个列表写入相同的行

时间:2017-12-13 18:19:11

标签: python xml csv parsing beautifulsoup

我有一些大数据文件需要解析。每个文件都重复某些标记,但只有一个标记重复。例如,每个文件都有namedate的父级,这些父级只在每个数据块中显示一次但有许多子项,例如patent citationsnon-patent citations和{{1} }。

因此,我通过查找这三个子节点的所有案例进行解析,并将每个文件中父节点的每次迭代存储到各个列表中。问题是这些孩子的长度总是不同,我想把它们全部写在CSV文件的一行上。

例如,对于我的列表输入的文件中的一次迭代,就像:

classification

我希望写入CSV文件的输出看起来像:

Name = [Jon]
Date = [1985]
Patcit = [1, 2, 3]
Npatcit = [4, 5, 6, 7, 8]
Class = [9, 10]

我的代码贯穿以下文件:

Name  Date  Patcit  Npatcit  Class
Jon   1985     1       4       9
               2       5       10
               3       6      
                       7
                       8
(Repeat next name and date iteration on the next row)

然后,例如,仅为 Patcit 列表编写内容将类似于:

from bs4 import BeautifulSoup

soup = BeautifulSoup(data, "lxml")
grant = soup.findAll("grant")

  for info in grant:
    cite = soup.findAll("us-citation")
    names = soup.findAll("name")

    Patcit = []
    Npatcit = []
    Class = []

    for item2 in cite:
      for items in item2.findAll("patcit"):
        pat = items.find("patent-citation-title")
        Patcit.append(pat)

.
.
.
.
The same for the other 2 lists

使用for inv_name in zip(names): for j in range(int(len(Patcit))): datapatcit = Patcit[j] writer.writerow[(inv_name).text, datapatcit]

所以这就是问题所在。我无法找到一个很好的方法来获得输出我想要的方式。

2 个答案:

答案 0 :(得分:2)

在每个输入中建立最长列表后,您可以使用空字符串填充其他列表。

Name = ["Jon"]
Date = [1985]
Patcit = [1, 2, 3]
Npatcit = [4, 5, 6, 7, 8]
Class = [9, 10]
data = {"Name":Name, "Date":Date, "Patcit":Patcit, "Npatcit":Npatcit, "Class":Class}

max_n = max([len(x) for x in data.values()])
for field in data:
    data[field] += [''] * (max_n - len(data[field]))

data
{'Class': [9, 10, '', '', ''],
 'Date': [1985, '', '', '', ''],
 'Name': ['Jon', '', '', '', ''],
 'Npatcit': [4, 5, 6, 7, 8],
 'Patcit': [1, 2, 3, '', '']}

然后使用您首选的方法写入CSV。我选择熊猫:

import pandas as pd
df = pd.DataFrame(data)
df.to_csv("output.csv", index=False)

df
  Class  Date Name  Npatcit Patcit
0     9  1985  Jon        4      1
1    10                   5      2
2                         6      3
3                         7       
4                         8       

<强>更新
如果您需要在多次迭代中执行此操作(例如,在示例用例中info中的多个grant个案例),则可以使用concat
我还建议将填充操作移动到一个函数中,如下所示:

import pandas as pd

def pad(data):
    max_n = max([len(x) for x in data.values()])
    for field in data:
        data[field] += [''] * (max_n - len(data[field]))
    return data

# CSV 1
Name = ["Jon"]
Date = [1985]
Patcit = [1, 2, 3]
Npatcit = [4, 5, 6, 7, 8]
Class = [9, 10]
data = {"Name":Name, "Date":Date, "Patcit":Patcit, "Npatcit":Npatcit, "Class":Class}
df = pd.DataFrame(pad(data))

# CSV 2
Name = ["Sally"]
Date = [19995]
Patcit = [9,8,7]
Npatcit = [1,3,5]
Class = [4, 10,15]
data = {"Name":Name, "Date":Date, "Patcit":Patcit, "Npatcit":Npatcit, "Class":Class}
df = pd.concat([df, pd.DataFrame(pad(data))])

df
  Class   Date   Name  Npatcit Patcit
0     9   1985    Jon        4      1
1    10                      5      2
2                            6      3
3                            7       
4                            8       
0     4  19995  Sally        1      9
1    10                      3      8
2    15                      5      7

答案 1 :(得分:0)

在实现pandas之后,我在循环的开头添加了一个简单的计数器,并在主循环中使用if语句运行@andrew_reece给出的函数pad(data),如下所示:

counter == 0
main for loop in grant:
  lists = []
  .
  .
  .
  def pad(data):
    .
    .
    .
    if counter == 0:
      df = pd.DataFrame(pad(data))
    else:
      df = pd.concat([df, pd.DataFrame(pad(data))])

    counter = counter + 1

我们也可以使用TrueFalse语句代替'count'。这可以确保第一个解析能够“触发”第一个连接。

再次感谢@andrew_reece的帮助。