python - قراءة ملف أزواج "المفتاح=القيمة" المتكررة في DataFrame




pandas (5)

لدي ملف 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   |
+-------+-----+

ليس حقا ما أبحث عنه.


IMHO ، كل الإجابات الحالية تبدو معقدة للغاية. ما أود القيام به ، هو استخدام '=' كمعلمة sep لـ read_csv لقراءة عمودين ، ثم pivot DataFrame الذي تم الحصول عليه:

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

أعلم أن لديك إجابات كافية ، ولكن فيما يلي طريقة أخرى للقيام بذلك باستخدام القاموس:

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

فقط للحصول على منظور آخر.


ما يمكنك القيام به أيضًا هو قراءة file textfile الخاص بك في كتل 3 ، وإنشاء قائمة متداخلة ، ووضعها في إطار بيانات:

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 . هذا سيجعل قراءته أسهل بكثير ، على سبيل المثال مع وظيفة pandas read_csv في حالة وجود ملف بتنسيق csv.


يفترض هذا الحل أن تنسيق النص كما وصفته ، ولكن يمكنك تعديله لاستخدام كلمة مختلفة للدلالة على بداية السطر الجديد. هنا ، نفترض أن سطرًا جديدًا يبدأ بحقل 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.

يمكنك استخدام الباندا لقراءة الملف ومعالجة البيانات. يمكنك استخدام هذا:

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




pandas