<jupyter_start><jupyter_text>Pop quiz on lambda functionsIn this exercise, you will practice writing a simple lambda function and calling this function. Recall what you know about lambda functions and answer the following questions:1. How would you write a lambda function `add_bangs` that adds three exclamation points `'!!!'` to the end of a string `a`?2. How would you call `add_bangs` with the argument `'hello'`?<jupyter_code>add_bangs = (lambda a: a + '!!!')
add_bangs('hello')<jupyter_output><empty_output><jupyter_text>Writing a lambda function you already knowSome function definitions are simple enough that they can be converted to a lambda function. By doing this, you write less lines of code, which is pretty awesome and will come in handy, especially when you're writing and maintaining big programs. In this exercise, you will use what you know about lambda functions to convert a function that does a simple task into a lambda function. Take a look at this function definition:```def echo_word(word1, echo):    """Concatenate echo copies of word1."""    words = word1 * echo    return words```The function `echo_word` takes 2 parameters: a string value, `word1` and an integer value, `echo`. It returns a string that is a concatenation of `echo` copies of `word1`. Your task is to convert this simple function into a lambda function.Instructions1. Define the lambda function `echo_word` using the variables `word1` and `echo`. Replicate what the original function definition for `echo_word()` does above.2. Call `echo_word()` with the string argument `'hey'` and the value `5`, in that order. Assign the call to `result`.<jupyter_code># Define echo_word as a lambda function: echo_word
echo_word = (lambda word1, echo: word1 * echo)

# Call echo_word: result
result = echo_word('hey', 5)

# Print result
print(result)<jupyter_output>heyheyheyheyhey<jupyter_text>map() and lambda functionsSo far, you've used lambda functions to write short, simple functions as well as to redefine functions with simple functionality. The best use case for lambda functions, however, are for when you want these simple functionalities to be anonymously embedded within larger expressions. What that means is that the functionality is not stored in the environment, unlike a function defined with `def`. To understand this idea better, you will use a lambda function in the context of the `map()` function.Recall from the video that `map()` applies a function over an object, such as a list. Here, you can use lambda functions to define the function that `map()` will use to process the object. For example:```nums = [2, 4, 6, 8, 10]result = map(lambda a: a ** 2, nums)```You can see here that a lambda function, which raises a value a to the power of 2, is passed to `map()` alongside a list of numbers, `nums`. The _map object_ that results from the call to `map()` is stored in `result`. You will now practice the use of lambda functions with `map()`. For this exercise, you will map the functionality of the `add_bangs()` function you defined in previous exercises over a list of strings.Instructions1. In the `map()` call, pass a lambda function that concatenates the string `'!!!'` to a string `item`; also pass the list of strings, `spells`. Assign the resulting map object to `shout_spells`.2. Convert `shout_spells` to a list and print out the list.<jupyter_code># Create a list of strings: spells
spells = ['protego', 'accio', 'expecto patronum', 'legilimens']

# Use map() to apply a lambda function over spells: shout_spells
shout_spells = map(lambda item: item + '!!!', spells)

# Convert shout_spells to a list: shout_spells_list
shout_spells_list = list(shout_spells)

# Print the result
print(shout_spells_list)<jupyter_output>['protego!!!', 'accio!!!', 'expecto patronum!!!', 'legilimens!!!']<jupyter_text>filter() and lambda functionsIn the previous exercise, you used lambda functions to anonymously embed an operation within `map()`. You will practice this again in this exercise by using a lambda function with `filter()`, which may be new to you! The function `filter()` offers a way to filter out elements from a list that don't satisfy certain criteria.Your goal in this exercise is to use `filter()` to create, from an input list of strings, a new list that contains only strings that have more than 6 characters.Instructions1. In the `filter()` call, pass a lambda function and the list of strings, `fellowship`. The lambda function should check if the number of characters in a string member is greater than 6; use the `len()` function to do this. Assign the resulting filter object to `result`.2. Convert `result` to a list and print out the list.<jupyter_code># Create a list of strings: fellowship
fellowship = ['frodo', 'samwise', 'merry', 'pippin', 'aragorn', 'boromir', 'legolas', 'gimli', 'gandalf']

