Bir sütun iki sütuna nasıl bölünür?


197

Bir sütun ile bir veri çerçevesi var ve ben bir sütun başlığı ' fips've diğeri ile iki sütuna bölmek istiyorum'row'

Veri çerçevem dfşöyle:

          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[:]Satır hücresini bölme hedefime ulaşmak için nasıl kullanacağımı bilmiyorum . Kullanabileceğim df['fips'] = helloyeni bir sütun eklemek ve bunu doldurmak hello. Herhangi bir fikir?

         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
Verilerinizi pandalara nasıl yüklediniz? Verileri istediğiniz biçimde read_table()veya read_fwf()
zach

Yanıtlar:


140

Daha iyi bir yol olabilir, ama bu bir yaklaşım:

                            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 () öğesinin sahip olduğunuz tüm dizinleri kaldıracağını unutmayın, bu nedenle yeni Veri Çerçeveniz 0'dan yeniden dizine eklenecektir (Özel durumunuzda önemli değildir).
Mart'ta Crashthatch

10
@Crashthatch - sonra tekrar ekleyebilirsiniz index = df.indexve iyisiniz .
kök

bir hücre bölünemezse ne olur?
Nisba

@Nisba: Herhangi bir hücre bölünemezse (örneğin, dize bu durum için boşluk içermiyorsa) yine de çalışır ancak bölünmenin bir kısmı boş olur. Herhangi bir sayı türü içeren en az bir hücre içeren sütunda karışık türler olması durumunda diğer durumlar ortaya çıkar. Daha sonra splityöntem NaN döndürür ve tolistyöntem bu değeri (NaN) olarak döndürür (sonuçta ValueErrorbu sorunun üstesinden gelmek için bölmeden önce dize türüne atabilirsiniz). Kendi başınıza denemenizi tavsiye ederim en iyi öğrenme yolu :-)
Nerxis

@techkuz: Eğer sizin de emin misin dfsahiptir rowsütun başlığını? Bunun bir çeşit DataFrame özniteliği olduğunu düşünebilirsiniz, ancak bu, sütunun adıdır. Sütun başlıklarınızı nasıl oluşturacağınız ve tanımlayacağınız size bağlıdır, bu nedenle farklı bir başlık kullanıyorsanız (örn. df.my_column_name.split(...)) Kullanın .
Nerxis

392

TL; DR versiyonu:

Basit bir durum için:

  • Sınırlayıcı içeren bir metin sütunum var ve iki sütun istiyorum

En basit çözüm:

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

Veya bölmenin her girişi için otomatik olarak aşağıdakileri içeren bir sütun içeren bir DataFrame oluşturabilirsiniz:

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

Sen kullanmalısınız expand=TrueDizeleriniz böler bir düzgün olmayan numarasına sahip ve isterseniz Noneeksik değerleri değiştirmek için.

Her iki durumda da, .tolist()yöntemin nasıl gerekli olmadığına dikkat edin . İkisi de değil zip().

Detayda:

Andy Hayden'ın çözümü , str.extract()yöntemin gücünü göstermede en mükemmel çözümdür .

Ancak bilinen bir ayırıcı üzerinde basit bir bölünme için (örneğin, tire ile bölme veya boşlukla bölme), .str.split()yöntem yeterlidir 1 . Dize sütunu (Seri) üzerinde çalışır ve bir liste sütunu (Seri) döndürür:

>>> 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: İlk iki parametrenin ne yapacağından emin değilseniz , yöntemin düz Python sürümü.str.split() için dokümanları öneririm .

Ama nasıl gidiyorsun:

  • iki elemanlı listeler içeren bir sütun

için:

  • her biri listelerin ilgili öğesini içeren iki sütun?

.strBir sütunun özelliğine daha yakından bakmamız gerekiyor .

Bir sütundaki her öğeyi dize olarak ele alan yöntemleri toplamak ve ardından her öğedeki ilgili yöntemi mümkün olduğunca verimli uygulamak için kullanılan büyülü bir nesnedir:

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

Ancak, bir dizenin her öğesini dizinine göre almak için bir "dizinleme" arayüzüne de sahiptir:

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

0    A
1    A
Name: AB, dtype: object

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

0    1
1    2
Name: AB, dtype: object

Tabii ki, bu indeksleme arayüzü, indeksleyebildiği .strher öğenin aslında bir dize olup olmadığını, umursamazsa gerçekten umursamaz, bu yüzden:

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

Ardından, Python grubunun tekrar tekrar açılmasını sağlamak basit bir konudur

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

Tabii ki, bir DataFrame'i bir dize sütununu bölmekten çıkarmak o kadar kullanışlıdır ki, .str.split()yöntem expand=Trueparametre ile sizin için yapabilir :

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

    0   1
0  A1  B1
1  A2  B2

Yani, istediğimizi gerçekleştirmenin başka bir yolu da:

>>> 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=TrueVersiyonu, bununla birlikte daha uzun, demet açma yöntemi üzerinde belirgin bir avantajı vardır. Demet açma, farklı uzunluklardaki bölünmelerle iyi başa çıkmaz:

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

Ancak yeterli "bölünme" olmayan sütunları expand=Trueyerleştirerek güzel bir şekilde işler 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 Bölmedeki '1' nin anlamı nedir ('', 1)?
Hariprasad

