1
$\begingroup$

I have a matrix that looks something like this:

chr pos het
chrI 27 2
chrI 55 0
chrI 27 0
chrI 55 1

It's essentially a VCF file that I have converted into a TSV. I want to be able to take all the values in the het column and apply this function: het_df['het'] = het_df['het'].transform(lambda x: -1*(x-1))

That line is from a python script and it works really well in transforming that column. However, as I am making plots from this data I want to be able to do this in R. When I went to convert it to an R script I started with this function:

convert_df <- lapply(het_df[,3], FUN=function(x) formula=(-1*(x-1)))

As I saw it in this issue: https://stackoverflow.com/questions/7009333/how-to-use-lapply-with-a-formula

However, I keep getting error messages such as this one:

Error in x - 1 : non-numeric argument to binary operator

Which is odd because when I run het_df[,3] it gives me the correct output:

   [1] "2" "0" "1" "1" "1" "1" "1"

I think I'm just a little lost and I don't know what to do to run this function...everything worked fine in my python script (I was able to generate plots with matplotlib) but I like manipulating plots more in R than python so I wanted to be able to convert the script. If anyone is able to see what I'm clearly doing wrong please let me know! Thank you!

Here is the python code I've been using in case this helps (I'm transforming the last column so I always get a 1 or a 0 for heterozygosity/homosygosity and then using a rolling window to obtain the variability in the data series and plotting them):

import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
import seaborn as sns

# read in file
het_df = pd.read_csv("het_file.tsv", sep="\t", header=None).set_axis(['chr', 'pos', 'het'], axis=1, copy=False)

# getting rid of homozygous alt allele
# always get 1 for heterozygosity
het_df['het'] = het_df['het'].transform(lambda x: -1*(x-1))

windows = [25, 50, 100, 200] # 100 bp, get rid of a lot of noise
steps = [5]

for window in windows:
    for step in steps:
        het_ratio = {}
        for chr_het_df in het_df.groupby('chr'):
            # rolling over the window
            # center = have the count in the center of the window
            # 50bp window count in the front or back of window or count in the center
            # ratio of heterozygosity
            het_ratio[chr_het_df[0]] = chr_het_df[1].set_index('pos').rolling(window=window, step=step, center=True).mean()
        fig, ax = plt.subplots(len(het_ratio), 1, sharex=True)
        for index in range(len(het_ratio)):
            chromosome = list(het_ratio.keys())[index] 
            sns.scatterplot(het_ratio[chromosome], ax=ax[index], s=4)
            ax[index].set_ylim(bottom=0, top=1)
            ax[index].legend([], [], frameon=False)
            ax[index].set(xlabel="Chromosome position", ylabel=chromosome)
            ax[index].set_yticks([0, 0.5, 1])
            ax[index].set_yticklabels([0, 0.5, 1], size = 6)
        fig.subplots_adjust(top=0.98, bottom=0.05, left=0.05, right=0.98)
        fig.set_size_inches(20, 15)
        plt.savefig("het_plot" + str(window) + "_step" + str(step) + ".png", dpi=150)
```
$\endgroup$

2 Answers 2

1
$\begingroup$

If the numbers are in quotes it means that it has read them as text. A numeric vector will be:

[1] 2 0 1 1 1 1 1

To replace that column with the new value you can use this:

het_df[,3] <- sapply(as.numeric(het_df[,3]), FUN=function(x){-1*(x-1)})

I used het_df[, 3] <- to replace the content of the column. I changed lapply to sapply, to get a vector and not a list. I forced the input to be numeric via as.numeric.
The syntax of the functions was wrong, to create a function in R you need function(x){#code}. The linked question is for a function that has an argument called formula, which is not the case here, because you want to define your own (anonymous) function.

$\endgroup$
2
  • $\begingroup$ Thank you so much that's exactly what I needed! That makes a lot more sense too - thank you for explaining what was going on. If you wouldn't mind can I ask you one more question? How would you work a rolling window into this data? From my above python code I was able to complete it using a for loop and the pandas package. Everywhere I am looking to try and replicate it in R is telling me a lot of different things so if you know a good place to look or if you have any advice moving forward that would be great! $\endgroup$
    – rimo
    Jan 4, 2023 at 16:16
  • $\begingroup$ That's a different question entirely; please try to limit posts to one question only, and ask a new question if you have follow-ups. $\endgroup$
    – gringer
    Jan 5, 2023 at 20:03
0
$\begingroup$

Doing mathematical operations on a matrix will only work if all the matrix elements are numerical. In your case, you have mixed character and numerical variables, and it looks like a data frame or tibble would be more appropriate (calling it het_df is a strong indicator that this is actually what you want to do, as well as the pandas structures in the python code). You can load a TSV file into a tibble in R using the read_tsv function from tidyverse:

library(tidyverse);
het_df <- read_tsv("input_file_name.tsv");

After this, numerical mathematical operations can be carried out column-by-column, because the columns are treated as separate structures internally:

het_df$het <- -1 * (het_df$het - 1); # approach 1 [base R]
het_df <- mutate(het_df, het = -1 * (het - 1); # approach 2 [tidyverse]
$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.