Як розділити стовпчик на два стовпчики?


197

У мене є кадр даних з одним стовпцем, і я хотів би розділити його на два стовпці, з одним заголовком стовпця як ", fips'а іншим"'row'

Мій кадр даних dfвиглядає приблизно так:

          row
0    00000 UNITED STATES
1    01000 ALABAMA
2    01001 Autauga County, AL
3    01003 Baldwin County, AL
4    01005 Barbour County, AL

Я не знаю, як використовувати, df.row.str[:]щоб досягти своєї мети - розділити комірку рядків. Я можу використовувати, df['fips'] = helloщоб додати новий стовпець і заповнити його hello. Будь-які ідеї?

         fips       row
0    00000 UNITED STATES
1    01000 ALABAMA 
2    01001 Autauga County, AL
3    01003 Baldwin County, AL
4    01005 Barbour County, AL

3
як ви завантажили свої дані в панди? Ви можете бути в змозі laod дані в потрібному Вам форматі , використовуючи read_table()або read_fwf()
Зах

Відповіді:


139

Можливо, буде і кращий спосіб, але це один підхід:

                            row
    0       00000 UNITED STATES
    1             01000 ALABAMA
    2  01001 Autauga County, AL
    3  01003 Baldwin County, AL
    4  01005 Barbour County, AL
df = pd.DataFrame(df.row.str.split(' ',1).tolist(),
                                 columns = ['flips','row'])
   flips                 row
0  00000       UNITED STATES
1  01000             ALABAMA
2  01001  Autauga County, AL
3  01003  Baldwin County, AL
4  01005  Barbour County, AL

6
Майте на увазі, що .tolist () видалить усі ваші індекси, тому ваш новий Dataframe буде перевстановлений з 0 (Це не має значення у вашому конкретному випадку).
Crashthatch

10
@Crashthatch - тоді знову можна просто додати, index = df.indexі ти хороший.
корінь

що робити, якщо одну клітинку неможливо розділити?
Нісба

@Nisba: Якщо жодна комірка не може бути розділена (наприклад, рядок не містить місця для цього випадку), вона все одно буде працювати, але одна частина розбиття буде порожньою. Інші ситуації трапляться, якщо у стовпці змішані типи мають хоча б одну комірку, що містить будь-який тип числа. Тоді splitметод повертає NaN, і tolistметод поверне це значення таким, яким є (NaN), що призведе до ValueError(для подолання цієї проблеми ви можете передати її до типу рядка перед розщепленням). Я рекомендую вам спробувати це самостійно, це найкращий спосіб навчання :-)
Nerxis

@techkuz: Ви впевнені, що у вас dfє rowзаголовок стовпця? Ви можете подумати, що це якийсь атрибут DataFrame, але цілком зрозуміло, що це назва стовпця. Ви вирішуєте, як створювати та визначати заголовки стовпців, тож якщо ви використовуєте інше, використовуйте його (наприклад df.my_column_name.split(...)).
Нерксіс

391

Версія TL; DR:

Для простого випадку:

  • У мене є текстовий стовпчик з роздільником, і я хочу два стовпчики

Найпростіше рішення:

df['A'], df['B'] = df['AB'].str.split(' ', 1).str

Або ви можете створити DataFrame з одним стовпцем для кожного запису розділення автоматично за допомогою:

df['AB'].str.split(' ', 1, expand=True)

Ви повинні використовувати, expand=Trueякщо у ваших рядків є неоднакова кількість розщеплень і ви хочете Noneзамінити відсутні значення.

Зауважте, як в будь-якому випадку .tolist()метод не є необхідним. Ніzip() .

Детально:

Рішення Енді Хейдена найкраще демонструє силу str.extract()методу.

Але для простого розколу на відомий роздільник (наприклад, розбиття тире або розбиття пробілом) .str.split()методу достатньо 1 . Він працює над стовпцем (Серією) рядків і повертає стовпець (Серія) списків:

>>> import pandas as pd
>>> df = pd.DataFrame({'AB': ['A1-B1', 'A2-B2']})
>>> df

      AB
0  A1-B1
1  A2-B2
>>> df['AB_split'] = df['AB'].str.split('-')
>>> df

      AB  AB_split
0  A1-B1  [A1, B1]
1  A2-B2  [A2, B2]

1: Якщо ви не впевнені, що робити перші два параметри .str.split(), я рекомендую документи для простої версії методу Python .

