পৃথক সারিগুলিতে স্প্লিট (বিস্ফোরিত) পান্ডাস ডেটা ফ্রেম স্ট্রিং এন্ট্রি


200

আমার একটি pandas dataframeরয়েছে যেখানে পাঠ্য স্ট্রিংয়ের একটি কলামে কমা-বিভাজিত মান রয়েছে। আমি প্রতিটি সিএসভি ক্ষেত্রকে বিভক্ত করতে চাইছি এবং প্রবেশ অনুসারে একটি নতুন সারি তৈরি করতে চাই (ধরে নিন যে সিএসভি পরিষ্কার আছে এবং কেবল ',' এ বিভক্ত হওয়া দরকার)। উদাহরণস্বরূপ, aহওয়া উচিত b:

In [7]: a
Out[7]: 
    var1  var2
0  a,b,c     1
1  d,e,f     2

In [8]: b
Out[8]: 
  var1  var2
0    a     1
1    b     1
2    c     1
3    d     2
4    e     2
5    f     2

এখনও অবধি, আমি বিভিন্ন সাধারণ ফাংশন চেষ্টা করেছি, তবে .applyপদ্ধতিটি কেবলমাত্র একটি অক্ষকে ব্যবহার করা হলে একটি সারিটি রিটার্নের মান হিসাবে স্বীকৃত বলে মনে হয় এবং আমি কাজ করতে পারি না .transform। যেকোন পরামর্শ সাদরে গ্রহন করা হবে!

উদাহরণ ডেটা:

from pandas import DataFrame
import numpy as np
a = DataFrame([{'var1': 'a,b,c', 'var2': 1},
               {'var1': 'd,e,f', 'var2': 2}])
b = DataFrame([{'var1': 'a', 'var2': 1},
               {'var1': 'b', 'var2': 1},
               {'var1': 'c', 'var2': 1},
               {'var1': 'd', 'var2': 2},
               {'var1': 'e', 'var2': 2},
               {'var1': 'f', 'var2': 2}])

আমি জানি এটি কার্যকর হবে না কারণ আমরা নালীর মধ্য দিয়ে গিয়ে ডেটাফ্রেম মেটা-ডেটা হারাব, তবে এটি আপনাকে কী করতে চেষ্টা করেছে তার একটি ধারণা দেওয়া উচিত:

def fun(row):
    letters = row['var1']
    letters = letters.split(',')
    out = np.array([row] * len(letters))
    out['var1'] = letters
a['idx'] = range(a.shape[0])
z = a.groupby('idx')
z.transform(fun)

2
এই পৃষ্ঠার অন্যান্য সমাধানগুলি কাজ করছে তবে আমি একটি সংক্ষিপ্ত এবং কার্যকর নিম্নলিখিত পেয়েছি। stackoverflow.com/questions/27263805/...
desaiankitb

1
অন্যদের জন্য এই পৃষ্ঠায় পৌঁছে যাওয়া এবং একাধিক কলামগুলি রাখে এমন সমাধানের সন্ধানের জন্য,
সোস

উত্তর:


81

কিভাবে ভালো কিছু সম্পর্কে:

In [55]: pd.concat([Series(row['var2'], row['var1'].split(','))              
                    for _, row in a.iterrows()]).reset_index()
Out[55]: 
  index  0
0     a  1
1     b  1
2     c  1
3     d  2
4     e  2
5     f  2

তারপরে আপনাকে কেবল কলামগুলির নাম পরিবর্তন করতে হবে


1
দেখে মনে হচ্ছে এটি কাজ করছে। আপনার সাহায্যের জন্য ধন্যবাদ! যদিও সাধারণভাবে স্প্লিট-অ্যাপ্লিকেশন-সম্মিলনের ক্ষেত্রে একটি পছন্দসই পদ্ধতি রয়েছে যেখানে প্রয়োগগুলি সালিশী আকারের একটি ডেটাফ্রেম (তবে সমস্ত অংশের জন্য সামঞ্জস্যপূর্ণ) প্রদান করে, এবং কেবল ফিরে আসা ডিএফকেই vstacks সংযুক্ত করে?
ভিনসেন্ট

GroupBy.apply কাজ করা উচিত (আমি এটি মাস্টারের বিরুদ্ধে চেষ্টা করেছি)। তবে, এক্ষেত্রে আপনার গ্রুপিংয়ের অতিরিক্ত পদক্ষেপের দরকার নেই যেহেতু আপনি সারিবদ্ধভাবে ডেটা তৈরি করছেন?
চ্যাং সে

1
এই যে বন্ধুরা. এত দেরিতে এদিকে লাফিয়ে উঠতে দুঃখিত, তবে এর থেকে আরও ভাল সমাধান না হলে ভাবছেন। আমি প্রথমবারের মতো ইটরোজ নিয়ে পরীক্ষার চেষ্টা করছি যেহেতু এটির জন্য টিকিটের মতো মনে হচ্ছে। প্রস্তাবিত সমাধানে আমিও বিভ্রান্ত। "_" কী উপস্থাপন করে? সমাধানটি কীভাবে কাজ করে তা আপনি সম্ভবত ব্যাখ্যা করতে পারেন? আপনি --Thank
horatio1701d

11
সমাধানটি কি আরও দুটি কলামে বাড়ানো যেতে পারে?
হোরাটিও 1701 ডি


146

