How do I load a CSV file?

Read a price file into a data frame with read.csv, check its shape and types, turn the date column into real dates, and pull one ticker out of it.

read.csv("prices.csv") reads a file of comma separated text and hands you back a data frame: one column per field in the header, one row per line in the file.

In this lesson I read a price file, check what came in, fix the date column, and pull a single ticker out of it. The file is simulated, not real market data.

Step 1. Read the file and check its shape

The file sits next to the lesson, so the name on its own is enough. dim() gives rows then columns.

p <- read.csv("prices.csv")   # read the file into a data frame
print(dim(p))                 # -> [1] 120   4
[1] 120   4
print(nrow(p))                # -> [1] 120
[1] 120
print(names(p))               # -> [1] "Date"   "Ticker" "Close"  "Volume"
[1] "Date"   "Ticker" "Close"  "Volume"

120 rows and 4 columns. Three tickers over 40 business days is 120 rows.

head(p, 4) prints the first four rows. R numbers the rows down the left and right-aligns each column.

print(head(p, 4))   # the first four rows of the file
        Date Ticker  Close  Volume
1 2026-01-02    AAA 186.66 2183494
2 2026-01-02    CCC 416.98 3117814
3 2026-01-02    DDD 125.18 7447373
4 2026-01-05    AAA 186.38 8463199
# ->         Date Ticker  Close  Volume
# -> 1 2026-01-02    AAA 186.66 2183494
# -> 2 2026-01-02    CCC 416.98 3117814
# -> 3 2026-01-02    DDD 125.18 7447373
# -> 4 2026-01-05    AAA 186.38 8463199

The file is stacked: all three tickers for one date, then all three for the next date. It is not one column per ticker.

str() gives the structure. One line per column, with the type and the first few values.

str(p)   # one line per column, type and first values
'data.frame':   120 obs. of  4 variables:
 $ Date  : chr  "2026-01-02" "2026-01-02" "2026-01-02" "2026-01-05" ...
 $ Ticker: chr  "AAA" "CCC" "DDD" "AAA" ...
 $ Close : num  187 417 125 186 423 ...
 $ Volume: int  2183494 3117814 7447373 8463199 3345056 7380472 5299573 2476170 8060541 4931962 ...
# -> 'data.frame':  120 obs. of  4 variables:
# ->  $ Date  : chr  "2026-01-02" "2026-01-02" "2026-01-02" "2026-01-05" ...
# ->  $ Ticker: chr  "AAA" "CCC" "DDD" "AAA" ...
# ->  $ Close : num  187 417 125 186 423 ...
# ->  $ Volume: int  2183494 3117814 7447373 8463199 3345056 7380472 5299573 2476170 8060541 4931962 ...

chr is character, num is numeric, int is integer. read.csv read the numbers as numbers, so Close and Volume are ready to compute with. Date is text.

summary() on a numeric column gives the six figure summary.

print(summary(p$Close))   # spread of the closes, all tickers mixed
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
  101.4   122.1   186.0   244.4   431.1   450.3 
# ->    Min. 1st Qu.  Median    Mean 3rd Qu.    Max.
# ->   101.4   122.1   186.0   244.4   431.1   450.3

That mixes all three tickers into one column, so the mean of 244.4 is not a price anything traded at. It sits between DDD near 110 and CCC near 430. Split by ticker before you read anything into it.

Step 2. The date column arrives as text

class() says what a column is. Ask it before you trust a column.

print(class(p$Date))   # -> [1] "character"
[1] "character"
print(p$Date[1])       # -> [1] "2026-01-02"
[1] "2026-01-02"

The quotes give it away. It is a string of ten characters, not a date.

Text sorts as text, character by character. Here are three dates held as text in day/month/year form.

messy <- c("1/2/2026", "10/1/2026", "2/3/2026")   # three dates held as text
print(sort(messy))                                # -> [1] "1/2/2026"  "10/1/2026" "2/3/2026"
[1] "1/2/2026"  "10/1/2026" "2/3/2026" 

October landed in the middle, because "1" sorts before "2". as.Date() turns text into a date, and dates sort and subtract by calendar.

p$Date <- as.Date(p$Date)   # convert the column in place
print(class(p$Date))        # -> [1] "Date"
[1] "Date"
print(p$Date[1])            # -> [1] "2026-01-02"
[1] "2026-01-02"

class() now says Date. The printed value looks the same, so the class is the only proof.

The column is stored as a count of days, so subtraction works.

span <- max(p$Date) - min(p$Date)   # last date minus first date
print(span)                         # -> Time difference of 55 days
Time difference of 55 days