# Use filter() to apply a lambda function over fellowship: result
result = filter(lambda member: len(member) > 6, fellowship)

# Convert result to a list: result_list
result_list = list(result)

# Print result_list
print(result_list)<jupyter_output>['samwise', 'aragorn', 'boromir', 'legolas', 'gandalf']<jupyter_text>reduce() and lambda functionsYou're getting very good at using lambda functions! Here's one more function to add to your repertoire of skills. The `reduce()` function is useful for performing some computation on a list and, unlike `map()` and `filter()`, returns a single value as a result. To use `reduce()`, you must import it from the `functools` module.Remember `gibberish()` from a few exercises back?``` Define gibberishdef gibberish(*args):    """Concatenate strings in *args together."""    hodgepodge = ''    for word in args:        hodgepodge += word    return hodgepodge````gibberish()` simply takes a list of strings as an argument and returns, as a single-value result, the concatenation of all of these strings. In this exercise, you will replicate this functionality by using `reduce()` and a lambda function that concatenates strings together.Instructions1. Import the `reduce` function from the `functools` module.2. In the `reduce()` call, pass a lambda function that takes two string arguments `item1` and `item2` and concatenates them; also pass the list of strings, `stark`. Assign the result to `result`. The first argument to `reduce()` should be the lambda function and the second argument is the list `stark`.<jupyter_code># Import reduce from functools
from functools import reduce

# Create a list of strings: stark
stark = ['robb', 'sansa', 'arya', 'brandon', 'rickon']

# Use reduce() to apply a lambda function over stark: result
result = reduce(lambda item1, item2: item1 + item2, stark)

# Print the result
print(result)<jupyter_output>robbsansaaryabrandonrickon<jupyter_text>Pop quiz about errorsIn the video, Hugo talked about how errors happen when functions are supplied arguments that they are unable to work with. In this exercise, you will identify which function call raises an error and what type of error is raised.Take a look at the following function calls to `len()`:```len('There is a beast in every man and it stirs when you put a sword in his hand.')len(['robb', 'sansa', 'arya', 'eddard', 'jon'])len(525600)len(('jaime', 'cersei', 'tywin', 'tyrion', 'joffrey'))```Which of the function calls raises an error and what type of error is raised? The call `len(525600)` raises a `TypeError`.  Error handling with try-exceptA good practice in writing your own functions is also anticipating the ways in which other people (or yourself, if you accidentally misuse your own function) might use the function you defined.As in the previous exercise, you saw that the `len()` function is able to handle input arguments such as strings, lists, and tuples, but not int type ones and raises an appropriate error and error message when it encounters invalid input arguments. One way of doing this is through exception handling with the `try-except` block.In this exercise, you will define a function as well as use a `try-except` block for handling cases when incorrect input arguments are passed to the function.Recall the `shout_echo()` function you defined in previous exercises; parts of the function definition are provided in the sample code. Your goal is to complete the exception handling code in the function definition and provide an appropriate error message when raising an error.Instructions1. Initialize the variables `echo_word` and `shout_words` to empty strings.2. Add the keywords `try` and `except` in the appropriate locations for the exception handling block.3. Use the `*` operator to concatenate `echo` copies of `word1`. Assign the result to `echo_word`.4. Concatenate the string `'!!!'` to `echo_word`. Assign the result to `shout_words`.<jupyter_code># Define shout_echo
def shout_echo(word1, echo=1):
    """Concatenate echo copies of word1 and three exclamation marks at the end of the string."""

    # Initialize empty strings: echo_word, shout_words
    echo_word = ''
    shout_words = ''
    
    # Add exception handling with try-except
    try:
        # Concatenate echo copies of word1 using *: echo_word
        echo_word = word1 * echo

        # Concatenate '!!!' to echo_word: shout_words
        shout_words = echo_word + '!!!'
    except:
        # Print error message
        print("word1 must be a string and echo must be an integer.")

    # Return shout_words
    return shout_words