@Hariprasad, maksimum bölme sayısı. İlk iki parametreyi Pandas belgelerinden daha iyi açıklayan yöntemin Python Sürümü.split() için belgelere bir bağlantı ekledim .
LeoRochael

5
pandas 1.0.0 raporları "FutureWarning: Karakterler üzerinde sütunsal yineleme gelecekteki sürümlerde kullanımdan kaldırılacak."
Frank

1
Bu Python 1.0.1 altında çalışır. df.join(df['AB'].str.split('-', 1, expand=True).rename(columns={0:'A', 1:'B'}))
Martien Lubberink

59

Şunları yapabilirsiniz ayıklamak oldukça düzgün regex desen kullanılarak farklı bölümlerini:

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]

Biraz uzun regex'i açıklamak için:

(?P<fips>\d{5})
  • Beş basamağı ( \d) eşleştirir ve adlandırır "fips".

Sonraki bölüm:

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

|İki şeyden birini ( ) yapar:

(?P<state>[A-Z ]*$)
  • Herhangi bir sayıda ( *) büyük harf veya boşluk ( [A-Z ]) ile eşleşir ve bunu "state"dizenin ( $) sonundan önce adlandırır ,

veya

(?P<county>.*?), (?P<state_code>[A-Z]{2}$))
  • başka bir şeyle eşleşir ( .*)
  • o zaman virgül ve boşluk
  • state_codedizenin ( $) sonundan önceki iki rakamla eşleşir .

Örnekte:
İlk iki satırın "eyalet" e (ilçe ve eyalet_kodu sütunlarında NaN bırakarak), son üç satır ilçeye, eyalet_koduna (NaN'yi eyalet sütununda bırakarak) çarptığına dikkat edin.


Bu kesinlikle en iyi çözümdür ama çok geniş regex ile bazılarına biraz ezici olabilir. Neden bunu bir bölüm 2 olarak yapmıyorsunuz ve sadece fips ve satır sütunlarıyla bölüm 1 var?
Little Bobby Tables

2
@josh bu iyi bir nokta, regex'in münferit kısımlarının anlaşılması "kolay" iken, uzun regex hızla karmaşıklaşabilir. Gelecekteki okuyucular için bazı açıklamalar ekledim! (Ayrıca (?P<label>...)sözdizimini açıklayan belgelere olan bağlantıyı da güncellemek zorunda kaldım ! Daha karmaşık regex için neden gittiğime dair hiçbir fikrim yok, açıkça basit olan hmmmm çalışabilir
Andy Hayden

1
Çok dostça görünüyor. Yaptığın için memnunum çünkü beni anlamak için belgelere bakmamı sağladı <group_name>. Şimdi kodumu çok özlü hale getirdiğini biliyorum.
Little Bobby Tables


23

Yeni bir veri çerçevesi oluşturmak istemiyorsanız veya veri çerçevenizde yalnızca bölmek istediğiniz sütunlardan daha fazla sütun varsa şunları yapabilirsiniz:

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

1
Bir zip argument #1 must support iterationhata alıyorum, python 2.7
Allan Ruin

20

Kullanabilirsiniz str.split boşluk (varsayılan ayırıcı) ve parametresi tarafından expand=Trueiçin DataFrameyeni sütunlara ata ile:

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

Orijinal sütunu kaldırmanız gerekiyorsa değişiklik 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

Neye benziyor:

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

Hata alırsanız:

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

ValueError: Sütunlar anahtarla aynı uzunlukta olmalıdır

Kontrol edebilir ve 4 sütun döndürür DataFrame sadece 2 değil :

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

Sonra çözüm DataFrametarafından yeni eklenirjoin :

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

Orijinal sütunu kaldır ile (başka bir sütun da varsa):

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

Bir dizeyi ayırıcıya dayalı olarak ikiden fazla sütuna bölmek istiyorsanız, 'maksimum bölünmeler' parametresini atlayabilirsiniz.
Kullanabilirsiniz:

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

Bu, otomatik olarak ilk dizelerinizdeki maksimum alan sayısı kadar sütun oluşturacaktır.


6

Henüz bunu görmedim şaşırttı. Sadece iki bölmeye ihtiyacınız varsa , kesinlikle tavsiye ederim. . .

Series.str.partition

partition ayırıcı üzerinde bir bölme gerçekleştirir ve genellikle oldukça performanslıdır.

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

Satırları yeniden adlandırmanız gerekirse,

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

Bunu orijinaline geri eklemeniz gerekiyorsa, joinveya öğesini kullanın 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

Sütun içeriğini birden çok seriye bölmek ve sonra oluşturulan sütunları mevcut DataFrame'e katılmak için uygula işlevini kullanarak karşılık gelen pandalar serisini (yani ihtiyacım olan sütunları) dışa aktarmayı tercih ederim . Tabii ki, kaynak sütun kaldırılmalıdır.

Örneğin

 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)

İki kelimeyi bölmek için dizeler işlevi şöyle olmalıdır:

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

0

Kimsenin dilim yöntemini kullanmadığını gördüm, bu yüzden buraya 2 sentimi koydum.

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

Bu yöntem iki yeni sütun oluşturur.


Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.