Але як походити:

  • стовпчик, що містить двоелементні списки

до:

  • два стовпці, кожен з яких містить відповідний елемент списків?

Що ж, нам потрібно уважніше подивитися .str атрибут стовпця.

Це магічний об'єкт, який використовується для збору методів, які розглядають кожен елемент у стовпці як рядок, а потім застосовують відповідний метод до кожного елемента максимально ефективно:

>>> upper_lower_df = pd.DataFrame({"U": ["A", "B", "C"]})
>>> upper_lower_df

   U
0  A
1  B
2  C
>>> upper_lower_df["L"] = upper_lower_df["U"].str.lower()
>>> upper_lower_df

   U  L
0  A  a
1  B  b
2  C  c

Але він також має "індексування" інтерфейс для отримання кожного елемента рядка за його індексом:

>>> df['AB'].str[0]

0    A
1    A
Name: AB, dtype: object

>>> df['AB'].str[1]

0    1
1    2
Name: AB, dtype: object

Звичайно, цей інтерфейс індексування .strнасправді не хвилює, чи кожен елемент його індексації насправді є рядком, якщо він може бути індексований, так що:

>>> df['AB'].str.split('-', 1).str[0]

0    A1
1    A2
Name: AB, dtype: object

>>> df['AB'].str.split('-', 1).str[1]

0    B1
1    B2
Name: AB, dtype: object

Тоді, це просте питання скористатись кортежем Python для розпакування ітерабелів

>>> df['A'], df['B'] = df['AB'].str.split('-', 1).str
>>> df

      AB  AB_split   A   B
0  A1-B1  [A1, B1]  A1  B1
1  A2-B2  [A2, B2]  A2  B2

Звичайно, виведення DataFrame з розбиття стовпця рядків настільки корисно, що .str.split()метод може зробити це для вас за допомогою expand=Trueпараметра:

>>> df['AB'].str.split('-', 1, expand=True)

    0   1
0  A1  B1
1  A2  B2

Отже, ще один спосіб здійснити те, що ми хотіли:

>>> df = df[['AB']]
>>> df

      AB
0  A1-B1
1  A2-B2

>>> df.join(df['AB'].str.split('-', 1, expand=True).rename(columns={0:'A', 1:'B'}))

      AB   A   B
0  A1-B1  A1  B1
1  A2-B2  A2  B2

expand=TrueВерсія, хоча і довше, має явну перевагу по порівнянні з методом кортежу розпакування. Розпакування кортежу не дуже добре справляється з розколами різної довжини:

>>> df = pd.DataFrame({'AB': ['A1-B1', 'A2-B2', 'A3-B3-C3']})
>>> df
         AB
0     A1-B1
1     A2-B2
2  A3-B3-C3
>>> df['A'], df['B'], df['C'] = df['AB'].str.split('-')
Traceback (most recent call last):
  [...]    
ValueError: Length of values does not match length of index
>>> 

Але expand=Trueце добре обробляє, розміщуючи Noneв стовпцях, для яких недостатньо "розщеплення":

>>> df.join(
...     df['AB'].str.split('-', expand=True).rename(
...         columns={0:'A', 1:'B', 2:'C'}
...     )
... )
         AB   A   B     C
0     A1-B1  A1  B1  None
1     A2-B2  A2  B2  None
2  A3-B3-C3  A3  B3    C3

df ['A'], df ['B'] = df ['AB']. str.split ('', 1) .str Яке значення '1' у розщепленні ('', 1)?
Харіпрасад

@Hariprasad, це максимальна кількість розщеплень. Я додав посилання на документи для версії .split()методу Python, яка пояснює перші два параметри краще, ніж документи Pandas.
LeoRochael

5
pandas 1.0.0 повідомляє "FutureWarning: стовпчаста ітерація над символами буде застаріла в майбутніх випусках."
Френк

1
Це працює під Python 1.0.1. df.join(df['AB'].str.split('-', 1, expand=True).rename(columns={0:'A', 1:'B'}))
Martien Lubberink

59

Ви можете витягти різні деталі досить акуратно, використовуючи схему регулярного вираження:

In [11]: df.row.str.extract('(?P<fips>\d{5})((?P<state>[A-Z ]*$)|(?P<county>.*?), (?P<state_code>[A-Z]{2}$))')
Out[11]: 
    fips                    1           state           county state_code