# Call shout_echo
shout_echo("particle", echo="accelerator")<jupyter_output>word1 must be a string and echo must be an integer.<jupyter_text>Error handling by raising an errorAnother way to raise an error is by using `raise`. In this exercise, you will add a `raise` statement to the `shout_echo()` function you defined before to raise an error message when the value supplied by the user to the `echo` argument is less than 0.The call to `shout_echo()` uses valid argument values. To test and see how the raise statement works, simply change the value for the `echo` argument to a _negative_ value. Don't forget to change it back to valid values to move on to the next exercise!Instructions1. Complete the `if` statement by checking if the value of `echo` is _less than_ 0.2. In the body of the `if` statement, add a `raise` statement that raises a `ValueError` with message `'echo must be greater than or equal to 0'` when the value supplied by the user to `echo` is less than 0.<jupyter_code># Define shout_echo
def shout_echo(word1, echo=1):
    """Concatenate echo copies of word1 and three exclamation marks at the end of the string."""

    # Raise an error with raise
    if echo < 0:
        raise ValueError('echo must be greater than or equal to 0')

    # Concatenate echo copies of word1 using *: echo_word
    echo_word = word1 * echo

    # Concatenate '!!!' to echo_word: shout_word
    shout_word = echo_word + '!!!'

    # Return shout_word
    return shout_word

# Call shout_echo
shout_echo("particle", echo=5)<jupyter_output><empty_output><jupyter_text>Bringing it all together (1)This is awesome! You have now learned how to write anonymous functions using `lambda`, how to pass lambda functions as arguments to other functions such as `map()`, `filter()`, and `reduce()`, as well as how to write errors and output custom error messages within your functions. You will now put together these learnings to good use by working with a Twitter dataset. Before practicing your new error handling skills,in this exercise, you will write a lambda function and use `filter()` to select retweets, that is, tweets that begin with the string `'RT'`.Instructions1. In the `filter()` call, pass a lambda function and the sequence of tweets as strings, `tweets_df['text']`. The lambda function should check if the first 2 characters in a tweet `x` are 'RT'. Assign the resulting filter object to `result`. To get the first 2 characters in a tweet `x`, use `x[0:2]`. To check equality, use a Boolean filter with `==`.2. Convert `result` to a list and print out the list.<jupyter_code># Import pandas
import pandas as pd

# Import the Twitter data as tweets_df DataFrame
tweets_df = pd.read_csv('tweets.csv')

# Select retweets from the Twitter DataFrame: result
result = filter(lambda x: x[0:2] == 'RT', tweets_df['text'])

# Create list from filter object result: res_list
res_list = list(result)

# Print all retweets in res_list
for tweet in res_list:
    print(tweet)<jupyter_output>RT @bpolitics: .@krollbondrating's <NAME> says Clinton is the weakest Dem candidate in 50 years https://t.co/pLk7rvoRSn https:/…
RT @HeidiAlpine: @dmartosko Cruz video found.....racing from the scene.... #cruzsexscandal https://t.co/zuAPZfQDk3
RT @AlanLohner: The anti-American D.C. elites despise Trump for his America-first foreign policy. Trump threatens their gravy train. https:…
RT @BIackPplTweets: Yo<NAME> trump meets his neighbor  https://t.co/RFlu17Z1eE
RT @trumpresearch: @WaitingInBagdad @thehill Trump supporters have selective amnisia.
RT @HouseCracka: 29,000+ PEOPLE WATCHING TRUMP LIVE ON ONE STREAM!!!