আপডেট 2: আরও জেনেরিক ভেক্টরাইজড ফাংশন, যা একাধিক normalএবং একাধিক listকলামের জন্য কাজ করবে

def explode(df, lst_cols, fill_value='', preserve_index=False):
    # make sure `lst_cols` is list-alike
    if (lst_cols is not None
        and len(lst_cols) > 0
        and not isinstance(lst_cols, (list, tuple, np.ndarray, pd.Series))):
        lst_cols = [lst_cols]
    # all columns except `lst_cols`
    idx_cols = df.columns.difference(lst_cols)
    # calculate lengths of lists
    lens = df[lst_cols[0]].str.len()
    # preserve original index values    
    idx = np.repeat(df.index.values, lens)
    # create "exploded" DF
    res = (pd.DataFrame({
                col:np.repeat(df[col].values, lens)
                for col in idx_cols},
                index=idx)
             .assign(**{col:np.concatenate(df.loc[lens>0, col].values)
                            for col in lst_cols}))
    # append those rows that have empty lists
    if (lens == 0).any():
        # at least one list in cells is empty
        res = (res.append(df.loc[lens==0, idx_cols], sort=False)
                  .fillna(fill_value))
    # revert the original index order
    res = res.sort_index()
    # reset index if requested
    if not preserve_index:        
        res = res.reset_index(drop=True)
    return res

ডেমো:

একাধিক listকলাম - সমস্ত listকলামে প্রতিটি সারিতে একই # টি উপাদান থাকতে হবে:

In [134]: df
Out[134]:
   aaa  myid        num          text
0   10     1  [1, 2, 3]  [aa, bb, cc]
1   11     2         []            []
2   12     3     [1, 2]      [cc, dd]
3   13     4         []            []

In [135]: explode(df, ['num','text'], fill_value='')
Out[135]:
   aaa  myid num text
0   10     1   1   aa
1   10     1   2   bb
2   10     1   3   cc
3   11     2
4   12     3   1   cc
5   12     3   2   dd
6   13     4

মূল সূচক মান সংরক্ষণ করা:

In [136]: explode(df, ['num','text'], fill_value='', preserve_index=True)
Out[136]:
   aaa  myid num text
0   10     1   1   aa
0   10     1   2   bb
0   10     1   3   cc
1   11     2
2   12     3   1   cc
2   12     3   2   dd
3   13     4

সেটআপ:

df = pd.DataFrame({
 'aaa': {0: 10, 1: 11, 2: 12, 3: 13},
 'myid': {0: 1, 1: 2, 2: 3, 3: 4},
 'num': {0: [1, 2, 3], 1: [], 2: [1, 2], 3: []},
 'text': {0: ['aa', 'bb', 'cc'], 1: [], 2: ['cc', 'dd'], 3: []}
})

সিএসভি কলাম:

In [46]: df
Out[46]:
        var1  var2 var3
0      a,b,c     1   XX
1  d,e,f,x,y     2   ZZ

In [47]: explode(df.assign(var1=df.var1.str.split(',')), 'var1')
Out[47]:
  var1  var2 var3
0    a     1   XX
1    b     1   XX
2    c     1   XX
3    d     2   ZZ
4    e     2   ZZ
5    f     2   ZZ
6    x     2   ZZ
7    y     2   ZZ

এই ছোট কৌশলটি ব্যবহার করে আমরা সিএসভি-জাতীয় কলামটি কলামে রূপান্তর করতে পারি list:

In [48]: df.assign(var1=df.var1.str.split(','))
Out[48]:
              var1  var2 var3
0        [a, b, c]     1   XX
1  [d, e, f, x, y]     2   ZZ

আপডেট: জেনেরিক ভেক্টরাইজড পদ্ধতি (একাধিক কলামের জন্যও কাজ করবে):

আসল ডিএফ:

In [177]: df
Out[177]:
        var1  var2 var3
0      a,b,c     1   XX
1  d,e,f,x,y     2   ZZ

সমাধান:

প্রথমে CSV স্ট্রিংগুলিকে তালিকায় রূপান্তর করা যাক:

In [178]: lst_col = 'var1' 

In [179]: x = df.assign(**{lst_col:df[lst_col].str.split(',')})

In [180]: x
Out[180]:
              var1  var2 var3
0        [a, b, c]     1   XX
1  [d, e, f, x, y]     2   ZZ

এখন আমরা এটি করতে পারি:

In [181]: pd.DataFrame({
     ...:     col:np.repeat(x[col].values, x[lst_col].str.len())
     ...:     for col in x.columns.difference([lst_col])
     ...: }).assign(**{lst_col:np.concatenate(x[lst_col].values)})[x.columns.tolist()]
     ...:
Out[181]:
  var1  var2 var3
0    a     1   XX
1    b     1   XX
2    c     1   XX
3    d     2   ZZ
4    e     2   ZZ
5    f     2   ZZ
6    x     2   ZZ
7    y     2   ZZ

পুরানো উত্তর:

@ আফঙ্কেলস্টাইন সমাধান দ্বারা অনুপ্রাণিত হয়ে , আমি এটিকে আরও সাধারণীকরণ করতে চেয়েছিলাম যা ডিএফ-এ দুটি কলামেরও বেশি প্রয়োগ করা যেতে পারে এবং প্রায় দ্রুত, প্রায় আফিঙ্কেলস্টেইনের দ্রবণ হিসাবে):

