панды: как разделить текст в столбце на несколько строк?



Я работаю с большим csv-файлом, и в предпоследнем столбце есть строка текста, которую я хочу разделить определенным разделителем. Мне было интересно, есть ли простой способ сделать это с помощью панд или питона?



CustNum  CustomerName     ItemQty  Item   Seatblocks                 ItemExt
32363 McCartney, Paul 3 F04 2:218:10:4,6 60
31316 Lennon, John 25 F01 1:13:36:1,12 1:13:37:1,13 300


Я хочу разделить на пробел(' ') а потом двоеточие(':') на Seatblocks столбец, но каждая ячейка приведет к различному количеству столбцов. У меня есть функция, чтобы переставить столбцы так Seatblocks столбец находится в конце листа, но я не уверен, что делать оттуда. Я могу сделать это в Excel со встроенным text-to-columns функция и быстрый макрос, но мой набор данных имеет слишком много записей для обработки excel.



в конечном счете, я хочу взять такой записи Джона Леннона и создать несколько строк с информацией из каждого блока мест на отдельной строке.

619   3  

3 ответов:

Это разбивает блоки сидений по пространству и дает каждому свой собственный ряд.

In [43]: df
Out[43]: 
   CustNum     CustomerName  ItemQty Item                 Seatblocks  ItemExt
0    32363  McCartney, Paul        3  F04               2:218:10:4,6       60
1    31316     Lennon, John       25  F01  1:13:36:1,12 1:13:37:1,13      300

In [44]: s = df['Seatblocks'].str.split(' ').apply(Series, 1).stack()

In [45]: s.index = s.index.droplevel(-1) # to line up with df's index

In [46]: s.name = 'Seatblocks' # needs a name to join

In [47]: s
Out[47]: 
0    2:218:10:4,6
1    1:13:36:1,12
1    1:13:37:1,13
Name: Seatblocks, dtype: object

In [48]: del df['Seatblocks']

In [49]: df.join(s)
Out[49]: 
   CustNum     CustomerName  ItemQty Item  ItemExt    Seatblocks
0    32363  McCartney, Paul        3  F04       60  2:218:10:4,6
1    31316     Lennon, John       25  F01      300  1:13:36:1,12
1    31316     Lennon, John       25  F01      300  1:13:37:1,13

или, чтобы дать каждую строку, разделенную двоеточием, в своем собственном столбце:

In [50]: df.join(s.apply(lambda x: Series(x.split(':'))))
Out[50]: 
   CustNum     CustomerName  ItemQty Item  ItemExt  0    1   2     3
0    32363  McCartney, Paul        3  F04       60  2  218  10   4,6
1    31316     Lennon, John       25  F01      300  1   13  36  1,12
1    31316     Lennon, John       25  F01      300  1   13  37  1,13

Это немного некрасиво, но, может быть, кто-то перезвонит с более красивым решением.

в отличие от Дэна, я считаю его ответ довольно элегантным... но, к сожалению, это также очень неэффективно. Итак, поскольку вопрос упомянут "большой csv-файл", позвольте мне предложить попробовать в оболочке решение Дэна:

time python -c "import pandas as pd;
df = pd.DataFrame(['a b c']*100000, columns=['col']);
print df['col'].apply(lambda x : pd.Series(x.split(' '))).head()"

... по сравнению с этой альтернативой:

time python -c "import pandas as pd;
from scipy import array, concatenate;
df = pd.DataFrame(['a b c']*100000, columns=['col']);
print pd.DataFrame(concatenate(df['col'].apply( lambda x : [x.split(' ')]))).head()"

... а это:

time python -c "import pandas as pd;
df = pd.DataFrame(['a b c']*100000, columns=['col']);
print pd.DataFrame(dict(zip(range(3), [df['col'].apply(lambda x : x.split(' ')[i]) for i in range(3)]))).head()"

второй просто воздерживается от выделения 100 000 серий, и этого достаточно, чтобы сделать его примерно в 10 раз быстрее. Но третье решение, которое несколько иронично тратит много звонков на str.split () (он вызывается один раз на столбец в строке, поэтому в три раза больше, чем для двух других решений), находится вокруг 40 раз быстрее, чем первый, потому что он даже избегает, например, 100 000 списков. И да, это, конечно, немного некрасиво...