0  00000        UNITED STATES   UNITED STATES              NaN        NaN
1  01000              ALABAMA         ALABAMA              NaN        NaN
2  01001   Autauga County, AL             NaN   Autauga County         AL
3  01003   Baldwin County, AL             NaN   Baldwin County         AL
4  01005   Barbour County, AL             NaN   Barbour County         AL

[5 rows x 5 columns]

Щоб пояснити дещо тривалий вираз:

(?P<fips>\d{5})
  • Збігає п’ять цифр ( \d) і називає їх "fips".

Наступна частина:

((?P<state>[A-Z ]*$)|(?P<county>.*?), (?P<state_code>[A-Z]{2}$))

Чи робить (або |) одну з двох речей:

(?P<state>[A-Z ]*$)
  • Збігає будь-яке число ( *) великих літер або пробілів ( [A-Z ]) і називає це "state"до кінця рядка ( $),

або

(?P<county>.*?), (?P<state_code>[A-Z]{2}$))
  • відповідає нічого іншого (.* ), то
  • кома і пробіл тоді
  • відповідає двозначній цифрі state_codeдо кінця рядка ( $).

У прикладі:
Зауважте, що перші два ряди потрапляють у "стан" (залишаючи NaN у стовпцях округу та state_code), а останні три - у коду округу, state_code (залишаючи NaN у стовпці стану).


Це, безумовно, найкраще рішення, але це може бути трохи непосильним для деяких з дуже обширним регулярним виразом. Чому б не зробити це як частина 2 і мати частину 1 лише з фіксами та стовпцями рядків?
Столики маленького