In [2]: df = pd.DataFrame(
   ...:    [{'var1': 'a,b,c', 'var2': 1, 'var3': 'XX'},
   ...:     {'var1': 'd,e,f,x,y', 'var2': 2, 'var3': 'ZZ'}]
   ...: )

In [3]: df
Out[3]:
        var1  var2 var3
0      a,b,c     1   XX
1  d,e,f,x,y     2   ZZ

In [4]: (df.set_index(df.columns.drop('var1',1).tolist())
   ...:    .var1.str.split(',', expand=True)
   ...:    .stack()
   ...:    .reset_index()
   ...:    .rename(columns={0:'var1'})
   ...:    .loc[:, df.columns]
   ...: )
Out[4]:
  var1  var2 var3
0    a     1   XX
1    b     1   XX
2    c     1   XX
3    d     2   ZZ
4    e     2   ZZ
5    f     2   ZZ
6    x     2   ZZ
7    y     2   ZZ

7
বাবু, আপনি যদি গিট প্যান্ডাসে কোনও আলোচনা খুলতে পারেন, আমার মনে হয় আমাদের এইরকম একটি ফাংশন বিল্ড দরকার! পান্ডার জন্য এসওতে অপ্রদর্শিত ও নির্লিপ্ত হওয়া সম্পর্কে আমি অনেক প্রশ্ন দেখেছি
YOBEN_S

একাধিক কলামের জন্য এটি কীভাবে ব্যবহার করবেন। আমি 2 কলামে কমা দ্বারা পৃথক করা ডেটা আছে এবং ধারাবাহিকভাবে এটি করতে চান যদি?
জস্করণ সিং পুরী

@ যাসকরনসিংহপুরী, আপনি প্রথমে সমস্ত সিএসভি কলামকে তালিকায় রূপান্তর করতে চান।
ম্যাকসু

1
অজানা, আপনার তালিকার উপাদানগুলি টিপলস থাকলে এটি কাজ করে না। তবে পুরো টিপলকে স্ট্রিংয়ে রূপান্তরিত করার পরে, এটি একটি মোহনগুলির মতো কাজ করে!
গাইডো

2
দেখে মনে হচ্ছে যে ভেনবেনের আবেদন পান্ডাস দেবতা শুনেছেন, তারা এপিআইতে একটি .explode()পদ্ধতি ইনস্টল করেছেন (এছাড়াও এই উত্তরটি দেখুন )।
cs95

117

গৃহীত উত্তরের চেয়ে দ্রুত কিছু খুঁজে পাওয়ার জন্য বেদনাদায়ক পরীক্ষার পরে, আমি এটি কাজ করেছিলাম work এটি চেষ্টা করেছি এমন ডেটাসেটে এটি প্রায় 100x দ্রুত গতিতে চলেছে।

যদি কেউ এটিকে আরও মার্জিত করার কোনও উপায় জানেন তবে সর্বদা দয়া করে আমার কোডটি সংশোধন করুন। আপনি যে কলামগুলিকে সূচক হিসাবে রাখতে চান এবং অন্য সূচিগুলি পুনরায় সেট করা এবং কলামগুলি পুনরায় নামকরণ না করেই কাজ করে এমন কোনও উপায় খুঁজে পাচ্ছি না, তবে আমি ভাবতে পারি যে এর বাইরে আরও কিছু কাজ করে।

b = DataFrame(a.var1.str.split(',').tolist(), index=a.var2).stack()
b = b.reset_index()[[0, 'var2']] # var1 variable is currently labeled 0
b.columns = ['var1', 'var2'] # renaming var1

2
এই সমাধানটি উল্লেখযোগ্যভাবে দ্রুত কাজ করেছে এবং কম মেমরি ব্যবহার করে বলে মনে হচ্ছে
সিরিল

1
এটি একটি সুন্দর ভেক্টরাইজড পান্ডাস সলিউশন, আমি এটি খুঁজছিলাম। ধন্যবাদ!
ডেনিস গোলোমাজভ

আমি যখন নিজের ডেটাসেটে এটি চেষ্টা করি তখন আমি TypeError: object of type 'float' has no len()প্রথম ধাপে DataFrame(df.var1.str.split(',').tolist())
পৌঁছে যাচ্ছি

@ user5359531 আপনার ডেটা সেটটি সম্ভবত কিছু আছে NaN, যে কলামে তাই প্রতিস্থাপনb = DataFrame(a.var1.str.split(',').values.tolist(), index=a.var2).stack()
ফ্লেয়ারের

শুধু FYI এখানে উদাহরণ এই সমাধান নিয়ে একটা চমৎকার লেখার।
এইচবিলি

46

এই সাধারণ কাজের জন্য আমি এখানে একটি ফাংশন লিখেছি । এটি Series/ stackপদ্ধতির তুলনায় আরও দক্ষ । কলামের ক্রম এবং নামগুলি বজায় রাখা হয়।

