Transcription
I have always thought that pandas are somewhat similar to programmers: they are just as kind, fluffy bears with huge black circles under their eyes.
Welcome to the intensive course on pandas for beginners!
Let's immediately start by declaring a variable. This variable will store an array that we create using the NumPy function `np.array`, and we will make it 6 by 4.
This is how it looks.
Next, we have another variable called `dates`, and here we will use the pandas function `pd.date_range`. We will ask this function to start from a specific date, say January 1, 2021.
Then, for the second argument, we specify the number of periods, which will be 6.
We will store the values created using this function in a variable called `df`. This is a DataFrame, which is a tabular data structure in pandas, similar to tables in Microsoft Excel.
In some ways, it resembles a NumPy array, although more distantly. We provide our array to it, and we want to see dates as indices. We will separate the columns using the list [1, 2, 3, 4].
We see on the screen how all these six periods starting from January 1, 2021, serve as indices, and we have 4 columns: 1, 2, 3, 4.
Pandas is often used as a supporting library in machine learning and data science. Therefore, in this intensive course, we will look at the main ways to use it and its methods.
For example, using square brackets, we can output column number 4 for all rows, and at the bottom, we also have a small summary.
But as you might guess, this is not the only way to work with data and data structures in pandas.
We can also perform what are called "slices," meaning we can slice our data structure. Here, we specify 1 and 3 in square brackets, and the corresponding rows are output.
Please note that when we accessed the column, we used apostrophes.
Moving on, since dates serve as indices, we can also ask to output records related to specific indices, to specific dates.
For instance, if we specify January 1, 2021, to January 5, 2021, we will get all rows with all values in that interval.
Also, for rows in DataFrames, we can use the `loc` attribute, where we can provide the index of the required rows.
Suppose we want to output two rows. If we access the DataFrame using the `iloc` attribute and provide, say, the interval from 1 to 3 (not inclusive), it will output row number 1, skip the missing one, and then output rows with indices 2 and 3, which naturally do not include the skipped one.
Similarly, if we expand the interval, we see that we now have four rows, again starting with index 1 and ending with index 4.
We can also use more complex constructions. For example, if we want to output all rows in this DataFrame but only the first and third columns, we use a colon, and inside the square brackets, we have another set of square brackets where we specify '1' and '3' between apostrophes.
As we can see, we get all rows but only two columns.
In a similar way, we can combine our indices, our dates, and say output all rows from January 1 to January 5, but again only two columns.
We see that we now have only 3 rows and 2 columns.
We can also perform arithmetic calculations. Before we output something on the screen, let's also use our variable `df`.
We will provide January 1, 2021, all the same two columns, but suppose we want to multiply one of the values in these columns by 5.
So, we take the value at index 1, which is 2, and multiply it by 5, resulting in 10.
Why 10? Because we are accessing the elements contained in the row for January 1 in columns 1 and 3, meaning we have two values.
Next, we specify the index, which is 0 and 1. In this case, it will be 2, which is the element in the third column.
But we can also multiply the element at index 0 in the row for January 2, 2021. For this, we simply change the date to the second and change the 1 to 0.
This will give us 4 multiplied by 5, resulting in 20.
Moving on, I will show you how to access a single value, a single element.
For this, we will take the same `df` function and use our variable `dates`, which, as we remember, stores our indices that are dates.
We will access the first element of the row with index 1, which corresponds to 4.
Let's refresh our memory. Here is our variable `dates`, which is an interval of 6 periods starting from January 1.
Since this is also an array, as it is a 6 by 4 array, we can output all elements in the row with index 2 or 3 from the top.
But we can also achieve a similar result using the `iloc` function in pandas.
Here, we also provide index 2, and we get the same array of elements, but this time the row name is written at the bottom, and each column is kindly numbered.
We can also select specific rows and specific columns. For this, it is enough to provide an interval for the first argument corresponding to the rows and for the second element an interval corresponding to the columns, or simply list the rows and columns separated by a comma, as shown here.
The syntax is quite flexible, so we could limit one parameter while saying that we need all for the second.
For example, here we want only two rows but all the columns available. This is helped by an empty colon as the second argument.
Moving on, this time we will limit the second parameter, namely the columns. As we can see, we have all rows, but for columns, only those in the interval from index 1 to index 3.
In addition, we can use comparison operators, such as greater than, less than, greater than or equal to, or less than or equal to.
For example, as an argument, we provide our DataFrame and say we want all elements that are greater than 5.
What happens to the elements that are less? They are returned as NaN, or in other words, as some empty value that does not participate in the output.
Well, let's improve our array a bit. This time it will be an array of 40 elements, 10 by 4, but everything else remains the same.
We start with January 1, and this time we will have 10 periods, and our columns will be labeled not with numbers from 1 to 4 but with letters A, B, C, D.
But we will use all the same data structures that we used in the first example.
Let's try to output it on the screen and see what we got.
In principle, nothing extraordinary; it is the same array as the first time, just a bit expanded.
Let's take this array as the basis for a new array, say, `cars`. We will copy the existing array and add a new column.
We use the `copy` function and write that in `df` in parentheses we specify the name of our column, which is `cars`, and then we will list the values for this column.
I write the first car that comes to mind: Ford, then Mazda, what else? Mitsubishi, probably.
Next, let's add Lada. We need 10 names, so the next one is Hummer.
I know that Hummer is spelled differently, but it's cooler to ride a Hummer than a regular car.
What else? Let's add BMW, Mercedes, and our last car will be Volkswagen.
Let's see what we got. We write `df` and use tab completion, and we see that we have the same array, just with a new column containing all the car brands we listed.
Now let's access our row indices using the `pd.date_range` function, where we provide the variable `start_date`, which starts from January 1, and the number of periods, which is 10 periods, from January 1 to January 10.
Next, we will look at working with what are called pandas Series.
This is also a very important data structure used to work with sequences of one-dimensional data, essentially an array with some extended capabilities.
Here, we will list elements from 1 to 10, and as an index, we will call the `pd.date_range` function, which we also provide with the start date and 10 periods.
We see that we have a data structure where each number corresponds to its date.
We can also freely add an additional column. For this, we declare a variable `extra` and copy all our previous expression with the only difference that we will add a column `extra`, which will consist of the values we already have, say multiplied by 10 and adding 2 at the end.
As you can guess, this is very convenient for some final sums or, say, calculating taxes and so on.
Now let's return to our DataFrame with cars and add this `extra` column.
In principle, we don't need to do anything; we can just change the variable name, and as we can see, we have our DataFrame with an additional column equal to those extra calculations we just did.
Next, using such a construction, we can access a specific element in our DataFrame, that is, the row with index 4, which is the fifth row in the `cars` column.
We assign the value "Renault" to it, but since we already have "Renault," let's change it to "Citroen" so that it visually differs.
As we can see, "Renault" has changed to "Citroen," while all other numerical values remain unchanged.
Moving on, this time we will use another index operator available in pandas, denoted as `iat`.
Here, we can specify the row index, which is the third row (index 3), and the second column index, which is the third column, and we change the value to 666.
This is quite visually evident. If we now change the row index to 4 and run this again, we will see that in the fourth row, the element at index 2 has changed to 666.
Another advantage of pandas is that we can work with both NumPy and pandas together, meaning we can combine them; they work great together.
For example, we can create an array `new_array` where we use the NumPy function `np.arange` to create an array of length 3, and for each element, we multiply it by 10 and add 5.
This combination of functions will evaluate the length of the DataFrame and perform arithmetic calculations on each of the elements.
Moreover, we can take the resulting array `new_array` and add it as a column to our DataFrame `df_cars`.
We give the column a name and assign it the value from the array `new_array`.
Let's see what we got. As we can see, the last column has all the elements from the array `new_array` evenly distributed across the rows.
It will not be a surprise for anyone that data in the real world is not always as complete and honest as these synthetic arrays and DataFrames we just created.
Therefore, we need to learn how to work with data when elements are missing or do not meet some of our requirements.
As an example, let's create an array `laptops`, where we will list the brands of well-known laptop manufacturers.
Again, all from my head: HP, Chromebook, MacBook, and that should be enough.
This array consists of five names, and we will need it in the future.
Let's first create our DataFrame again using the `pd.DataFrame` function and internally specify that we want columns with five names.
Let's say the first column will be "price," and randomly I write 350, 400, 500, 560, and 1000 for the MacBook, of course.
For the second column, we will represent it as an array. I don't know, let's say "disk space," and similarly, an array of five values: 500, 500.
That's a bit low, actually. Let's make it 2 terabytes or something like that. I think that's the most realistic.
Now let's output everything we got on the screen. We write `laptops_df`. Since we did not specify the indices, it will most likely just be numbers from 0 to 5.
Let's see. Yes, that's how it turned out: price, disk space, and as indices, we have numbers from 0 to 5, meaning from 0 to 4 inclusive.
It's time to use our first array, and let's assign the parameter `index` to the values of the `laptops` array.
As we can see, there are no problems; pandas has stretched the array to what is needed.
Suppose, for some unimaginable reasons, we decided to create our second array, `laptops_2`.
We copy all the names but change, say, "Chromebook" to "Huawei" and create a new DataFrame called `laptops_df_2`.
But this time, instead of using the `pd.DataFrame` function, we will copy our previous DataFrame `laptops_df` and just re-index it using the `pd.Index` function, providing it with the old array.
We will get a new DataFrame where all indices have been changed.
As we can see, "Huawei" is there, but the values, that is, the price and disk space for it, are not available.
Therefore, pandas returns NaN.
This abbreviation has nothing to do with nuns; "nun" is spelled differently in English.
So, let's move on and create a new DataFrame `laptops_df_3`, which will equal `laptops_df_2`, but for which we will use the `dropna` function to remove all data that is NaN.
We specify `how='any'`, and we see that "Huawei" has disappeared because, as a reminder, all elements were missing, meaning NaN.
But to avoid solving problems in such a radical way, we can instead use the `fillna` function to fill in the missing data.
In parentheses, we specify what values we want to fill in, say 100.
So, we got the price and disk space to be 100 terabytes for a laptop for 100 bucks. How do you like that, Elon Musk?
Now, pandas also has the `isna` function, which is a boolean function, meaning it will return either True or False.
We can check for missing values in our `laptops_df_2` DataFrame, and as we can see, instead of NaN, we get True, meaning they are indeed null or, in other words, they are absent.
Accordingly, we can build various combinations using this DataFrame.
For example, we can multiply all prices by 10, saying that prices have increased, and the disk space has also increased by 10 times, meaning simple arithmetic is available for elements in pandas without any problems.
We can also specify how we want to see the elements using built-in functions, such as `set_option`, where we provide the parameter `display.float_format`, meaning the number of decimal places.
In this case, it will be two.
Now let's see our `laptops_df_2` using the statistical function `describe`, which should output the mean, standard deviation, minimum, and maximum values for all values in the "price" and "disk space" columns.
This is a very useful function, and I recommend checking it out in the documentation; the link is in the description.
We can also output the mean value separately using the `mean` function.
For "price," it is 560, and for "disk space," it is 125.
Similarly, if we provide the function `mean` with an argument of 1, we will get the mean value row-wise.
In this example, we have too little data to use this function effectively, but it is used frequently in statistics.
There is also another interesting function called `apply`, which is essentially a function of functions, meaning it applies some function that we provide as an argument.
For example, if we provide a cumulative function from NumPy, it will mean that all values will be summed up into one total.
If our values are strings, concatenation will occur, meaning one word will be added to another, and so on.
The concatenation function is found in many programming languages and frameworks, but it is especially useful in data manipulation.
Next, since we are concatenating data, to some extent, we need to first declare a variable `pieces`, which will represent a list of three elements, each of which represents part of our `laptops_df_2`.
The idea here is that we will use the `concat` function to combine these three separate parts into one whole.
I made sure that I separated them by the necessary index, and let's see how our list looks.
It looks very ugly. Let's create some beauty.
For this, we declare a new variable, let's call it `final_list`, and now, addressing a specific element of the list `pieces` by index, we can start combining them.
But no one said that we can do this in the necessary order.
For example, in this case, we will combine the first part and the last part, skipping the second element.
The `concat` function will glue these two disparate pieces into one whole.
Now we declare a new variable `hp`, which will be equal to the element at index 2.
At index 2, we have HP, so our variable now contains the element HP with its price and disk space.
Using the `append` function, we can add it to the end of our `laptops_df_2`.
As we can see, we now have HP both in the middle and at the very end.
Moving on, the next important function to consider is the `merge` function, which essentially provides the merging of certain objects by columns or indices, just as it would be done in a database.
For example, we have two DataFrames, `df1` and `df2`, and we can declare a variable `result` and use the `merge` function, providing it with our `df1` and specifying what our foreign key will be.
We can get a summary table as a result.
If someone does not understand how this works, I recommend the corresponding video from my SQL playlist.
But we don't always have to create arrays with data ourselves; I think it's time to import data from the internet.
There are many resources from which we can import data, but I will consider the two most well-known to me: Kaggle, which has a large number of datasets, and Osi, which is not as popular as Kaggle but is very helpful, especially when some problems arise.
For example, it often happens that Kaggle does not allow downloading datasets because the requests to the server exceed a certain limit.
So, we create a variable `bank_data` and use the `pd.read_csv` function to read a file in CSV format, meaning comma-separated values.
This file will be available at a link in the repository, and you can copy it to your disk. Just be careful; if the file does not exist when you try to download it, check the path.
You may need to change the format from backslashes to forward slashes or access this file directly from the repository.
Here is how it looks: the file is a collection of data on some bank employees, and I don't know if they are real or not.
In any case, I provided it as an example of how we can easily read CSV files using pandas.
We can also easily write them, and we can use not only CSV formats but also many other formats.
Now I will show you how we can save this file if we have modified it to some extent.
We assume we want to save it. For this, there is a very convenient command `to_csv`, and again we specify the path.
I will copy it and change the file name so that it does not overwrite it, say `bank_updated.csv`.
And just like that, we created a new CSV file.
Now let's copy another file called `online_sales`, which is in Excel table format, specifically `.xlsx`.
I declare a variable `excel_file`, where I specify the path to the file. Again, the file is available in the repository, or we can take it directly from the machine.
This is the second resource I showed you. Here, we click on the three dots and can download it. The choice is yours.
So, we specified the file path, copied it to our hard drive, and now we need to read it.
We declare a new variable `online_sales_df`, and traditionally, we will use the `pd.read_excel` function to read it.
We provide this function with our variable `excel_file`, which corresponds to the file path, and as the second parameter, we specify the name or number of the tab from which we will read the data.
In this case, we have only one tab, and then we specify that we do not want row indexing, and the last parameter indicates how we will handle missing data, meaning we will replace them with NaN, or "not applicable."
The necessary preparations are complete, and now let's output our `online_sales_df` on the screen and see what it contains.
Here is how it looks: it seems to be an inventory list of what we have in stock, and we will work with it further.
Again, pandas allows using similar SQL functions, and we can group our elements by a certain parameter, for example, "quantity," and sum the quantity, meaning we will sum the amount of products we have in stock.
It seems that we have some products in stock that we should have ordered.
What is convenient in pandas is that we always see at the bottom the statistics of what participated in the operation called by our function.
In this case, it is 722 rows and 2 columns.
The next group will be by "country," and this time we will count, not sum, meaning we will count the values within a certain group.
We see that we have a list of all countries for which we have inventory, meaning who orders from us or whom we order from.
Next, we see the counted quantities.
Well, let's move on, and now we will talk about resampling.
Let's declare another variable `time_index`, and you will soon see what this topic is about.
Our index will be equal to a certain time interval. As parameters for the `pd.date_range` function, we provide when it starts, January 1, 2021, the second parameter is how many periods we will have, which is 10, and the last parameter is the frequency, meaning minutes.
In previous cases, we did not specify the third parameter, and our periods were placed on separate days.
Now, if I output `time_index`, we will see that the periods go by minutes, meaning we have 0 minutes, then 2 minutes, 4, and so on, all happening within one day.
We can also create a pandas Series using this.
Let's declare a variable `time_series` and use the `pd.Series` function.
As the first parameter, we provide the NumPy function `np.arange` to create an array of 10 elements, and as the second parameter, we provide `time_index` for the index.
We see that we have a time series of 10 elements from 0 to 9, and for each of them, the index is the date, or more precisely, the time.
Now let's use the `resample` function.
Suppose we take our series and use the `resample` function to divide it into 5-minute intervals and sum everything that falls into these 5-minute intervals.
In the interval from 0 minutes to 5 minutes, we got 10 values, and everything after 5 minutes gives us 35.
You can verify this yourself by summing them.
In particular, we can even change the default label name. It is set to "0," meaning if our interval starts at 0 minutes and ends at 5 minutes, it is labeled as 0.
But if we change it to "right," as you can see, the sum remains the same, but the label shifts to the last interval that closes it, meaning now instead of 0, it became 2, and instead of 5, it became 10.
We can also specify that the closing value of the interval is included in the selection.
For example, if we specify here also 5 minutes and set the `label` parameter to "right," now the 5-minute interval will also include the value from the 5-minute interval, and instead of 10, we will have 15.
Here, we can also notice that the closing interval now has a sum of values equal to 30 because the 5 has moved into the previous interval.
Again, if we divide our data into 5 30-second intervals using this construction, we will see that some values will be absent, meaning they will return NaN because the interval is too small, and no values from our original time series fell into that interval.
We can also use custom functions with the `apply` method and provide this function as a parameter.
For this, we declare a function `custom_function` that takes an array object as input, and suppose we want to sum the values.
In particular, this will be our time series. We will sum all values, then multiply by 3, and add 10, returning this as a result.
Now, in this form, this function can be used in `apply`.
Again, through the `pd.Series` function, we declare our variable `time_series` and then through the `apply` method, we provide the interval of 3 minutes and then attach another function `map` to it.
Now, we pass our function that we just wrote.
This returns us a time series of four intervals: from 0 to 3, from 3 to 6, and from 6 to 9, where the values falling into each of these intervals are summed, then multiplied by 3, and 10 is added on top.
In pandas, there is also another way to create series using the already known random number functions from NumPy.
For this, we take the `pd.Series` function and as the first parameter, we provide the NumPy function `np.random.rand`, which will give us 5 random or pseudo-random values.
As the second parameter, we provide the indices, listing 5 letters A, B, C, D, E.
Your numbers will likely be somewhat different from mine because this is a pseudo-random number generator.
I got these values, and since all of this is essentially an array with extended capabilities, we can access a specific element of our series by index.
This will also be possible if I use the same construction but without indices.
We see that by default, everything will be labeled with numbers from 0 to 4.
Again, all numbers are pseudo-random, and the order may not match yours.
As I mentioned, we can use a construction similar to NumPy, and in square brackets, we write `series[2]`, which will give us the element at index 2.
But the series is also interesting because we can use data structures from Python, called dictionaries, where we have key-value pairs.
As an example, we can create several pairs of points with values A, B, C, and so on.
Now I will declare a new variable `dict_series`, which will take the pandas Series and as an argument, it will receive our dictionary.
Please note how it looks on the screen. It looks like if we had labeled indices; in fact, these are key-value pairs.
In this case, the keys become similar to indices, and we can also access a specific value by its key.
If we decide to add indices ourselves, for example, we use the same dictionary and say we will provide it as an argument to the `pd.Series` function, and as the second argument, we will use the index, and say we will have indices not in order at all.
Now we will output this, and we see that those keys that did not have values will be returned as NaN.
We can also return values using the `get` function.
For example, we want to return the value at key "A," which is 30.
This is another way to access it, and we can also set some default value instead of NaN to return in case the key does not have a corresponding value.
Another example is creating a series from a scalar value, meaning a single value.
In particular, we specify 5 as the first parameter, and here I copy the indices.
If I output all this on the screen now, we will see that the indices are A, B, C, D, E, but each has been assigned the value 5.
We can also use simple arithmetic addition.
For example, we take this series `time_series` and add it to itself for demonstration purposes, writing `time_series + time_series`.
We see that the values have been summed together.
But if we call the original series, we see that it has not been changed; it remains as it was originally.
We can also not just add series, meaning sequences of values to each other; we can also add some scalar value, say 1000, and each element of the series will be increased by 1000, while the original series will remain the same.
Here, we multiply each element by 5 and get the result.
We can also pass our series as an argument to the NumPy function without any obstacles.
Here, I used the exponential function and passed our series as an argument.
If I want to output the elements of the series starting from a certain index, I can use the following construction, starting from index 1 to the end of the series.
Similarly, we can make a selection for the last element.
For this, in square brackets, we write -1, meaning we cut off the last moment.
And note that in any output, unlike working with arrays, we always have a key; we always have an index.
If we add two modified series, meaning the one where we requested to output from the first element and the one where we cut off the last element, we will see that the summation occurred only with those elements that were present in both series.
Despite the fact that in the last series, where we cut off the last element, there was an element at index 0, it still returns NaN because that element was absent in our first selection from the first value to the end.
For the next trick, we will need to create a function `multiply_by_ten`, which will take our series as input and return each element of this series multiplied by 10.
This illustrates another way we can arithmetically change elements in a series, for example, using the `map` function, which will display or link values.
In this case, a specific value from our series will be passed to this function, multiplied by 10, and then sent back to the original series under the original key but multiplied by 10.
We write `time_series.map(multiply_by_ten)`, and in the parameters, we provide the function `multiply_by_ten`.
This will return us a time series of four intervals from 0 to 3, from 3 to 6, and from 6 to 9, where the values falling into each of these intervals are summed, then multiplied by 3, and 10 is added on top.
Pandas also has a function for working with string values, specifically with their case.
We can make them uppercase or make them all lowercase.
Suppose I will create a visualization string only in uppercase letters, and using the `str.upper()` function, I will return all values but with all letters in lowercase.
Another important advantage of pandas is working with dates, meaning arithmetic operations.
For this, we need to import `datetime`.
We write `import datetime`, and now let's see how it works.
First, we will output the current date, which is the current date and time when I recorded this video.
Now we can start working with our object using excellent functions, particularly accessing the year, month, and day, to get a normal date.
In particular, we can also calculate how much time has passed since a certain moment or how much is left.
For example, using the arithmetic function `delta`, which we define as the current date minus the date I set to January 1, 2012, when the world was supposed to end.
If I remember correctly, if we output this now, we will see that 3207 days have passed, along with some seconds and microseconds.
Again, to avoid dragging this entire recipe along, we can use the `days` function, which will return the number of days that have passed.
We can also use the `timedelta` function to parse a string and convert it into a date.
For example, we can use `timedelta` and as an argument, we can write something like "5 days, 10 hours," and we will get a numerical value as output.
But that's not all.
Suppose we have a format where we provide `timedelta` with a certain key and set it to some value.
For example, we can write `days=2` and `seconds=10`, and we will get 2 days and 10 seconds as output.
As you might guess, we can also mix strings and numerical values.
For example, we write `1` and as the unit, we specify "days," meaning we got one day and 0:00:00 remaining time.
Now let's move on to something more meaningful.
In particular, here I declared a series of variables.
I have `absurd_day`, which falls on January 1, 2021, the day of absurdity, or the day of foolishness, November 20, 2021, and the day of independence of the Republic of Tuvalu, October 1, 2021.
Suppose I know that I can take a vacation between the day of absurdity and the day of independence of Tuvalu.
I subtract one from the other, and it turns out that I will have a vacation of 50 days.
Now we will use the `pd.date_range` function to create a custom time interval.
We use `pd.date_range` and as parameters, we provide the date of the International Day of Absurdity and the number of periods, which will be the value of our variable `time_to_relax` in days, and the last parameter is the frequency, where we specify "days."
Now, using this construction, we will create an even more complex construction.
Now we have `time_lock_series`.
Next, we use the `pd.Series` function, providing it with the pseudo-random numbers from NumPy, where we pass `time_to_relax` as the number of days, and the second parameter is the index, which is equal to `time_lock_series`.
Now we will output not the entire series but only the last five values using the `tail` function.
The pseudo-random numbers have been distributed by days in the second column.
Please write in the comments what you think about the dates and what correlation you see.
Look at the full list of dates to understand what patterns are present.
Now let's return to the DataFrame and look at some key methods.
We created a dictionary with categorical values and numerical values.
Next, we output a specific key from the dictionary and separately the value of the dictionary.
Let's see what we get.
So, in principle, we got the expected result.
Now we will create a DataFrame using the corresponding method, naming our variable `avoid_excessive`, and as arguments for our DataFrame, we provide our dictionary.
As output, we will use only two indices, for example, "start" and "finish."
We will see that the keys will act as indices, and the values will be evenly distributed or replicated to fill the void.
In particular, we see columns with categorical values and numerical values distributed across rows, meaning this is essentially a duplicate under different indices.
To save time, I created several constructions in advance.
You can pause to copy them, but I will explain what is happening here.
We have a dictionary with one key and several values that will be distributed across columns.
Another example is a dictionary with two keys, where its value is essentially a series.
We also have indices, and the missing values are returned as NaN.
The next example is a dictionary consisting of lists, where each element is a string.
As an assignment, you can now create your DataFrame and place it in the `pd.DataFrame` function.
Thus, pandas will convert it into a DataFrame.
In the last example, instead of a dictionary containing lists, we have a list containing dictionaries, and as we can see, pandas handled this excellently.
Well, that was a brief introduction to pandas.
I want to reiterate that we will use pandas quite often in the course of introduction to machine learning and data science.
So, we will gain a lot of practice that will be needed for further work on projects.
That was the entire channel.
If you enjoyed it, give it an imperial thumbs up, subscribe to the channel, hit the bell, and see you later! Bye!