2
@josh, це хороший момент, хоча окремі частини регулярного виразів "легко" зрозуміти, тривалий регулярний вираз може швидко ускладнитися. Я додав пояснення для майбутніх читачів! (Я також повинен був оновити посилання на документи, що пояснює (?P<label>...)синтаксис! Я не маю уявлення, чому я пішов на більш складний регулярний вираз, явно простий міг працювати хмммм
Енді Хейден,

1
Виглядає набагато привітніше. Я радий, що ти це зробив, бо змусив мене подивитися на документи, щоб зрозуміти <group_name>. Тепер я знаю, що це робить мій код дуже лаконічним.
Столики маленького


23

Якщо ви не хочете створити новий кадр даних або якщо у вашому кадрі даних є більше стовпців, ніж лише ті, які ви хочете розділити, ви можете:

df["flips"], df["row_name"] = zip(*df["row"].str.split().tolist())
del df["row"]  

1
Я отримую zip argument #1 must support iterationпомилку, python 2.7
Allan Ruin

20

Ви можете використовувати str.splitпробіл (проміжник за замовчуванням) та параметр expand=Trueдля для DataFrameпризначення нових стовпців:

df = pd.DataFrame({'row': ['00000 UNITED STATES', '01000 ALABAMA', 
                           '01001 Autauga County, AL', '01003 Baldwin County, AL', 
                           '01005 Barbour County, AL']})
print (df)
                        row
0       00000 UNITED STATES
1             01000 ALABAMA
2  01001 Autauga County, AL
3  01003 Baldwin County, AL
4  01005 Barbour County, AL



df[['a','b']] = df['row'].str.split(n=1, expand=True)
print (df)
                        row      a                   b
0       00000 UNITED STATES  00000       UNITED STATES
1             01000 ALABAMA  01000             ALABAMA
2  01001 Autauga County, AL  01001  Autauga County, AL
3  01003 Baldwin County, AL  01003  Baldwin County, AL
4  01005 Barbour County, AL  01005  Barbour County, AL

Якщо потрібно, вилучіть початковий стовпець за допомогою DataFrame.pop

df[['a','b']] = df.pop('row').str.split(n=1, expand=True)
print (df)
       a                   b
0  00000       UNITED STATES
1  01000             ALABAMA
2  01001  Autauga County, AL
3  01003  Baldwin County, AL
4  01005  Barbour County, AL

Що таке:

df[['a','b']] = df['row'].str.split(n=1, expand=True)
df = df.drop('row', axis=1)
print (df)

       a                   b
0  00000       UNITED STATES
1  01000             ALABAMA
2  01001  Autauga County, AL
3  01003  Baldwin County, AL
4  01005  Barbour County, AL

Якщо ви отримаєте помилку:

#remove n=1 for split by all whitespaces
df[['a','b']] = df['row'].str.split(expand=True)

ValueError: Стовпці повинні бути такої ж довжини, як і ключові

Ви можете перевірити, і він поверне 4 колонки DataFrame, а не лише 2:

print (df['row'].str.split(expand=True))
       0        1        2     3
0  00000   UNITED   STATES  None
1  01000  ALABAMA     None  None
2  01001  Autauga  County,    AL
3  01003  Baldwin  County,    AL
4  01005  Barbour  County,    AL

Потім розчин додають нові DataFrameпо join:

df = pd.DataFrame({'row': ['00000 UNITED STATES', '01000 ALABAMA', 
                           '01001 Autauga County, AL', '01003 Baldwin County, AL', 
                           '01005 Barbour County, AL'],
                    'a':range(5)})
print (df)
   a                       row
0  0       00000 UNITED STATES
1  1             01000 ALABAMA
2  2  01001 Autauga County, AL
3  3  01003 Baldwin County, AL
4  4  01005 Barbour County, AL

df = df.join(df['row'].str.split(expand=True))
print (df)

   a                       row      0        1        2     3
0  0       00000 UNITED STATES  00000   UNITED   STATES  None
1  1             01000 ALABAMA  01000  ALABAMA     None  None
2  2  01001 Autauga County, AL  01001  Autauga  County,    AL
3  3  01003 Baldwin County, AL  01003  Baldwin  County,    AL
4  4  01005 Barbour County, AL  01005  Barbour  County,    AL

Видаліть оригінальний стовпець (якщо є й інші стовпці):

df = df.join(df.pop('row').str.split(expand=True))
print (df)
   a      0        1        2     3
0  0  00000   UNITED   STATES  None
1  1  01000  ALABAMA     None  None
2  2  01001  Autauga  County,    AL
3  3  01003  Baldwin  County,    AL
4  4  01005  Barbour  County,    AL   

8

Якщо ви хочете розділити рядок на більш ніж два стовпчики на основі роздільника, ви можете опустити параметр "максимальний розкол".
Ви можете використовувати:

df['column_name'].str.split('/', expand=True)

Це автоматично створить стільки стовпців, скільки максимальна кількість полів, включених у будь-який ваш початковий рядок.


6

Здивований, я ще цього не бачив. Якщо вам потрібні лише два розколи, настійно рекомендую. . .

Series.str.partition

partition виконує один розкол на сепараторі і, як правило, досить виконавський.

df['row'].str.partition(' ')[[0, 2]]

       0                   2
0  00000       UNITED STATES
1  01000             ALABAMA
2  01001  Autauga County, AL
3  01003  Baldwin County, AL
4  01005  Barbour County, AL

Якщо вам потрібно перейменувати рядки,

df['row'].str.partition(' ')[[0, 2]].rename({0: 'fips', 2: 'row'}, axis=1)

    fips                 row
0  00000       UNITED STATES
1  01000             ALABAMA
2  01001  Autauga County, AL
3  01003  Baldwin County, AL
4  01005  Barbour County, AL

Якщо вам потрібно приєднати це до оригіналу, використовуйте joinабо concat:

df.join(df['row'].str.partition(' ')[[0, 2]])

pd.concat([df, df['row'].str.partition(' ')[[0, 2]]], axis=1)

                        row      0                   2
0       00000 UNITED STATES  00000       UNITED STATES
1             01000 ALABAMA  01000             ALABAMA
2  01001 Autauga County, AL  01001  Autauga County, AL
3  01003 Baldwin County, AL  01003  Baldwin County, AL
4  01005 Barbour County, AL  01005  Barbour County, AL

0

Я вважаю за краще експортувати відповідні серії панд (тобто потрібні мені стовпці), використовуючи функцію застосувати, щоб розділити вміст стовпця на кілька рядів, а потім приєднати створені стовпці до існуючої DataFrame. Звичайно, стовпчик джерела слід видалити.

напр

 col1 = df["<col_name>"].apply(<function>)
 col2 = ...
 df = df.join(col1.to_frame(name="<name1>"))
 df = df.join(col2.toframe(name="<name2>"))
 df = df.drop(["<col_name>"], axis=1)

Для розділення двох слів функція рядків повинна бути приблизно такою:

lambda x: x.split(" ")[0] # for the first element
lambda x: x.split(" ")[-1] # for the last element

0

Я бачив, що ніхто не використовував метод скибочки, тому тут я поклав свої 2 центи.

df["<col_name>"].str.slice(stop=5)
df["<col_name>"].str.slice(start=6)

Цей метод створить два нові стовпці.


Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.