列を2つの列に分割する方法は?


196

私は1つの列を有するデータフレームを持っていると私は1つの列'としてヘッダと2つの列に分割したい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
どのようにデータをパンダにロードしましたか?read_table()または read_fwf()
zach

回答:


136

より良い方法があるかもしれませんが、これは1つのアプローチです。

                            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から再作成されることに注意してください(特定のケースでは問題ありません)。
クラッシュサッチ2013年

10
@Crashthatch-もう一度追加するだけで問題index = df.indexありません。
ルート

1つのセルを分割できない場合はどうなりますか?
Nisba 2018年

@Nisba:セルを分割できない場合(たとえば、この場合、文字列にスペースが含まれていない場合)は機能しますが、分割の一部が空になります。他の状況は、列にタイプが混在していて、任意の数値タイプを含むセルが少なくとも1つある場合に発生します。次に、splitメソッドはNaNを返し、tolistメソッドはこの値をそのまま(NaN)で返しますValueError(この問題を解決するには、分割する前に文字列型にキャストできます)。自分で試してみることをお勧めします:-)
Nerxis

@techkuz:あなたdfはあなたがrow列ヘッダーを持っていますか?ある種のDataFrame属性だと思うかもしれませんが、これが列の名前であることは明らかです。列ヘッダーをどのように作成および定義するかはあなた次第なので、別のものを使用する場合はそれを使用してください(例:)df.my_column_name.split(...)
Nerxis

388

TL; DRバージョン:

単純な場合:

  • 区切り文字付きのテキスト列があり、2つの列が欲しい

最も簡単な解決策は次のとおりです。

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

または、次のようにして、スプリットのエントリごとに1列のデータフレームを自動的に作成できます。

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:最初の2つのパラメーターの内容がわからない場合は、メソッドのプレーンPythonバージョンの.str.split()ドキュメントをお勧めします。

しかし、どうやって行くのですか:

  • 2要素のリストを含む列

に:

  • リストのそれぞれの要素を含む2つの列?

さて、私たちはを詳しく見る必要があります .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=TrueNone十分な「スプリット」がない列に配置することで、うまく処理します。

>>> 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 split( ''、1)の「1」の意味は何ですか?
Hariprasad 2017年

@Hariprasad、それは分割の最大数です。最初の2つのパラメーターをPandasのドキュメントよりも詳しく説明するメソッドのPythonバージョンのドキュメント.split()へのリンクを追加しました。
LeoRochael 2017年

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})
  • 5桁(\d)に一致し、名前を付けます"fips"

次の部分:

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

|の2つのいずれかを行います():

(?P<state>[A-Z ]*$)
  • *大文字またはスペース([A-Z ])の任意の数()に一致し、これ"state"に文字列の最後($)の前に名前を付けます。

または

(?P<county>.*?), (?P<state_code>[A-Z]{2}$))
  • それ以外のもの(.*)に一致します
  • カンマとスペース
  • state_code文字列の最後の2桁に一致します($)。

この例
では、最初の2行が「state」にヒットし(countyとstate_code列にNaNが残る)、最後の3行が郡にヒットし、state_code(state列にNaNが残っている)ことに注意してください。


これは間違いなく最良のソリューションですが、非常に広範な正規表現を使用している人にとっては、少し圧倒されるかもしれません。それをパート2にして、フィップと行の列だけを含むパート1を作成してみませんか?
リトルボビーテーブル

2
@joshは良い点です。正規表現の個々の部分は「簡単」に理解できますが、長い正規表現はすぐに複雑になる可能性があります。今後の読者向けに説明を追加しました!(私はまた、(?P<label>...)構文を説明するドキュメントへのリンクを更新する必要がありました!なぜもっと複雑な正規表現に行ったのかわかりません。明らかに、単純なものがhmmmm
Andy Hayden

1
とてもフレンドリーに見えます。ドキュメントを見てを理解してもらえたので、喜んでくれました<group_name>。これでコードが非常に簡潔になることがわかりました。
リトルボビーテーブル


22

新しいデータフレームを作成したくない場合、またはデータフレームに分割したい列よりも多くの列がある場合は、次のことができます。

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

1
私が取得zip argument #1 must support iterationエラー、のpython 2.7
アラン遺跡

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:列はキーと同じ長さでなければなりません

チェックするとDataFrame、2だけでなく4カラムが返されます。

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

区切り文字に基づいて文字列を3つ以上の列に分割する場合は、「最大分割」パラメータを省略できます。
以下を使用できます。

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

これにより、初期文字列に含まれるフィールドの最大数と同じ数の列が自動的に作成されます。


6

私はまだこれを見ていません。2つの分割のみが必要な場合は、強くお勧めします。。。

Series.str.partition

partition セパレーターで1つの分割を実行し、通常は非常にパフォーマンスが高い

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

私が使用して、対応するパンダシリーズ(私が必要すなわち列)をエクスポートすることを好む適用する複数の系列に列の内容を分割して、関数を参加し、既存のデータフレームに生成された列を。もちろん、ソース列は削除する必要があります。

例えば

 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)

2つの単語の文字列を分割するには、関数は次のようになります。

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)

このメソッドは、2つの新しい列を作成します。


弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.