def tidy_split(df, column, sep='|', keep=False):
    """
    Split the values of a column and expand so the new DataFrame has one split
    value per row. Filters rows where the column is missing.

    Params
    ------
    df : pandas.DataFrame
        dataframe with the column to split and expand
    column : str
        the column to split and expand
    sep : str
        the string used to split the column's values
    keep : bool
        whether to retain the presplit value as it's own row

    Returns
    -------
    pandas.DataFrame
        Returns a dataframe with the same columns as `df`.
    """
    indexes = list()
    new_values = list()
    df = df.dropna(subset=[column])
    for i, presplit in enumerate(df[column].astype(str)):
        values = presplit.split(sep)
        if keep and len(values) > 1:
            indexes.append(i)
            new_values.append(presplit)
        for value in values:
            indexes.append(i)
            new_values.append(value)
    new_df = df.iloc[indexes, :].copy()
    new_df[column] = new_values
    return new_df

এই ফাংশনটির সাথে, আসল প্রশ্নটি এতটা সহজ:

tidy_split(a, 'var1', sep=',')

1
এটি ফোসকাটে দ্রুত! এটার জন্য অনেক ধন্যবাদ।
অনুরাগ এন শর্মা

42

পান্ডা> = 0.25

সিরিজ এবং ডেটাফ্রেম পদ্ধতিগুলি এমন একটি .explode()পদ্ধতি নির্ধারণ করে যা পৃথক সারিগুলিতে তালিকা বিস্ফোরিত করে । তালিকার মতো কলামটি বিস্ফোরণে ডক্স বিভাগটি দেখুন ।

যেহেতু আপনার কাছে কমা দ্বারা পৃথক স্ট্রিংগুলির একটি তালিকা রয়েছে, উপাদানগুলির একটি তালিকা পেতে কমাতে স্ট্রিংটি বিভক্ত করুন, তারপরে explodeসেই কলামটিতে কল করুন।

df = pd.DataFrame({'var1': ['a,b,c', 'd,e,f'], 'var2': [1, 2]})
df
    var1  var2
0  a,b,c     1
1  d,e,f     2

df.assign(var1=df['var1'].str.split(',')).explode('var1')

  var1  var2
0    a     1
0    b     1
0    c     1
1    d     2
1    e     2
1    f     2

মনে রাখবেন যে explodeকেবলমাত্র একটি একক কলামে (এখন জন্য) কাজ করে।


এনএএন এবং খালি তালিকা সঠিকভাবে পেতে হুপের মধ্য দিয়ে ঝাঁপিয়ে না পড়ে চিকিত্সা পাওয়ার উপযুক্ত হয়ে পড়ে get

df = pd.DataFrame({'var1': ['d,e,f', '', np.nan], 'var2': [1, 2, 3]})
df
    var1  var2
0  d,e,f     1
1            2
2    NaN     3

df['var1'].str.split(',')

0    [d, e, f]
1           []
2          NaN

df.assign(var1=df['var1'].str.split(',')).explode('var1')

  var1  var2
0    d     1
0    e     1
0    f     1
1          2  # empty list entry becomes empty string after exploding 
2  NaN     3  # NaN left un-touched

এটি ravel+ repeat-ভিত্তিক সমাধানগুলির (যা খালি তালিকাগুলি সম্পূর্ণ উপেক্ষা করে এবং এনএএনএস-এ চেপে রাখে) উপর গুরুতর সুবিধা


4
এটি আমার পক্ষে সবচেয়ে সহজ এবং সেরা ফিট করে! ধন্যবাদ!
আইজাক সিম

14

অনুরূপ প্রশ্ন: পান্ডাস: আমি কীভাবে একাধিক সারিতে একটি কলামে পাঠ্যকে বিভক্ত করব?

আপনি করতে পারেন:

>> a=pd.DataFrame({"var1":"a,b,c d,e,f".split(),"var2":[1,2]})
>> s = a.var1.str.split(",").apply(pd.Series, 1).stack()
>> s.index = s.index.droplevel(-1)
>> del a['var1']
>> a.join(s)
   var2 var1
0     1    a
0     1    b
0     1    c
1     2    d
1     2    e
1     2    f

2
এটি আরও একটি নাম পরিবর্তনের কোড যুক্ত করার পরে কাজ করে s.name = 'var1'
জেসি

14

টি এল; ডিআর

import pandas as pd
import numpy as np

def explode_str(df, col, sep):
    s = df[col]
    i = np.arange(len(s)).repeat(s.str.count(sep) + 1)
    return df.iloc[i].assign(**{col: sep.join(s).split(sep)})

def explode_list(df, col):
    s = df[col]
    i = np.arange(len(s)).repeat(s.str.len())
    return df.iloc[i].assign(**{col: np.concatenate(s)})

প্রদর্শন

explode_str(a, 'var1', ',')

  var1  var2
0    a     1
0    b     1
0    c     1
1    d     2
1    e     2
1    f     2

আসুন একটি নতুন ডাটাফ্রেম তৈরি করুন dযার তালিকা রয়েছে

d = a.assign(var1=lambda d: d.var1.str.split(','))

explode_list(d, 'var1')

  var1  var2
0    a     1
0    b     1
0    c     1
1    d     2
1    e     2
1    f     2

সাধারাওন বক্তব্য

আমি ব্যবহার করব np.arangeসঙ্গে repeatdataframe সূচক অবস্থানের যে আমি সাথে ব্যবহার করতে পারেন উত্পাদন করতে iloc

প্রায়শই জিজ্ঞাসিত প্রশ্নাবলী

আমি কেন ব্যবহার করব না loc?

কারণ সূচকটি অনন্য হতে পারে না এবং ব্যবহার locকরে কোনও সন্ধানী সূচির সাথে মেলে এমন প্রতিটি সারি ফিরে আসবে।

