반복 된 "key = value"쌍의 파일을 DataFrame으로 읽습니다.


11

이 형식의 데이터가있는 txt 파일이 있습니다. 처음 3 줄은 계속 반복됩니다.

name=1
grade=A
class=B
name=2
grade=D
class=A

예를 들어 데이터를 테이블 형식으로 출력하고 싶습니다.

name | grade | class
1    | A     | B
2    | D     | A

헤더를 설정하고 데이터를 반복하는 데 어려움을 겪고 있습니다. 지금까지 시도한 것은 다음과 같습니다.

def myfile(filename):
    with open(file1) as f:
        for line in f:
            yield line.strip().split('=',1)

def pprint_df(dframe):
    print(tabulate(dframe, headers="keys", tablefmt="psql", showindex=False,))

#f = pd.DataFrame(myfile('file1')
df = pd.DataFrame(myfile('file1'))
pprint_df(df)

그 결과는

+-------+-----+
| 0     | 1   |
|-------+-----|
| name  | 1   |
| grade | A   |
| class | B   |
| name  | 2   |
| grade | D   |
| class | A   |
+-------+-----+

내가 찾고있는 것이 아닙니다.

답변:


2

이 솔루션에서는 텍스트 형식이 설명 된대로 가정하지만 다른 단어를 사용하여 새 줄의 시작을 나타내도록 텍스트 형식을 수정할 수 있습니다. 여기서는 새로운 줄이 name필드로 시작한다고 가정 합니다. myfile()아래 기능을 수정 했습니다. 아이디어가 있기를 바랍니다. :)

def myfile(filename):
    d_list = []
    with open(filename) as f:
        d_line = {}
        for line in f:
            split_line = line.rstrip("\n").split('=')  # Strip \n characters and split field and value.
            if (split_line[0] == 'name'):
                if d_line:
                    d_list.append(d_line)  # Append if there is previous line in d_line.
                d_line = {split_line[0]: split_line[1]}  # Start a new dictionary to collect the next lines.
            else:
                d_line[split_line[0]] = split_line[1]  # Add the other 2 fields to the dictionary.
        d_list.append(d_line) # Append the last line.
    return pd.DataFrame(d_list)  # Turn the list of dictionaries into a DataFrame.

10

팬더를 사용하여 파일을 읽고 데이터를 처리 할 수 ​​있습니다. 이것을 사용할 수 있습니다 :

import pandas as pd
df = pd.read_table(r'file.txt', header=None)
new = df[0].str.split("=", n=1, expand=True)
new['index'] = new.groupby(new[0])[0].cumcount()
new = new.pivot(index='index', columns=0, values=1)

new 출력 :

0     class grade name
index                 
0         B     A    1
1         A     D    2

add df = pd.read_table(file, header=None), 다음 줄을 만드십시오. new = df[0].str.split("=", n=1, expand=True)이것은 "nice code"와 관련하여 제가 가장 좋아하는 답변입니다.
MrFuppes

@MrFuppes 내 답변을 편집했습니다. 힌트 주셔서 감사합니다.
luigigi

1
그러나 +1 ;-), 나는 방금 %timeit내 대답에 반대하여 순수 팬더 솔루션이 얼마나 느린 지 놀라게되었습니다. 내 컴퓨터에서 (매우 작은 입력 txt 파일의 경우) 약 7 배 느 렸습니다! 편의성과 오버 헤드가 발생하고 오버 헤드 (대부분의 경우) 성능이 저하됩니다.
MrFuppes

7

충분한 답변이 있다는 것을 알고 있지만 사전을 사용하여 다른 방법을 사용하십시오.

import pandas as pd
from collections import defaultdict
d = defaultdict(list)

with open("text_file.txt") as f:
    for line in f:
        (key, val) = line.split('=')
        d[key].append(val.replace('\n', ''))

df = pd.DataFrame(d)
print(df)

