Подтвердить что ты не робот

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

У меня есть кадр данных с одним столбцом, и я хотел бы разбить его на два столбца с одним заголовком столбца как 'fips', а другой 'row'

Мой dataframe 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
4b9b3361

Ответ 1

Там может быть лучший способ, но это здесь один подход:

In [34]: import pandas as pd

In [35]: df
Out[35]: 
                        row
0       00000 UNITED STATES
1             01000 ALABAMA
2  01001 Autauga County, AL
3  01003 Baldwin County, AL
4  01005 Barbour County, AL

In [36]: df = pd.DataFrame(df.row.str.split(' ',1).tolist(),
                                   columns = ['flips','row'])

In [37]: df
Out[37]: 
   flips                 row
0  00000       UNITED STATES
1  01000             ALABAMA
2  01001  Autauga County, AL
3  01003  Baldwin County, AL
4  01005  Barbour County, AL

Ответ 2

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. Он работает со столбцом (Series) строк и возвращает столбец (Series) списков:

>>> 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

Ответ 3

Вы можете extract разделить детали довольно аккуратно с помощью шаблона регулярного выражения:

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 в столбцах county и state_code), в то время как последние три попадают в графство state_code (оставляя NaN в столбце состояния).

Ответ 4

df[['fips', 'row']] = df['row'].str.split(' ', n=1, expand=True)

Ответ 5

Если вы не хотите создавать новый фреймворк данных, или если в вашем фрейме данных больше столбцов, чем только те, которые вы хотите разбить, вы можете:

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

Ответ 6

Вы можете использовать str.split с 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   

Ответ 7

Если вы хотите разбить строку на более чем два столбца на основе разделителя, вы можете опустить параметр "максимальные разбиения".
Ты можешь использовать:

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

Это автоматически создаст столько столбцов, сколько максимальное количество полей включено в любую из ваших исходных строк.

Ответ 8

Удивлен, я еще не видел этого. Если вам нужно только два сплита, я настоятельно рекомендую. , ,

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

Ответ 9

Я предпочитаю экспортировать соответствующие серии панд (т.е. нужные мне столбцы), используя функцию apply, чтобы разбить содержимое столбцов на несколько серий, а затем присоединить сгенерированные столбцы к существующему 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

Ответ 10

Я видел, что никто не использовал метод среза, поэтому здесь я положил свои 2 цента здесь.

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

Этот метод создаст два новых столбца.