আপনি যে valuesবৈশিষ্ট্যটি এবং স্লাইসটি ব্যবহার করেন না কেন ?

কল করার সময় values, যদি ডেটাফ্রেমের সম্পূর্ণতা একত্রী "ব্লক" এ থাকে, পান্ডস অ্যারেটির একটি দৃশ্য "ব্লক" ফিরিয়ে দেবে। অন্যথায় পান্ডাদের একটি নতুন অ্যারে একসাথে আবদ্ধ করতে হবে। কোবল করার সময় সেই অ্যারেটি অবশ্যই অভিন্ন টাইপের হবে। প্রায়শই এর অর্থ dtype দিয়ে একটি অ্যারে ফিরিয়ে দেওয়া object। অ্যাট্রিবিউটটি ilocকাটানোর পরিবর্তে ব্যবহার করে values, আমি এটি মোকাবেলা থেকে নিজেকে দূরে রাখি।

আপনি কেন ব্যবহার করবেন assign?

আমি যখন assignবিস্ফোরিত হচ্ছি একই কলামের নামটি ব্যবহার করি তখন আমি বিদ্যমান কলামটি ওভাররাইট করে ডেটা ফ্রেমে এর অবস্থান বজায় রাখি।

সূচকের মানগুলি কেন পুনরাবৃত্তি হয়?

ilocপুনরাবৃত্তি অবস্থানগুলি ব্যবহার করার কারণে , ফলাফল সূচক একই পুনরাবৃত্তি প্যাটার্ন দেখায়। প্রতিটি উপাদান তালিকা বা স্ট্রিংয়ের জন্য একটি পুনরাবৃত্তি।
এটি দিয়ে পুনরায় সেট করা যেতে পারেreset_index(drop=True)


স্ট্রিংসের জন্য

আমি চাই না যে অকালকালীন স্ট্রিংগুলি বিভক্ত করতে হবে। সুতরাং পরিবর্তে আমি sepযুক্তির উপস্থিতিগুলি গণনা করে ধরে নিলাম যে আমি বিভক্ত হলে ফলাফলের তালিকার দৈর্ঘ্য বিভাজকের সংখ্যার চেয়ে আরও একটি হবে।

আমি তখন ব্যবহার sepকরতে joinস্ট্রিং তারপর split

def explode_str(df, col, sep):
    s = df[col]
    i = np.arange(len(s)).repeat(s.str.count(sep) + 1)
    return df.iloc[i].assign(**{col: sep.join(s).split(sep)})

তালিকাগুলির জন্য

স্ট্রিংগুলির মতো একই সাথে এর উপস্থিতিগুলি গণনা করার দরকার নেই sepকারণ এটি ইতিমধ্যে বিভক্ত।

আমি concatenateতালিকাগুলিকে একসাথে জ্যাম করতে নম্পি ব্যবহার করি ।

import pandas as pd
import numpy as np

def explode_list(df, col):
    s = df[col]
    i = np.arange(len(s)).repeat(s.str.len())
    return df.iloc[i].assign(**{col: np.concatenate(s)})


আমার এটা ভাল লেগেছে. সত্যিই সংক্ষিপ্ত এবং অভিনয়টিও খুব ভাল হওয়া উচিত। যদিও একটি প্রশ্ন: df.iloc [i] ডাটাফ্রেমের সারিগুলি পুনরাবৃত্তি করার সমান বা এটি এর চেয়ে বেশি দক্ষ? ধন্যবাদ!
টিম

7

ডেটাফ্রেমের কাঠামো পরিবর্তন না করেই ডেটাফ্রেমকে বিভক্ত এবং বিস্ফোরণের সম্ভাবনা রয়েছে

নির্দিষ্ট কলামগুলির ডেটা বিভক্ত করুন এবং প্রসারিত করুন

ইনপুট:

    var1    var2
0   a,b,c   1
1   d,e,f   2



#Get the indexes which are repetative with the split 
temp = df['var1'].str.split(',')
df = df.reindex(df.index.repeat(temp.apply(len)))


df['var1'] = np.hstack(temp)

বাইরে:

    var1    var2
0   a   1
0   b   1
0   c   1
1   d   2
1   e   2
1   f   2

সম্পাদনা করুন -1

একাধিক কলামের জন্য সারি বিভক্ত এবং প্রসারিত করুন

