I am trying to convert Race or Ethnicity values into a numeric code for them. For example, "White" would equal "0" , and "American Indian" would equal "1" , and "Latino" would equal "2", and so on and so forth.
I attached a screenshot and inbedded a photo below, that shows my attempt to do this, but I failed miserably. I've been looking online for over 1.5 hours now trying to find an answer or similar example I could go off of but have had no luck.
Solved! Go to Solution.
Looks like you've got some basic syntax problems in your code.
To start with, python is indentation-based, and if/elif/else groups should all share the same indentation level. The actions inside those if/elif/else conditions are one indentation level down from there. Also, you do your condition, then your action, like so:
if condition:
# do stuff
elif other_condition:
# do other stuff
else:
# do default stuff
Second, the field-names-with-exclamation-points thing isn't actually valid python. It's a weird choice ESRI made with the outer layer of the interpreter and is only valid in the function call. It will always throw an error if you put it in the code block. This is one of my many gripes with the implementation of Field Calculator.
Lastly, this could be done quite a bit more simply with a list or dictionary lookup.
Try this code in the function call line:
GetRaceCode(!USER_Race!)
And then this code in the Code Block:
def GetRaceCode(string_value):
# I took the order you used, but it honestly looks scrambled. Make sure
# to change any numbers that are wrong. If they're all correct and in
# order, and the duplicates are separate, then this technically could've
# been done with a list. But I'm going with a dictionary for simplicity
# of editing, for you.
options = {'White': 0,
'American Indian': 1,
'Latino': 2,
'No Response': 3,
'____ does not know': 4,
'____ asked, but has not provided': 5,
'Black or African American': 6,
'Other': 7,
'Black': 8,
'Asian': 9,
'Hawaiian': 10,
'Native Hawaiian or Other Pacific Islander': 11,
}
# First, check to see if it's a valid, and accepted entry.
# If so, pull it from the list above, and grab the value we said it was.
# Dictionary calls in Python are formatted as dictionary_name[lookup_key]
if string_value in options:
return options[string_value]
else:
# NOTE: Zero is also your code for White. Are you sure you want the
# failsafe option to match one of the selections? If not, change
# this number to something not in the dictionary above.
return 0
Looks like you've got some basic syntax problems in your code.
To start with, python is indentation-based, and if/elif/else groups should all share the same indentation level. The actions inside those if/elif/else conditions are one indentation level down from there. Also, you do your condition, then your action, like so:
if condition:
# do stuff
elif other_condition:
# do other stuff
else:
# do default stuff
Second, the field-names-with-exclamation-points thing isn't actually valid python. It's a weird choice ESRI made with the outer layer of the interpreter and is only valid in the function call. It will always throw an error if you put it in the code block. This is one of my many gripes with the implementation of Field Calculator.
Lastly, this could be done quite a bit more simply with a list or dictionary lookup.
Try this code in the function call line:
GetRaceCode(!USER_Race!)
And then this code in the Code Block:
def GetRaceCode(string_value):
# I took the order you used, but it honestly looks scrambled. Make sure
# to change any numbers that are wrong. If they're all correct and in
# order, and the duplicates are separate, then this technically could've
# been done with a list. But I'm going with a dictionary for simplicity
# of editing, for you.
options = {'White': 0,
'American Indian': 1,
'Latino': 2,
'No Response': 3,
'____ does not know': 4,
'____ asked, but has not provided': 5,
'Black or African American': 6,
'Other': 7,
'Black': 8,
'Asian': 9,
'Hawaiian': 10,
'Native Hawaiian or Other Pacific Islander': 11,
}
# First, check to see if it's a valid, and accepted entry.
# If so, pull it from the list above, and grab the value we said it was.
# Dictionary calls in Python are formatted as dictionary_name[lookup_key]
if string_value in options:
return options[string_value]
else:
# NOTE: Zero is also your code for White. Are you sure you want the
# failsafe option to match one of the selections? If not, change
# this number to something not in the dictionary above.
return 0
Instead of:
if string_value in options:
return options[string_value]
else:
return 0
You can use:
options.get(string_value, 0) # or replace 0 with preferred default value
Clever! Somehow I've never encountered/used this approach, and I love it. Definitely saving for the future.
My screenshot below should work correctly. If you're writing your number values to a string field, then make sure to put quotes around the numbers.
I don't know how to properly explain it, but your Code Block cannot "see" your fields. You can't directly reference them using !Field_Name! syntax. Instead, you have to pass those fields to it from the line above. And then you reference your fields that way. Hopefully my screenshot will help explain it.
From there, you just have your if statements to calculate your values. And then at the very end, you need to return the value of "Race_Code" so it can calculate value in your table.
Edit: @MErikReedAugusta replied as I was typing my response and didn't see it until after I posted. Their method is more elegant and better than mine lol.
Thank you Ryan for the help. Screenshots are the best!! Even though I didn't select yours as the solution, your suggestion is still an MVP!! ha . Have a good day!
If you don't actually care about the specific codes assigned to the values in that column, and just want to map specific string values to an integer, you can use a generic solution like this:
CODES: list[str] = []
def GetCode(value: str) -> int:
# Pass Null (You can replace None with a default value like -1)
if not value:
return None
if value not in CODES:
CODES.append(value)
return CODES.index(value)
This just creates a running list of all the string values it finds and uses the list index of the string as the return value.
This way you don't need to create a mapping of all possible values and can just let Python do it for you.
There is a tutorial that includes a simple example of how to conditionally calculate values in one field based on values in another:
Thank you for that link Bob, I saved it in my notes and bookmarked it.