pandas – 特定の条件で連結するPython

okwaves2024-01-25  8

編集済み

文字列の連結に関する条件を含む If ループを作成したいと考えています。 つまり、セル A1 に特定の形式のテキストが含まれている場合は、連結のみを行い、それ以外の場合はそのままにしておきます。

例: 請求書番号が CM2/0000/ のような場合は、この文字列を日付列 (月 - 年) と連結します。それ以外の場合は、請求書番号をそのままにしておきます。

サンプルデータ

サンプル データを使用して投稿を更新してください。辞書からデータフレームを作成できます。

– マイク67

2020 年 9 月 5 日 2:22

コード、データ、エラー メッセージは画像ではなく常にテキストとして配置してください

– フラス

2020 年 9 月 5 日 16:40



------------------------

必要なことを行う関数を作成し、 df.apply() を使用してそれをすべての行で実行できます。

@Boomer の回答からのサンプル データを使用します。

編集: dataframe に実際にあるものを示していませんでした。bil_date に datetime があるようですが、文字列を使用しました。これをどのように扱うかを示すために、文字列を日時に変換する必要がありました。そして今、それは必要です.str[3:].str.replace('/','-') の代わりに .strftime('%m-%y') または .dt.strftime('%m-%y') を使用します。パンダは国ごとに異なる形式で dateitm を表示するため、str(x) を使用すると、15/09/19 ではなく 2019-09-15 00:00:00 が表示されるためです。

import pandas as pd

df = pd.DataFrame({
    'bill_number': ['CM2/0000/', 'CM2/0000', 'CM3/0000/', 'CM3/0000'],
    'bill_date': ['15/09/19', '15/09/19', '15/09/19', '15/09/19']
})
df['bill_date'] = pd.to_datetime(df['bill_date'])

def convert(row):
    if row['bill_number'].endswith('/'):
        #return row['bill_number'] + row['bill_date'].str[3:].replace('/','-')
        return row['bill_number'] + row['bill_date'].strftime('%m-%y')
    else:
        return row['bill_number']

df['bill_number'] = df.apply(convert, axis=1)

print(df)

結果:

      bill_number bill_date
0  CM2/0000/09-19  15/09/19
1        CM2/0000  15/09/19
2  CM3/0000/09-19  15/09/19
3        CM3/0000  15/09/19

2 番目のアイデアは、マスクを作成することです

 mask = df['bill_number'].str.endswith('/')

その後、すべての値にそれを使用します

 #df.loc[mask,'bill_number'] = df[mask]['bill_number'] + df[mask]['bill_date'].str[3:].str.replace('/','-')
 df.loc[mask,'bill_number'] = df[mask]['bill_number'] + df[mask]['bill_date'].dt.strftime('%m-%y')

または

 #df.loc[mask,'bill_number'] = df.loc[mask,'bill_number'] + df.loc[mask,'bill_date'].str[3:].str.replace('/','-')
 df.loc[mask,'bill_number'] = df.loc[mask,'bill_number'] + df.loc[mask,'bill_date'].dt.strftime('%m-%y')

左側では、値を正しく割り当てるために `[mask]['bill_number'] の代わりに .loc[mask,'bill_number'] が必要ですが、右側ではその必要がありません。

import pandas as pd

df = pd.DataFrame({
    'bill_number': ['CM2/0000/', 'CM2/0000', 'CM3/0000/', 'CM3/0000'],
    'bill_date': ['15/09/19', '15/09/19', '15/09/19', '15/09/19']
})
df['bill_date'] = pd.to_datetime(df['bill_date'])

mask = df['bill_number'].str.endswith('/')

#df.loc[mask,'bill_number'] = df[mask]['bill_number'] + df[mask]['bill_date'].str[3:].str.replace('/','-')
# or
#df.loc[mask,'bill_number'] = df.loc[mask,'bill_number'] + df.loc[mask,'bill_date'].str[3:].str.replace('/','-')

df.loc[mask,'bill_number'] = df[mask]['bill_number'] + df[mask]['bill_date'].dt.strftime('%m-%y')
#or
#df.loc[mask,'bill_number'] = df.loc[mask,'bill_number'] + df.loc[mask,'bill_date'].dt.strftime('%m-%y')

print(df)

3 番目のアイデアは、numpy.where() を使用することです

import pandas as pd
import numpy as np

df = pd.DataFrame({
    'bill_number': ['CM2/0000/', 'CM2/0000', 'CM3/0000/', 'CM3/0000'],
    'bill_date': ['15/09/19', '15/09/19', '15/09/19', '15/09/19']
})
df['bill_date'] = pd.to_datetime(df['bill_date'])

df['bill_number'] = np.where(
                       df['bill_number'].str.endswith('/'), 
                       #df['bill_number'] + df['bill_date'].str[3:].str.replace('/','-'), 
                       df['bill_number'] + df['bill_date'].dt.strftime('%m-%y'), 
                       df['bill_number'])

print(df)

3

これらの回答のうち 2 つを試しましたが、def (row) の回答では次のエラーが発生しました: TypeError: ("'Timestamp' object is not subscriptable", 'occurred atindex 0' ;) そして、np.where アプローチを試してみたところ、次のエラーが発生しました: AttributeError: Can Only use .str accessor with string names, that use np.object_ dtype in pandas

– サナ・シャー

2020 年 9 月 5 日 16:15

問題はそれです質問に実際のデータが示されていませんでした。エラーは、列 bill_date にタイムスタンプがあることを示していますが、文字列しかありません。コードをテストするには、文字列を日時に変換する必要があります。df[' の代わりに row['bill_date'].strftime('%m-%y') が必要のようです。 ;請求日'].str[3:].str.replace('/','-')

– フラス

2020 年 9 月 5 日 16:56

回答の例を変更しました。文字列の代わりに日時を使用するようになりました。

– フラス

2020 年 9 月 5 日 17:11



------------------------

おそらくこれはあなたにとってうまくいくでしょう。 @Mike67 が述べていたようなデータサンプルがあればいいですね。しかし、あなたの情報に基づいて、これが私が思いついたものです。かさばりますが、機能します。きっと他の誰かがもっと派手なバージョンを作ってくれると思います。

import pandas as pd
from pandas import DataFrame, Series

dat = {'num': ['CM2/0000/','CM2/0000', 'CM3/0000/', 'CM3/0000',],
    'date': ['15/09/19','15/09/19','15/09/19','15/09/19']}
df = pd.DataFrame(dat)

df['date'] = df['date'].map(lambda x: str(x)[3:])
df['date'] = df['date'].str.replace('/','-')

for cols in df.columns:
df.loc[df['num'].str.endswith('/'), cols] = df['num'] + df['date']

print(df)

Results:
              num   date
0  CM2/0000/09-19  09-19
1        CM2/0000  09-19
2  CM3/0000/09-19  09-19
3        CM3/0000  09-19

総合生活情報サイト - OKWAVES
総合生活情報サイト - OKWAVES
生活総合情報サイトokwaves(オールアバウト)。その道のプロ(専門家)が、日常生活をより豊かに快適にするノウハウから業界の最新動向、読み物コラムまで、多彩なコンテンツを発信。