Filename    RGB                                             RGB_type
0   A   [[0, 1650, 6, 39], [0, 1691, 1, 59], [50, 1402...   [r, g, b]
1   B   [[0, 1423, 16, 38], [0, 1445, 16, 46], [0, 141...   [r, g, b]

রেফারেন্স কলামের উপর ভিত্তি করে ইনডেক্সিং এবং স্ট্যাকের সাহায্যে কলাম মান তথ্য প্রান্তিককরণ

df = df.reindex(df.index.repeat(df['RGB_type'].apply(len)))
df = df.groupby('Filename').apply(lambda x:x.apply(lambda y: pd.Series(y.iloc[0])))
df.reset_index(drop=True).ffill()

বাইরে:

                Filename    RGB_type    Top 1 colour    Top 1 frequency Top 2 colour    Top 2 frequency
    Filename                            
 A  0       A   r   0   1650    6   39
    1       A   g   0   1691    1   59
    2       A   b   50  1402    49  187
 B  0       B   r   0   1423    16  38
    1       B   g   0   1445    16  46
    2       B   b   0   1419    16  39

5

আমি কলামের স্বেচ্ছাসেবী সংখ্যার সাথে ডেটাফ্রেমগুলির সমাধান নিয়ে এসেছি (যখন এখনও কেবল একবারে একটি কলামের এন্ট্রি পৃথক করে)।

def splitDataFrameList(df,target_column,separator):
    ''' df = dataframe to split,
    target_column = the column containing the values to split
    separator = the symbol used to perform the split

    returns: a dataframe with each entry for the target column separated, with each element moved into a new row. 
    The values in the other columns are duplicated across the newly divided rows.
    '''
    def splitListToRows(row,row_accumulator,target_column,separator):
        split_row = row[target_column].split(separator)
        for s in split_row:
            new_row = row.to_dict()
            new_row[target_column] = s
            row_accumulator.append(new_row)
    new_rows = []
    df.apply(splitListToRows,axis=1,args = (new_rows,target_column,separator))
    new_df = pandas.DataFrame(new_rows)
    return new_df

2
এই টডিক্ট () রূপান্তরটির কারণে সুন্দর তবে দুঃখজনকভাবে ধীরে :(
ম্যাক ২

4

এখানে মোটামুটি সরল বার্তাটি যা splitপান্ডাস strঅ্যাকসেসর থেকে পদ্ধতিটি ব্যবহার করে এবং তারপরে প্রতিটি সারিকে একক অ্যারে সমতল করার জন্য NumPy ব্যবহার করে।

সম্পর্কিত মানগুলি অবিভক্ত কলামটির সাথে সঠিক সংখ্যার পুনরাবৃত্তি করে পুনরুদ্ধার করা হয় np.repeat

var1 = df.var1.str.split(',', expand=True).values.ravel()
var2 = np.repeat(df.var2.values, len(var1) / len(df))

pd.DataFrame({'var1': var1,
              'var2': var2})

  var1  var2
0    a     1
1    b     1
2    c     1
3    d     2
4    e     2
5    f     2

1
এটি একটি খুব সুন্দর উত্তর হতে পারে। দুর্ভাগ্যক্রমে, এটি প্রচুর কলামের জন্য স্কেল করে না, তাই না?
মাইকেল ডোনার

3

আমার তালিকাগুলি বিস্ফোরণে বিভিন্ন উপায়ে ব্যবহার করে আমি মেমরির বাইরে থাকা অভিজ্ঞতার সাথে লড়াই করে যাচ্ছি যাতে কোন উত্তরগুলি উত্তর দেয় তা স্থির করতে আমি কিছু বেঞ্চমার্ক প্রস্তুত করেছি। আমি তালিকার সংখ্যার তালিকার দৈর্ঘ্যের বিভিন্ন অনুপাত সহ পাঁচটি পরিস্থিতি পরীক্ষা করেছি। নীচে ফলাফল ভাগ করা:

সময়: (কম ভাল, বড় সংস্করণ দেখতে ক্লিক করুন)

গতি

পিক মেমরির ব্যবহার: (কম ভাল)

পিক মেমরির ব্যবহার

উপসংহার :

  • @ MaxU এর উত্তর (আপডেট 2), কোডনাম CONCATENATE অফার, প্রায় প্রতিটি ক্ষেত্রে সেরা গতি যখন উঁকি মেমোরি ব্যবহার কম রেখে
  • দেখতে @ DMulligan এর উত্তর (কোডনাম স্ট্যাক ) আপনি অপেক্ষাকৃত ছোট তালিকা সঙ্গে সারি প্রক্রিয়া প্রচুর প্রয়োজন এবং বর্ধিত শিখর মেমরির সামর্থ,
  • গৃহীত @ চ্যাংয়ের উত্তরটি কয়েকটি ফ্রেমে এমন ডেটা ফ্রেমের জন্য ভাল কাজ করে তবে খুব বড় তালিকা রয়েছে।

সম্পূর্ণ বিবরণ (ফাংশন এবং বেঞ্চমার্কিং কোড) এই গিটহাবের সংক্ষেপে রয়েছে । দয়া করে নোট করুন যে বেঞ্চমার্ক সমস্যাটি সরল করা হয়েছে এবং তালিকায় স্ট্রিং বিভক্তকরণকে অন্তর্ভুক্ত করেনি - যা বেশিরভাগ সমাধান একই ধরণের ফাংশনে সম্পাদিত হয়েছিল।


ভাল তুলনা! আপনি কোনও কোড পোস্ট করতে আপত্তি করেন যা আপনি বেঞ্চমার্কের চক্রান্ত করার জন্য ব্যবহার করেছিলেন?
ম্যাকসু

1
দয়া করে এই লিঙ্কটি দেখুন: gist.github.com/krassowski/0259a2cd2ba774ccd9f69bbcc3187fbf (ইতিমধ্যে উত্তরে অন্তর্ভুক্ত) - আইএমও এটি সমস্ত এখানে পেস্ট করতে কিছুটা দীর্ঘ হবে।
ক্রেসোস্কি

2

দুর্দান্ত @ ডামুলিগানের সমাধানের ভিত্তিতে , এখানে একটি জেনেরিক ভেক্টরাইজড (কোনও লুপ নেই) ফাংশন রয়েছে যা একটি ডেটাফ্রেমের একটি কলামকে একাধিক সারিগুলিতে বিভক্ত করে এবং এটিকে মূল ডেটাফ্রেমে ফিরে একীভূত করে। এটি change_column_orderএই উত্তর থেকে দুর্দান্ত জেনেরিক ফাংশন ব্যবহার করে ।

def change_column_order(df, col_name, index):
    cols = df.columns.tolist()
    cols.remove(col_name)
    cols.insert(index, col_name)
    return df[cols]

def split_df(dataframe, col_name, sep):
    orig_col_index = dataframe.columns.tolist().index(col_name)
    orig_index_name = dataframe.index.name
    orig_columns = dataframe.columns
    dataframe = dataframe.reset_index()  # we need a natural 0-based index for proper merge
    index_col_name = (set(dataframe.columns) - set(orig_columns)).pop()
    df_split = pd.DataFrame(
        pd.DataFrame(dataframe[col_name].str.split(sep).tolist())
        .stack().reset_index(level=1, drop=1), columns=[col_name])
    df = dataframe.drop(col_name, axis=1)
    df = pd.merge(df, df_split, left_index=True, right_index=True, how='inner')
    df = df.set_index(index_col_name)
    df.index.name = orig_index_name
    # merge adds the column to the last place, so we need to move it back
    return change_column_order(df, col_name, orig_col_index)

উদাহরণ:

df = pd.DataFrame([['a:b', 1, 4], ['c:d', 2, 5], ['e:f:g:h', 3, 6]], 
                  columns=['Name', 'A', 'B'], index=[10, 12, 13])
df
        Name    A   B
    10   a:b     1   4
    12   c:d     2   5
    13   e:f:g:h 3   6

split_df(df, 'Name', ':')
    Name    A   B
10   a       1   4
10   b       1   4
12   c       2   5
12   d       2   5
13   e       3   6
13   f       3   6    
13   g       3   6    
13   h       3   6    

দ্রষ্টব্য যে এটি কলামগুলির মূল সূচি এবং ক্রম সংরক্ষণ করে। এটি ডেটাফ্রেমগুলির সাথেও কাজ করে যার অ-অনুক্রমিক সূচক রয়েছে।


2
এটি আমার জন্য এটির
ইভান

2

স্ট্রিং ফাংশন বিভাজন একটি বুলিয়ান আর্গুমেন্ট 'প্রসারিত' নিতে পারে।

এই যুক্তিটি ব্যবহার করে একটি সমাধান এখানে দেওয়া হয়েছে:

(a.var1
  .str.split(",",expand=True)
  .set_index(a.var2)
  .stack()
  .reset_index(level=1, drop=True)
  .reset_index()
  .rename(columns={0:"var1"}))

1

উপরে থেকে জিলনের দুর্দান্ত উত্তরটি ব্যবহৃত হয়েছে, তবে একাধিক কলাম বিভক্ত করতে প্রসারিত হওয়া দরকার। ভেবেছিলাম ভাগ করে নেব।

def splitDataFrameList(df,target_column,separator):
''' df = dataframe to split,
target_column = the column containing the values to split
separator = the symbol used to perform the split

returns: a dataframe with each entry for the target column separated, with each element moved into a new row. 
The values in the other columns are duplicated across the newly divided rows.
'''
def splitListToRows(row, row_accumulator, target_columns, separator):
    split_rows = []
    for target_column in target_columns:
        split_rows.append(row[target_column].split(separator))
    # Seperate for multiple columns
    for i in range(len(split_rows[0])):
        new_row = row.to_dict()
        for j in range(len(split_rows)):
            new_row[target_columns[j]] = split_rows[j][i]
        row_accumulator.append(new_row)
new_rows = []
df.apply(splitListToRows,axis=1,args = (new_rows,target_column,separator))
new_df = pd.DataFrame(new_rows)
return new_df

1

মাল্টিআইএনডেক্স সমর্থন সহ ম্যাক্সের উত্তরটি আপগ্রেড করা হয়েছে

def explode(df, lst_cols, fill_value='', preserve_index=False):
    """
    usage:
        In [134]: df
        Out[134]:
           aaa  myid        num          text
        0   10     1  [1, 2, 3]  [aa, bb, cc]
        1   11     2         []            []
        2   12     3     [1, 2]      [cc, dd]
        3   13     4         []            []

        In [135]: explode(df, ['num','text'], fill_value='')
        Out[135]:
           aaa  myid num text
        0   10     1   1   aa
        1   10     1   2   bb
        2   10     1   3   cc
        3   11     2
        4   12     3   1   cc
        5   12     3   2   dd
        6   13     4
    """
    # make sure `lst_cols` is list-alike
    if (lst_cols is not None
        and len(lst_cols) > 0
        and not isinstance(lst_cols, (list, tuple, np.ndarray, pd.Series))):
        lst_cols = [lst_cols]
    # all columns except `lst_cols`
    idx_cols = df.columns.difference(lst_cols)
    # calculate lengths of lists
    lens = df[lst_cols[0]].str.len()
    # preserve original index values    
    idx = np.repeat(df.index.values, lens)
    res = (pd.DataFrame({
                col:np.repeat(df[col].values, lens)
                for col in idx_cols},
                index=idx)
             .assign(**{col:np.concatenate(df.loc[lens>0, col].values)
                            for col in lst_cols}))
    # append those rows that have empty lists
    if (lens == 0).any():
        # at least one list in cells is empty
        res = (res.append(df.loc[lens==0, idx_cols], sort=False)
                  .fillna(fill_value))
    # revert the original index order
    res = res.sort_index()
    # reset index if requested
    if not preserve_index:        
        res = res.reset_index(drop=True)

    # if original index is MultiIndex build the dataframe from the multiindex
    # create "exploded" DF
    if isinstance(df.index, pd.MultiIndex):
        res = res.reindex(
            index=pd.MultiIndex.from_tuples(
                res.index,
                names=['number', 'color']
            )
    )
    return res

1

ওয়ান-লাইনার ব্যবহার split(___, expand=True)করে levelএবং nameযুক্তিগুলি reset_index():

>>> b = a.var1.str.split(',', expand=True).set_index(a.var2).stack().reset_index(level=0, name='var1')
>>> b
   var2 var1
0     1    a
1     1    b
2     1    c
0     2    d
1     2    e
2     2    f

যদি আপনাকে bপ্রশ্নটির মতো দেখতে দেখতে প্রয়োজন হয় তবে আপনি অতিরিক্তভাবে এটি করতে পারেন:

>>> b = b.reset_index(drop=True)[['var1', 'var2']]
>>> b
  var1  var2
0    a     1
1    b     1
2    c     1
3    d     2
4    e     2
5    f     2

0

আমি এই সমস্যার নিম্নলিখিত সমাধান নিয়ে এসেছি:

def iter_var1(d):
    for _, row in d.iterrows():
        for v in row["var1"].split(","):
            yield (v, row["var2"])

new_a = DataFrame.from_records([i for i in iter_var1(a)],
        columns=["var1", "var2"])

0

অজগর অনুলিপি প্যাকেজ ব্যবহার করে এমন আরও একটি সমাধান

import copy
new_observations = list()
def pandas_explode(df, column_to_explode):
    new_observations = list()
    for row in df.to_dict(orient='records'):
        explode_values = row[column_to_explode]
        del row[column_to_explode]
        if type(explode_values) is list or type(explode_values) is tuple:
            for explode_value in explode_values:
                new_observation = copy.deepcopy(row)
                new_observation[column_to_explode] = explode_value
                new_observations.append(new_observation) 
        else:
            new_observation = copy.deepcopy(row)
            new_observation[column_to_explode] = explode_values
            new_observations.append(new_observation) 
    return_df = pd.DataFrame(new_observations)
    return return_df

df = pandas_explode(df, column_name)

0

এখানে প্রচুর উত্তর রয়েছে তবে আমি অবাক হয়েছি যে কেউ পান্ডাস বিস্ফোরণে নির্মিত বিল্ট ইন উল্লেখ করেনি। নীচের লিঙ্কটি দেখুন: https://pandas.pydata.org/pandas-docs/stable/references/api/pandas.DataFrame.explode.html#pandas.DataFrame.explode

কোনও কারণে আমি সেই ফাংশনটি অ্যাক্সেস করতে পারিনি, তাই আমি নীচের কোডটি ব্যবহার করেছি:

import pandas_explode
pandas_explode.patch()
df_zlp_people_cnt3 = df_zlp_people_cnt2.explode('people')

এখানে চিত্র বর্ণনা লিখুন

উপরে আমার ডেটার একটি নমুনা রয়েছে। আপনি দেখতে পাচ্ছেন যে লোক কলামে বহু লোক রয়েছে এবং আমি এটি বিস্ফোরিত করার চেষ্টা করছিলাম। আমি যে কোড দিয়েছি তা তালিকার ধরণের ডেটার জন্য কাজ করে। সুতরাং আপনার কমা দ্বারা পৃথক টেক্সট ডেটা তালিকা ফর্ম্যাটে আনার চেষ্টা করুন। এছাড়াও যেহেতু আমার কোডগুলি ফাংশনে অন্তর্নির্মিত ব্যবহার করে, এটি কাস্টম / প্রয়োগ ফাংশনগুলির চেয়ে অনেক দ্রুত faster

দ্রষ্টব্য: আপনার পাইপের সাথে প্যান্ডাস_এক্সপ্লোড ইনস্টল করতে হতে পারে।


0

আমার অনুরূপ সমস্যা ছিল, আমার সমাধানটি ডেটাফ্রেমকে অভিধানের তালিকায় প্রথমে রূপান্তরিত করছিল, তারপরে রূপান্তরটি কর। ফাংশনটি এখানে:

import copy
import re

def separate_row(df, column_name):
    ls = []
    for row_dict in df.to_dict('records'):
        for word in re.split(',', row_dict[column_name]):
            row = copy.deepcopy(row_dict)
            row[column_name]=word
            ls(row)
    return pd.DataFrame(ls)

উদাহরণ:

>>> from pandas import DataFrame
>>> import numpy as np
>>> a = DataFrame([{'var1': 'a,b,c', 'var2': 1},
               {'var1': 'd,e,f', 'var2': 2}])
>>> a
    var1  var2
0  a,b,c     1
1  d,e,f     2
>>> separate_row(a, "var1")
  var1  var2
0    a     1
1    b     1
2    c     1
3    d     2
4    e     2
5    f     2

পৃথকীকরণ তালিকার সারিগুলিকে সমর্থন করতে আপনি ফাংশনটি কিছুটা পরিবর্তন করতে পারেন।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.