डेटाफ़्रेम में बार-बार "कुंजी = मान" जोड़े की फ़ाइल पढ़ें


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

जोड़ें df = pd.read_table(file, header=None), निम्न पंक्ति बनाएं new = df[0].str.split("=", n=1, expand=True), और "अच्छा कोड" के संदर्भ में यह मेरा पसंदीदा उत्तर होगा।
MrFuppes

@Mruppuppes मैंने अपना उत्तर संपादित किया। संकेत के लिए धन्यवाद।
लुइगीगी

1
+1 %timeit;; हालाँकि, मैं सिर्फ अपने जवाब के खिलाफ दौड़ता रहा और यह सोचता रहा कि शुद्ध-पांडा समाधान कितना धीमा है। यह मेरी मशीन पर x7 धीमी के बारे में था (एक बहुत छोटी इनपुट txt फ़ाइल के लिए)! सुविधा के साथ ओवरहेड आता है, ओवरहेड के साथ (ज्यादातर समय) प्रदर्शन में नुकसान आता है ...
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

आप जो भी कर सकते हैं, वह अपने टेक्स्टफाइल fileको 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। उदाहरण के लिए, csv फ़ाइल के मामले में pandasफ़ंक्शन read_csv के साथ उदाहरण के लिए इसे पढ़ना अधिक आसान होगा ।


0

आप पायथन के शब्दकोश मॉड्यूल और पंडों का उपयोग करके उस आउटपुट को उत्पन्न कर सकते हैं ।

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)

यह दृष्टिकोण सबसे कुशल नहीं हो सकता है लेकिन यह पंडों के किसी भी उन्नत कार्य का उपयोग नहीं करता है। आशा है ये मदद करेगा।

उत्पादन:

    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
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.