출력은 다음과 같습니다.

name grade class
0    1     A     B
1    2     D     A

다른 관점을 얻으려면.


3

출력을 얻었을 때 이것이 문제를 처리하는 방법입니다.

먼저 열의 반복성을 기반으로 고유 색인을 작성하십시오.

df['idx'] = df.groupby(df['0'])['0'].cumcount() + 1
print(df)
        0  1  idx
0   name  1      1
1  grade  A      1
2  class  B      1
3   name  2      2
4  grade  D      2
5  class  A      2

그런 다음 crosstab함수를 사용하여 데이터 프레임을 피벗하는 데 사용합니다

df1 = pd.crosstab(df['idx'],df['0'],values=df['1'],aggfunc='first').reset_index(drop=True)
print(df1[['name','grade','class']])
0 name grade class
0    1     A     B
1    2     D     A

3

당신이 할 수있는 일은 file3 블록으로 텍스트 파일 을 읽고 중첩 된 목록을 작성하고 데이터 프레임에 넣는 것입니다.

from itertools import zip_longest
import pandas as pd

# taken from https://docs.python.org/3.7/library/itertools.html:
def grouper(iterable, n, fillvalue=None):
    "Collect data into fixed-length chunks or blocks"
    # grouper('ABCDEFG', 3, 'x') --> ABC DEF Gxx"
    args = [iter(iterable)] * n
    return zip_longest(*args, fillvalue=fillvalue)

data = [['name', 'grade', 'class']]
with open(file, 'r') as fobj:
    blocks = grouper(fobj, 3)
    for b in blocks:
        data.append([i.split('=')[-1].strip() for i in b])

df = pd.DataFrame(data[1:], columns=data[0])  

df 직접 될 것입니다

  name grade class
0    1     A     B
1    2     D     A

참고 # 1 : 이것이 순수한 pandas솔루션 보다 더 많은 코드 줄을 만들지 만 내 경험상 더 적은 pandas기능을 사용 하므로 오버 헤드 가 적기 때문에 더 효율적일 것 입니다.

참고 # 2 : 일반적으로 입력 데이터를 다른 형식 (예 : json또는) 으로 저장하는 것이 좋습니다 csv. 예를 들어 csv 파일의 경우 read_csvpandas 함수 를 사용하면 훨씬 쉽게 읽을 수 있습니다.


0

Python의 Dictionary 모듈 과 Pandas를 사용하여 해당 출력을 생성 할 수 있습니다 .

import pandas as pd
from collections import defaultdict

text = '''name=1
          grade=A
          class=B
          name=2
          grade=D
          class=A'''
text = text.split()

new_dict = defaultdict(list) 
for i in text:
    temp = i.split('=')
    new_dict[temp[0]].append(temp[1])

df = pd.DataFrame(new_dict)

이 방법은 가장 효율적인 방법은 아니지만 Pandas의 고급 기능을 사용하지 않습니다. 도움이 되길 바랍니다.

출력 :

    name    grade   class
0      1        A       B
1      2        D       A

0

IMHO, 모든 현재 답변이 너무 복잡해 보입니다. 내가 할 일은 2 열을 읽은 다음 얻은 DataFrame 을 읽는 매개 변수 로 사용 '='하는 것입니다.seppd.read_csvpivot

import pandas as pd

df = pd.read_csv('myfile', sep='=', header=None)
#        0  1
# 0   name  1
# 1  grade  A
# 2  class  B
# 3   name  2
# 4  grade  D
# 5  class  A

df = df.pivot(index=df.index // len(df[0].unique()), columns=0)
#       1           
# 0 class grade name
# 0     B     A    1
# 1     A     D    2

결과에서 해당 다중 수준 열 인덱스를 원하지 않으면 다음을 통해 제거 할 수 있습니다.

df.columns = df.columns.get_level_values(1)
# 0 class grade name
# 0     B     A    1
# 1     A     D    2
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.