EDIT:ответ предлагает, как использовать "to_list()" и чтобы избежать необходимости в лямбда. Получается что-то как

time python -c "import pandas as pd;
df = pd.DataFrame(['a b c']*100000, columns=['col']);
print pd.DataFrame(df.col.str.split().tolist()).head()"

что еще более эффективно, чем третье решение, и, конечно, гораздо более элегантно.

EDIT: еще проще

time python -c "import pandas as pd;
df = pd.DataFrame(['a b c']*100000, columns=['col']);
print pd.DataFrame(list(df.col.str.split())).head()"

работает, а почти как эффективная.

EDIT:еще проще! И обрабатывает NaNs (но менее эффективно):

time python -c "import pandas as pd;
df = pd.DataFrame(['a b c']*100000, columns=['col']);
print df.col.str.split(expand=True).head()"
import pandas as pd
import numpy as np

df = pd.DataFrame({'ItemQty': {0: 3, 1: 25}, 
                   'Seatblocks': {0: '2:218:10:4,6', 1: '1:13:36:1,12 1:13:37:1,13'}, 
                   'ItemExt': {0: 60, 1: 300}, 
                   'CustomerName': {0: 'McCartney, Paul', 1: 'Lennon, John'}, 
                   'CustNum': {0: 32363, 1: 31316}, 
                   'Item': {0: 'F04', 1: 'F01'}}, 
                    columns=['CustNum','CustomerName','ItemQty','Item','Seatblocks','ItemExt'])

print (df)
   CustNum     CustomerName  ItemQty Item                 Seatblocks  ItemExt
0    32363  McCartney, Paul        3  F04               2:218:10:4,6       60
1    31316     Lennon, John       25  F01  1:13:36:1,12 1:13:37:1,13      300

еще одно подобное решение с цепочкой-это использование reset_index и rename:

print (df.drop('Seatblocks', axis=1)
             .join
             (
             df.Seatblocks
             .str
             .split(expand=True)
             .stack()
             .reset_index(drop=True, level=1)
             .rename('Seatblocks')           
             ))

   CustNum     CustomerName  ItemQty Item  ItemExt    Seatblocks
0    32363  McCartney, Paul        3  F04       60  2:218:10:4,6
1    31316     Lennon, John       25  F01      300  1:13:36:1,12
1    31316     Lennon, John       25  F01      300  1:13:37:1,13

если в столбце неNaN значения, самое быстрое решение-использовать list понимание с DataFrame конструктора:

df = pd.DataFrame(['a b c']*100000, columns=['col'])

In [141]: %timeit (pd.DataFrame(dict(zip(range(3), [df['col'].apply(lambda x : x.split(' ')[i]) for i in range(3)]))))
1 loop, best of 3: 211 ms per loop

In [142]: %timeit (pd.DataFrame(df.col.str.split().tolist()))
10 loops, best of 3: 87.8 ms per loop

In [143]: %timeit (pd.DataFrame(list(df.col.str.split())))
10 loops, best of 3: 86.1 ms per loop

In [144]: %timeit (df.col.str.split(expand=True))
10 loops, best of 3: 156 ms per loop

In [145]: %timeit (pd.DataFrame([ x.split() for x in df['col'].tolist()]))
10 loops, best of 3: 54.1 ms per loop

но если столбец содержит NaN работает только str.split с параметром expand=True взамен DataFrame (документация), и это объяснить почему это медленнее:

df = pd.DataFrame(['a b c']*10, columns=['col'])
df.loc[0] = np.nan
print (df.head())
     col
0    NaN
1  a b c
2  a b c
3  a b c
4  a b c

print (df.col.str.split(expand=True))
     0     1     2
0  NaN  None  None
1    a     b     c
2    a     b     c
3    a     b     c
4    a     b     c
5    a     b     c
6    a     b     c
7    a     b     c
8    a     b     c
9    a     b     c

Comments

    Ничего не найдено.