https://t.co/7QCFz9ehNe
RT @urfavandtrump: RT for <NAME>
Fav for Donald Trump https://t.co/PZ5vS94lOg
RT @trapgrampa: This is how I see #Trump every time he speaks. https://t.co/fYSiHNS0nT
RT @trumpresearch: @WaitingInBagdad @thehill Trump supporters have selective amnisia.
RT @Pjw20161951: NO KIDDING: #SleazyDonald just attacked <NAME> for NOT RAISI[...]<jupyter_text>Bringing it all together (2)Sometimes, we make mistakes when calling functions - even ones you made yourself. But don't fret! In this exercise, you will improve on your previous work with the `count_entries()` function in the last chapter by adding a `try-except` block to it. This will allow your function to provide a helpful message when the user calls your `count_entries()` function but provides a column name that isn't in the DataFrame.Instructions1. Add a `try` block so that when the function is called with the correct arguments, it processes the DataFrame and returns a dictionary of results.2. Add an `except` block so that when the function is called incorrectly, it displays the following error message: `'The DataFrame does not have a ' + col_name + ' column.'`.<jupyter_code># Define count_entries()
def count_entries(df, col_name='lang'):
    """Return a dictionary with counts of occurrences as value for each key."""

    # Initialize an empty dictionary: cols_count
    cols_count = {}

    # Add try block
    try: 
        # Extract column from DataFrame: col
        col = df[col_name]
        
        # Iterate over the column in dataframe
        for entry in col:
    
            # If entry is in cols_count, add 1
            if entry in cols_count.keys():
                cols_count[entry] += 1
            # Else add the entry to cols_count, set the value to 1
            else:
                cols_count[entry] = 1
    
        # Return the cols_count dictionary
        return cols_count

    # Add except block
    except:
        print(f'The DataFrame does not have a {col_name} column.')

# Call count_entries(): result1
result1 = count_entries(tweets_df, 'lang')

# Print result1
print(result1)<jupyter_output>{'en': 97, 'et': 1, 'und': 2}<jupyter_text>Bringing it all together (3)In the previous exercise, you built on your function `count_entries()` to add a `try-except` block. This was so that users would get helpful messages when calling your `count_entries()` function and providing a column name that isn't in the DataFrame. In this exercise, you'll instead raise a `ValueError` in the case that the user provides a column name that isn't in the DataFrame.Instructions1. If `col_name` is not a column in the DataFrame `df`, raise a ValueError `'The DataFrame does not have a ' + col_name + ' column.'`.2. Call your new function `count_entries()` to analyze the `'lang'` column of `tweets_df`. Store the result in `result1`.3. Print `result1`. Check out the result. In the next exercise, you'll see that it raises the necessary `ValueErrors`.<jupyter_code># Define count_entries()
def count_entries(df, col_name='lang'):
    """Return a dictionary with counts of occurrences as value for each key."""
    
    # Raise a ValueError if col_name is NOT in DataFrame
    if col_name not in df.columns:
        raise ValueError(f'The DataFrame does not have a {col_name} column.')

    # Initialize an empty dictionary: cols_count
    cols_count = {}
    
    # Extract column from DataFrame: col
    col = df[col_name]
    
    # Iterate over the column in DataFrame
    for entry in col:

        # If entry is in cols_count, add 1
        if entry in cols_count.keys():
            cols_count[entry] += 1
            # Else add the entry to cols_count, set the value to 1
        else:
            cols_count[entry] = 1
        
        # Return the cols_count dictionary
    return cols_count

# Call count_entries(): result1
result1 = count_entries(tweets_df, 'lang')

# Print result1
print(result1)<jupyter_output>{'en': 97, 'et': 1, 'und': 2}
{'fraction_non_alphanumeric': 0.0821563088512241, 'fraction_numerical': 0.00847457627118644, 'mean_word_length': 4.4031796502384735, 'pattern_counts': {'":': 0, '<': 38, '<?xml version=': 0, '>': 38, 'https://': 6, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '10', 'dir': 'jupyter-structured-clean-dedup', 'id': '629340', 'license': 'MIT', 'n_tokens_mistral': 4850, 'n_tokens_neox': 4626, 'n_words': 2320, 'path': 'python_data_science_toolbox_part_1/3_lambda_functions_and_error_handling.ipynb', 'repo_name': 'vhsenna/datacamp-courses', 'size': '17020'}