Try that on the character column and R stops with non-numeric argument to binary operator. Convert the date column right after you read the file, every time.

Step 3. Count what is in the file

table() counts how many times each value appears in a column.

print(table(p$Ticker))   # how many rows each ticker has

AAA CCC DDD 
 40  40  40 
# ->
# -> AAA CCC DDD
# ->   40  40  40

Three tickers, 40 rows each. range() gives the smallest and largest value, which on a date column is the span of the file.

print(range(p$Date))       # -> [1] "2026-01-02" "2026-02-26"
[1] "2026-01-02" "2026-02-26"
print(length(unique(p$Date)))   # -> [1] 40
[1] 40

40 distinct dates and 40 rows per ticker, so no ticker is missing a day.

Step 4. Pull one ticker out

p$Ticker == "AAA" gives one TRUE or FALSE per row. Put that vector inside [ , ] before the comma and R keeps the TRUE rows and every column. The comma is what makes it a row filter; forget it and R tries to select columns instead.

keep <- p$Ticker == "AAA"   # TRUE on the AAA rows
print(sum(keep))             # -> [1] 40
[1] 40
aapl <- p[keep, ]            # rows where keep is TRUE, all columns
print(dim(aapl))             # -> [1] 40  4
[1] 40  4

sum() on a logical vector counts the TRUEs, because TRUE counts as 1.

print(head(aapl, 5))   # first five AAA rows, row numbers kept
         Date Ticker  Close  Volume
1  2026-01-02    AAA 186.66 2183494
4  2026-01-05    AAA 186.38 8463199
7  2026-01-06    AAA 188.51 5299573
10 2026-01-07    AAA 187.24 4931962
13 2026-01-08    AAA 189.27 7949369
# ->          Date Ticker  Close  Volume
# -> 1  2026-01-02    AAA 186.66 2183494
# -> 4  2026-01-05    AAA 186.38 8463199
# -> 7  2026-01-06    AAA 188.51 5299573
# -> 10 2026-01-07    AAA 187.24 4931962
# -> 13 2026-01-08    AAA 189.27 7949369

The row numbers went 1, 4, 7, 10, 13. They are the positions those rows held in p, kept as labels. Set rownames(aapl) <- NULL if you want them renumbered from 1.

order(x) returns the positions of x sorted smallest first, and feeding those positions back as a row index sorts the frame. Here the file already arrives in date order, so nothing moves. Reverse the rows first and you can see the sort do its work.

back <- aapl[nrow(aapl):1, ]        # same rows, newest first
print(head(back, 3))                # newest three now at the top
          Date Ticker  Close  Volume
118 2026-02-26    AAA 169.42 6496907
115 2026-02-25    AAA 171.42 5647098
112 2026-02-24    AAA 172.64 7223495
# ->           Date Ticker  Close  Volume
# -> 118 2026-02-26    AAA 169.42 6496907
# -> 115 2026-02-25    AAA 171.42 5647098
# -> 112 2026-02-24    AAA 172.64 7223495

fixed <- back[order(back$Date), ]   # sort the rows by date, oldest first
print(head(fixed, 3))               # oldest three back at the top
        Date Ticker  Close  Volume
1 2026-01-02    AAA 186.66 2183494
4 2026-01-05    AAA 186.38 8463199
7 2026-01-06    AAA 188.51 5299573
# ->        Date Ticker  Close  Volume
# -> 1 2026-01-02    AAA 186.66 2183494
# -> 4 2026-01-05    AAA 186.38 8463199
# -> 7 2026-01-06    AAA 188.51 5299573

order() on a Date column sorts by calendar; on a character column it sorts by character.

Your turn

Read the file, convert the date column, and pull out DDD sorted by date. Print how many rows you got, the first three, and the summary of its closes.

p       <- read.csv("prices.csv")        # read the simulated price file
p$Date  <- as.Date(p$Date)               # text to real dates

nvda <- p[p$Ticker == "DDD", ]          # keep the DDD rows
nvda <- nvda[order(nvda$Date), ]         # oldest first

print(nrow(nvda))                        # -> [1] 40
print(range(nvda$Date))                  # -> [1] "2026-01-02" "2026-02-26"

print(head(nvda, 3))
# ->        Date Ticker  Close  Volume
# -> 3 2026-01-02   DDD 125.18 7447373
# -> 6 2026-01-05   DDD 124.66 7380472
# -> 9 2026-01-06   DDD 122.78 8060541

print(summary(nvda$Close))
# ->    Min. 1st Qu.  Median    Mean 3rd Qu.    Max.
# ->   101.4   106.0   109.2   112.4   121.9   126.5