我有一个文本文件, 格式如下:
1: frack 0.733, shale 0.700,
10: space 0.645, station 0.327, nasa 0.258,
4: celebr 0.262, bahar 0.345
我需要隐藏此文本的数据框架具有以下格式:
Id Term weight
1 frack 0.733
1 shale 0.700
10 space 0.645
10 station 0.327
10 nasa 0.258
4 celebr 0.262
4 bahar 0.345
我怎么能做到呢?
下面是一种使用该文件进行分析的优化方法 re
, 首先采用 id, 然后分析数据元组。 这利用了文件对象是可迭性的这一事实。 当您循环访问打开的文件时, 您将以字符串的方式获取各个行, 从中可以提取有意义的数据元素。
import re
import pandas as pd
SEP_RE = re.compile(r":\s+")
DATA_RE = re.compile(r"(?P[a-z]+)\s+(?P\d+\.\d+)", re.I)
def parse(filepath: str):
def _parse(filepath):
with open(filepath) as f:
for line in f:
id, rest = SEP_RE.split(line, maxsplit=1)
for match in DATA_RE.finditer(rest):
yield [int(id), match["term"], float(match["weight"])]
return list(_parse(filepath))
例子:
>>> df = pd.DataFrame(parse("/Users/bradsolomon/Downloads/doc.txt"),
... columns=["Id", "Term", "weight"])
>>>
>>> df
Id Term weight
0 1 frack 0.733
1 1 shale 0.700
2 10 space 0.645
3 10 station 0.327
4 10 nasa 0.258
5 4 celebr 0.262
6 4 bahar 0.345
>>> df.dtypes
Id int64
Term object
weight float64
dtype: object
SEP_RE
查找初始分隔符: 文本 :
后跟一个或多个空格。 maxsplit=1
一旦找到第一个拆分, 它就会停止。 当然, 这假定您的数据是严格的格式化的: 整个数据集的格式始终遵循您的问题中列出的示例格式。
之后, DATA_RE.finditer()
处理每个 (术语、重量) 对. rest
字符串 rest
本身将看起来像 frack 0.733, shale 0.700,
。 .finditer()
为您提供多个 match
对象, 您可以在其中 ["key"]
使用表示法从给定的命名捕获组访问元素, 例如 (?P[a-z]+)
。
可视化的一种简单方法是将 line
文件中的示例用作字符串:
>>> line = "1: frack 0.733, shale 0.700,\n"
>>> SEP_RE.split(line, maxsplit=1)
['1', 'frack 0.733, shale 0.700,\n']
现在, 您有了初始 ID 和组件的其余部分, 您可以将其解压缩到两个标识符中。
>>> id, rest = SEP_RE.split(line, maxsplit=1)
>>> it = DATA_RE.finditer(rest)
>>> match = next(it)
>>> match
>>> match["term"]
'frack'
>>> match["weight"]
'0.733'
将其可视化的更好方法是 pdb
。 如果你敢;) 就试试吧
这是需要特定类型的解决方案的问题之一, 如果您放松对数据格式的限制, 这些解决方案可能无法很好地概括。
例如, 它假定每个 Term
字母只能使用大写或小写 ascii 字母, 而不能使用其他字母。 如果您有其他 Unicode 字符作为标识符, 则需要查找其他 re
字符 \w
, 例如。
如果将输入按摩到适当的格式, 则可以使用 DataFrame 构造函数。这里有一个方法:
import pandas as pd
from itertools import chain
text="""1: frack 0.733, shale 0.700,
10: space 0.645, station 0.327, nasa 0.258,
4: celebr 0.262, bahar 0.345 """
df = pd.DataFrame(
list(
chain.from_iterable(
map(lambda z: (y[0], *z.strip().split()), y[1].split(",")) for y in
map(lambda x: x.strip(" ,").split(":"), text.splitlines())
)
),
columns=["Id", "Term", "weight"]
)
print(df)
# Id Term weight
#0 4 frack 0.733
#1 4 shale 0.700
#2 4 space 0.645
#3 4 station 0.327
#4 4 nasa 0.258
#5 4 celebr 0.262
#6 4 bahar 0.345
解释
我想你已经把你的文件读进了字符串 text
。你想做的第一件事是在拆分之前剥离前导行/尾随逗号和空格:
print(list(map(lambda x: x.strip(" ,").split(":"), text.splitlines())))
#[['1', ' frack 0.733, shale 0.700'],
# ['10', ' space 0.645, station 0.327, nasa 0.258'],
# ['4', ' celebr 0.262, bahar 0.345']]
下一步是在逗号上拆分以分隔值, 并 Id
为每组值分配:
print(
[
list(map(lambda z: (y[0], *z.strip().split()), y[1].split(","))) for y in
map(lambda x: x.strip(" ,").split(":"), text.splitlines())
]
)
#[[('1', 'frack', '0.733'), ('1', 'shale', '0.700')],
# [('10', 'space', '0.645'),
# ('10', 'station', '0.327'),
# ('10', 'nasa', '0.258')],
# [('4', 'celebr', '0.262'), ('4', 'bahar', '0.345')]]
最后, 我们使用 itertools.chain.from_iterable
扁平此输出, 然后可以将其直接传递给 DataFrame 构造函数。
注意: *
元组解包是巨蟒 3 功能。
假设您的数据 ( csv
文件) 看起来像给定的:
df = pd.read_csv('untitled.txt', sep=': ', header=None)
df.set_index(0, inplace=True)
# split the `,`
df = df[1].str.strip().str.split(',', expand=True)
# 0 1 2 3
#-- ------------ ------------- ---------- ---
# 1 frack 0.733 shale 0.700
#10 space 0.645 station 0.327 nasa 0.258
# 4 celebr 0.262 bahar 0.345
# stack and drop empty
df = df.stack()
df = df[~df.eq('')]
# split ' '
df = df.str.strip().str.split(' ', expand=True)
# edit to give final expected output:
# rename index and columns for reset_index
df.index.names = ['Id', 'to_drop']
df.columns = ['Term', 'weight']
# final df
final_df = df.reset_index().drop('to_drop', axis=1)
只是为了把我的两分钱: 你可以给自己写一个解析器, 并把结果输入: pandas
import pandas as pd
from parsimonious.grammar import Grammar
from parsimonious.nodes import NodeVisitor
file = """
1: frack 0.733, shale 0.700,
10: space 0.645, station 0.327, nasa 0.258,
4: celebr 0.262, bahar 0.345
"""
grammar = Grammar(
r"""
expr = (garbage / line)+
line = id colon pair*
pair = term ws weight sep? ws?
garbage = ws+
id = ~"\d+"
colon = ws? ":" ws?
sep = ws? "," ws?
term = ~"[a-zA-Z]+"
weight = ~"\d+(?:\.\d+)?"
ws = ~"\s+"
"""
)
tree = grammar.parse(file)
class PandasVisitor(NodeVisitor):
def generic_visit(self, node, visited_children):
return visited_children or node
def visit_pair(self, node, visited_children):
term, _, weight, *_ = visited_children
return (term.text, weight.text)
def visit_line(self, node, visited_children):
id, _, pairs = visited_children
return [(id.text, *pair) for pair in pairs]
def visit_garbage(self, node, visited_children):
return None
def visit_expr(self, node, visited_children):
return [item
for lst in visited_children
for sublst in lst if sublst
for item in sublst]
pv = PandasVisitor()
out = pv.visit(tree)
df = pd.DataFrame(out, columns=["Id", "Term", "weight"])
print(df)
这就产生了
Id Term weight
0 1 frack 0.733
1 1 shale 0.700
2 10 space 0.645
3 10 station 0.327
4 10 nasa 0.258
5 4 celebr 0.262
6 4 bahar 0.345
在这里, 我们正在构建一个语法与可能的信息: 行或空白。line
它是由一个 id (例如 1
), 后面是冒号 :
()、空格和 pair
term
weight
s, 然后是一个 sep
器。
之后, 我们需要一个 NodeVisitor
类, 以实际做某事, 用检索到的。
下面是你的问题的另一个看法。创建一个列表, 其中将包含每个 id 和术语的列表。然后生成数据框。
import pandas as pd
file=r"give_your_path".replace('\\', '/')
my_list_of_lists=[]#creating an empty list which will contain lists of [Id Term Weight]
with open(file,"r+") as f:
for line in f.readlines():#looping every line
my_id=[line.split(":")[0]]#storing the Id in order to use it in every term
for term in [s.strip().split(" ") for s in line[line.find(":")+1:].split(",")[:-1]]:
my_list_of_lists.append(my_id+term)
df=pd.DataFrame.from_records(my_list_of_lists)#turning the lists to dataframe
df.columns=["Id","Term","weight"]#giving columns their names
它是可以只使用完全熊猫:
df = pd.read_csv(StringIO(u"""1: frack 0.733, shale 0.700,
10: space 0.645, station 0.327, nasa 0.258,
4: celebr 0.262, bahar 0.345 """), sep=":", header=None)
#df:
0 1
0 1 frack 0.733, shale 0.700,
1 10 space 0.645, station 0.327, nasa 0.258,
2 4 celebr 0.262, bahar 0.345
将列 1
转换为列表, 然后展开:
df[1] = df[1].str.split(",", expand=False)
dfs = []
for idx, rows in df.iterrows():
print(rows)
dfslice = pd.DataFrame({"Id": [rows[0]]*len(rows[1]), "terms": rows[1]})
dfs.append(dfslice)
newdf = pd.concat(dfs, ignore_index=True)
# this creates newdf:
Id terms
0 1 frack 0.733
1 1 shale 0.700
2 1
3 10 space 0.645
4 10 station 0.327
5 10 nasa 0.258
6 10
7 4 celebr 0.262
8 4 bahar 0.345
现在, 我们需要将最后一行拆分并删除空:
newdf["terms"] = newdf["terms"].str.strip()
newdf = newdf.join(newdf["terms"].str.split(" ", expand=True))
newdf.columns = ["Id", "terms", "Term", "Weights"]
newdf = newdf.drop("terms", axis=1).dropna()
产生的新 df:
Id Term Weights
0 1 frack 0.733
1 1 shale 0.700
3 10 space 0.645
4 10 station 0.327
5 10 nasa 0.258
7 4 celebr 0.262
8 4 bahar 0.345
我可以假设在 "期限" 之前只有 1 个空格吗?
df=pd.DataFrame(columns=['ID','Term','Weight'])
with open('C:/random/d1','r') as readObject:
for line in readObject:
line=line.rstrip('\n')
tempList1=line.split(':')
tempList2=tempList1[1]
tempList2=tempList2.rstrip(',')
tempList2=tempList2.split(',')
for item in tempList2:
e=item.split(' ')
tempRow=[tempList1[0], e[0],e[1]]
df.loc[len(df)]=tempRow
print(df)
您可以逐行读取。
然后, 您可以将 ":" 用于索引, ",", "值" 分开
3.
with open('path/filename.txt','r') as filename:
content = filename.readlines()
这将为您提供以下结果:
content =[
['1','frack 0.733, shale 0.700,'],
['10', 'space 0.645, station 0.327, nasa 0.258,'],
['4','celebr 0.262, bahar 0.345 ']]