Python — Найдите подстроку в строке с помощью оператора IF при повторении фрейма данных pandas с циклом FOR

#python #pandas #dataframe #for-loop #if-statement

Вопрос:

У меня есть фрейм данных, который выглядит так…

                                      Variable
0                         Religion - Buddhism
1                            Source: Clickerz
2                            Religion - Islam
3                            Source: SRZ FREE
4   Ethnicity - Mixed - White amp; Black African
 

Я хочу манипулировать variable столбцом, чтобы создать такой new column , который выглядит следующим образом…

                                         Variable           New Column
    0                         Religion - Buddhism           Buddhism
    1                            Source: Clickerz           Clickerz
    2                            Religion - Islam            Islam
    3                            Source: SRZ FREE            SRZ FREE
    4   Ethnicity - Mixed - White amp; Black African         Mixed - White and Black African
 

Чтобы в конечном итоге у меня был фрейм данных, который выглядит так…

                             Variable                      New Column
    0                       Religion                        Buddhism
    1                         Source                        Clickerz
    2                       Religion                           Islam
    3                         Source                        SRZ FREE
    4                      Ethnicity         Mixed - White and Black African
 

Я хочу выполнить итерацию по Variable столбцу и манипулировать данными для создания New Column . Я планировал использовать несколько if операторов, чтобы найти определенное слово, например 'Ethnicity' , или 'Religion' , а затем применить манипуляцию.

Например…

 For row in df['Variable']:

      if 'Religion' in row:

              df['New Column'] = ...
      
      elif 'Ethnicity' in row:

              df['New Column'] = ...

      elif: 'Source' in row:

              df['New Column'] = ...

      else:

              df['New Column'] = 'Not Applicable'
 

Несмотря type(row) на то, что возвращает 'str' значение, относящееся к строке класса, этот код продолжает возвращать новый столбец как «Неприменимый», что означает, что он не обнаруживает ни одной строки ни в одной из строк во фрейме данных, даже когда я вижу, что они там есть.

Я уверен, что есть простой способ сделать это…ПОЖАЛУЙСТА, ПОМОГИТЕ!

Я также попробовал следующее…

 For row in df['Variable']:

  if row.find('Religion') != -1:

          df['New Column'] = ...

  elif row.find('Ethnicity') != -1:

          df['New Column'] = ...

  elif: row.find('Source') != -1:

          df['New Column'] = ...

  else:

          df['New Column'] = 'Not Applicable'
 

И я продолжаю получать все записи в новой колонке «Неприменимо». И снова он не находит строку в существующем столбце.

Это проблема с типом данных или что-то в этом роде?

Ответ №1:

Вы могли бы использовать вложенный for цикл:

 # For each row in the dataframe
for row in df['column_variable']:
    # Set boolean to indicate if a substring was found
    substr_found = False

    # For each substring
    for sub_str in ["substring1", "substring2"]:
        # If the substring is in the row
        if sub_str in row:
            # Execute code...
            df['new_column'] = ...

            # Substring was found!
            substr_found = True

    # If substring was not found
    if not substr_found:
        # Set invalid code...
        df['new column'] = 'Not Applicable'
 

Ответ №2:

Насколько это возможно, вам следует избегать зацикливания строк при работе с a DataFrame . В этой статье объясняется, какие альтернативы являются более эффективными.

Вы в основном пытаетесь перевести строки на основе некоторой фиксированной карты. Естественно, dict на ум приходит а:

 substring_map = {
    "at": "pseudo-cat",
    "dog": "true dog",
    "bre": "something else",    
    "na": "not applicable"
}
 

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

Логику сопоставления подстрок теперь можно отделить от определения карты:

 def translate_substring(x):
  for substring, new_string in substring_map.items():
    if substring in x:
      return new_string
  return "not applicable"
 

Используйте apply функцию «сопоставление» для создания целевого столбца:

 df = pd.DataFrame({"name":
  ["cat", "dogg", "breeze", "bred", "hat", "misty"]})

df["new_column"] = df["name"].apply(translate_substring)

# df:
#      name      new_column
# 0     cat      pseudo-cat
# 1    dogg        true dog
# 2  breeze  something else
# 3    bred  something else
# 4     hat      pseudo-cat
# 5   misty  not applicable
 

Этот код, примененный к pd.concat([df] * 10000) (60 000 строк), выполняется за 42 мс в записной книжке Colab. Для сравнения, использование iterrows завершается за 3,67 с-ускорение в 87 раз.

Ответ №3:

Вы можете создать пустой список, добавить туда новые значения и создать новый столбец в качестве последнего шага:

 all_data = []
for row in df["column_variable"]:
    if "substring1" in row:
        all_data.append("Found 1")
    elif "substring2" in row:
        all_data.append("Found 2")
    elif "substring3" in row:
        all_data.append("Found 3")
    else:
        all_data.append("Not Applicable")

df["new column"] = all_data

print(df)
 

С принтами:

       column_variable new column
0  this is substring1    Found 1
1  this is substring2    Found 2
2  this is substring1    Found 1
3  this is substring3    Found 3
 

Комментарии:

1. По какой-то причине, когда я набираю…»если» подстрока «в строке:» она не находит подстроку в строке, даже если она явно там. Это и есть главная проблема

2. @ElliottDavey Пожалуйста, отредактируйте свой вопрос с помощью образца вашего фрейма данных.

Ответ №4:

Может быть, самый короткий путь, который я могу придумать:

 #Dummy DataFrame
df = pd.DataFrame([[1,"substr1"],[3,"bla"],[5,"bla"]],columns=["abc","col_to_check"])

substrings = ["substr1","substr2", "substr3"]
content = df["col_to_check"].unique().tolist() # Unique content of column

for subs in substrings: # Go through all your substrings
    if subs in content: # Check if substring is in column
        df[subs] = 0 # Fill your new column with whatever you want
 

Ответ №5:

Обновлено в соответствии с вашим фреймом данных!

 import pandas as pd
 

Ваш Фрейм данных

 lst = []

for i in ['Religion - Buddhism','Source: Clickerz','Religion - Islam','Source: SRZ FREE','Ethnicity - Mixed - White amp; Black African']:
    item = [i]
    lst.append(item)

df = pd.DataFrame.from_records(lst)
df.columns = ['variable']
print(df)
 
                                     variable
0                        Religion - Buddhism
1                           Source: Clickerz
2                           Religion - Islam
3                           Source: SRZ FREE
4  Ethnicity - Mixed - White amp; Black African
 

Использование цикла For и частичного сопоставления строк в сочетании с .loc установкой новых значений

 for x,y in df['variable'].iteritems():
    if 'religion' in y.lower():
        z = y.split('-')
        df.loc[x, 'variable'] = z[0].strip()
        df.loc[x, 'value'] = ''.join(z[1:]).strip()
    if 'source' in y.lower():
        z = y.split(':')
        df.loc[x, 'variable'] = z[0].strip()
        df.loc[x, 'value'] = ''.join(z[1:]).strip()
    if 'ethnicity' in y.lower():
        z = y.split('-')
        df.loc[x, 'variable'] = z[0].strip()
        df.loc[x, 'value'] = ''.join(z[1:]).strip()

print(df)
 
     variable                         value
0   Religion                      Buddhism
1     Source                      Clickerz
2   Religion                         Islam
3     Source                      SRZ FREE
4  Ethnicity  Mixed  White amp; Black African
 

Ответ №6:

Я создал функцию «string_splitter» и применил ее в лямбда-функции, это решило проблему.

Я создал следующую функцию для разделения строк различными способами на основе разных подстрок, содержащихся в ячейке.

 def string_splitter(cell):

word_list1 = ['Age', 'Disability', 'Religion', 'Gender']
word_list2 = ['Number shortlisted', 'Number Hired', 'Number Interviewed']

if any([word in cell for word in word_list1]):
    
    result = cell.split("-")[1]
    result = result.strip()
    
elif 'Source' in cell:
    
    result = cell.split(":")[1]
    result = result.strip()
    
elif 'Ethnicity' in cell:
    
    result_list = cell.split("-")[1:3]
    result = "-".join(result_list)
    result = result.strip()

elif any([word in cell for word in word_list2]):
    
    result = cell.split(" ")[1]
    result = result.strip()

elif 'Number of Applicants' in cell:
    
    result = cell


return result
 

Затем я позвонил string_splitter при использовании лямбда-операции. Это применяло функцию к каждой ячейке по отдельности, поскольку код повторяется по каждой строке указанного столбца в фрейме данных. Как показано ниже:

 df['Answer'] = df['Visual Type'].apply(lambda x: string_splitter(x))
 

string_splitter позволил мне создать New column свое .

Затем я создал другую функцию column_formatter для управления Variable столбцом после New Column того, как он был создан. Вторая функция показана ниже:

 def column_formatter(cell):

word_list1 = ['Age', 'Gender', 'Ethnicity', 'Religion']
word_list2 = ['Number of Applicants', 'Number Hired', 'Number shortlisted', 'Number Interviewed']

if any([word in cell for word in word_list1]):
    
    result = cell.split("-")[0]
    result = result.strip()

elif 'Source' in cell:
    
    result = cell.split(":")[0]
    result = result.strip()

elif 'Disability' in cell:
    
    result = cell.split(" ")[0]
    result = result.strip()

elif any([word in cell for word in word_list2]):
    
    result = 'Number of Applicants'
    
else:
    
    result = 'Something wrong here'


return result
 

А затем вызвал функцию таким же образом, как показано ниже:

 df['Visual Type'] = df['Visual Type'].apply(lambda x: column_formatter(x))